-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathfunctions.php
More file actions
1591 lines (1384 loc) · 59.8 KB
/
functions.php
File metadata and controls
1591 lines (1384 loc) · 59.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?php
/**
* Qi Ling 主题函数和定义
*
* @package Developer_Starter
* @since 1.0.0
*/
// 防止直接访问
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* 主题常量
*/
define( 'DEVELOPER_STARTER_VERSION', '1.0.5' );
define( 'DEVELOPER_STARTER_DIR', get_template_directory() );
define( 'DEVELOPER_STARTER_URI', get_template_directory_uri() );
define( 'DEVELOPER_STARTER_INC', DEVELOPER_STARTER_DIR . '/inc' );
define( 'DEVELOPER_STARTER_ASSETS', DEVELOPER_STARTER_URI . '/assets' );
/**
* 根据主题设置切换前台显示语言
* 必须在加载翻译文件之前执行
*/
function developer_starter_switch_locale( $locale ) {
// 只在前台切换语言,后台保持WordPress设置
if ( is_admin() ) {
return $locale;
}
// 获取主题语言设置,默认为 zh_CN
$options = get_option( 'developer_starter_options', array() );
$theme_language = isset( $options['theme_language'] ) && ! empty( $options['theme_language'] )
? $options['theme_language']
: 'zh_CN';
return $theme_language;
}
// 优先级设为1,确保在其他操作之前执行
add_filter( 'locale', 'developer_starter_switch_locale', 1 );
/**
* 加载主题翻译文件
* 使用init钩子确保locale已经正确切换
*/
function developer_starter_load_textdomain() {
// 先卸载可能已加载的(错误locale的)翻译
unload_textdomain( 'developer-starter' );
// 重新加载正确locale的翻译
$locale = get_locale();
$mo_file = DEVELOPER_STARTER_DIR . '/languages/developer-starter-' . $locale . '.mo';
if ( file_exists( $mo_file ) ) {
load_textdomain( 'developer-starter', $mo_file );
}
}
add_action( 'init', 'developer_starter_load_textdomain', 1 );
/**
* 核心类
*/
require_once DEVELOPER_STARTER_INC . '/core/class-theme-setup.php';
require_once DEVELOPER_STARTER_INC . '/core/class-assets.php';
require_once DEVELOPER_STARTER_INC . '/core/class-helpers.php';
require_once DEVELOPER_STARTER_INC . '/core/class-message-manager.php';
require_once DEVELOPER_STARTER_INC . '/core/class-smtp-manager.php';
require_once DEVELOPER_STARTER_INC . '/core/class-auth-manager.php';
require_once DEVELOPER_STARTER_INC . '/core/class-faq-manager.php';
/**
* 后台管理类
*/
require_once DEVELOPER_STARTER_INC . '/admin/class-admin-settings.php';
require_once DEVELOPER_STARTER_INC . '/admin/class-meta-boxes.php';
/**
* 模块系统
*/
require_once DEVELOPER_STARTER_INC . '/modules/class-module-base.php';
require_once DEVELOPER_STARTER_INC . '/modules/class-module-manager.php';
/**
* 加载各个模块
*/
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-banner-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-services-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-features-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-clients-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-stats-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-cta-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-image-text-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-columns-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-timeline-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-faq-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-contact-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-news-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-products-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-cases-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-downloads-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-process-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-pricing-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-video-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-testimonials-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-countdown-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-multi-image-text-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-features-list-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-team-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-gallery-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-branches-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-tabs-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-accordion-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-comparison-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-blog-module.php';
require_once DEVELOPER_STARTER_INC . '/modules/modules/class-featured-posts-module.php';
/**
* 中国特性功能
*/
require_once DEVELOPER_STARTER_INC . '/china/class-china-features.php';
/**
* SEO功能
*/
require_once DEVELOPER_STARTER_INC . '/seo/class-seo-manager.php';
/**
* 小工具
*/
require_once DEVELOPER_STARTER_INC . '/widgets/class-widget-contact.php';
require_once DEVELOPER_STARTER_INC . '/widgets/class-widget-social.php';
/**
* 首页创建器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-homepage-creator.php';
/**
* 解决方案页面创建器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-solutions-page-creator.php';
/**
* 落地页创建器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-landing-page-creator.php';
/**
* 功能清单展示页面创建器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-features-showcase-page-creator.php';
/**
* 资源下载页面创建器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-resources-page-creator.php';
/**
* 博客页面创建器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-blog-page-creator.php';
/**
* 文章增强器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-post-enhancer.php';
/**
* 菜单保护器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-menu-protector.php';
/**
* 公告管理器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-announcement-manager.php';
/**
* 招聘管理
*/
require_once DEVELOPER_STARTER_INC . '/core/class-careers-manager.php';
/**
* 分类管理器
*/
require_once DEVELOPER_STARTER_INC . '/core/class-category-manager.php';
/**
* 表单管理系统
*/
require_once DEVELOPER_STARTER_INC . '/forms/class-form-manager.php';
require_once DEVELOPER_STARTER_INC . '/forms/class-form-admin.php';
require_once DEVELOPER_STARTER_INC . '/forms/class-form-handler.php';
/**
* 注册博客布局侧边栏
*/
function developer_starter_register_blog_sidebar() {
register_sidebar( array(
'name' => __( '博客布局侧边栏', 'developer-starter' ),
'id' => 'blog-module-sidebar',
'description' => __( '用于博客布局模块的侧边栏小工具区域', 'developer-starter' ),
'before_widget' => '<div id="%1$s" class="sidebar-widget widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h4 class="widget-title">',
'after_title' => '</h4>',
) );
}
add_action( 'widgets_init', 'developer_starter_register_blog_sidebar' );
/**
* 初始化主题
*/
function developer_starter_init() {
// 初始化核心类
new Developer_Starter\Core\Theme_Setup();
new Developer_Starter\Core\Assets();
new Developer_Starter\Core\Message_Manager();
new Developer_Starter\Core\SMTP_Manager();
// 初始化后台管理
if ( is_admin() ) {
new Developer_Starter\Admin\Admin_Settings();
new Developer_Starter\Admin\Meta_Boxes();
}
// 初始化模块管理器
Developer_Starter\Modules\Module_Manager::get_instance();
// 初始化中国特性功能
new Developer_Starter\China\China_Features();
// 初始化SEO
new Developer_Starter\SEO\SEO_Manager();
// 初始化首页创建器
new Developer_Starter\Core\Homepage_Creator();
// 初始化解决方案页面创建器
new Developer_Starter\Core\Solutions_Page_Creator();
// 初始化落地页创建器
new Developer_Starter\Core\Landing_Page_Creator();
// 初始化功能清单展示页面创建器
new Developer_Starter\Core\Features_Showcase_Page_Creator();
// 初始化资源下载页面创建器
new Developer_Starter\Core\Resources_Page_Creator();
// 初始化博客页面创建器
new Developer_Starter\Core\Blog_Page_Creator();
// 初始化文章增强器
Developer_Starter\Core\Post_Enhancer::get_instance();
// 初始化菜单保护器
new Developer_Starter\Core\Menu_Protector();
// 初始化公告管理器
new Developer_Starter\Core\Announcement_Manager();
// 初始化招聘管理
new Developer_Starter\Core\Careers_Manager();
// 初始化用户认证
new Developer_Starter\Core\Auth_Manager();
// 初始化FAQ管理
new Developer_Starter\Core\FAQ_Manager();
// 初始化分类管理器
new Developer_Starter\Core\Category_Manager();
// 初始化表单系统
Developer_Starter\Forms\Form_Manager::get_instance();
if ( is_admin() ) {
new Developer_Starter\Forms\Form_Admin();
}
new Developer_Starter\Forms\Form_Handler();
}
add_action( 'after_setup_theme', 'developer_starter_init', 5 );
/**
* 自定义评论回调函数
* 提前定义以确保在 comments.php 加载前可用
*/
if ( ! function_exists( 'developer_starter_comment_callback' ) ) {
function developer_starter_comment_callback( $comment, $args, $depth ) {
$GLOBALS['comment'] = $comment;
// 用户名脱敏由全局过滤器 get_comment_author 自动处理
?>
<li id="comment-<?php comment_ID(); ?>" <?php comment_class( 'comment-item' ); ?>>
<article class="comment-body">
<div class="comment-avatar">
<?php echo get_avatar( $comment, 48 ); ?>
</div>
<div class="comment-content">
<div class="comment-meta">
<span class="comment-author"><?php echo esc_html( get_comment_author() ); ?></span>
<span class="comment-date"><?php echo get_comment_date(); ?></span>
<?php if ( $comment->comment_approved == '0' ) : ?>
<span class="comment-awaiting"><?php esc_html_e( '待审核', 'developer-starter' ); ?></span>
<?php endif; ?>
</div>
<div class="comment-text">
<?php comment_text(); ?>
</div>
<div class="comment-actions">
<?php
comment_reply_link( array_merge( $args, array(
'depth' => $depth,
'max_depth' => $args['max_depth'],
) ) );
?>
</div>
</div>
</article>
<?php
}
}
/**
* 用户名脱敏处理
*/
if ( ! function_exists( 'developer_starter_mask_username' ) ) {
function developer_starter_mask_username( $name ) {
$name = trim( $name );
if ( empty( $name ) ) {
return $name;
}
// 获取字符串长度(支持中文)
$len = mb_strlen( $name, 'UTF-8' );
if ( $len <= 1 ) {
return $name;
}
// 取第一个字符
$first = mb_substr( $name, 0, 1, 'UTF-8' );
// 其余用*代替
$stars = str_repeat( '*', min( $len - 1, 3 ) );
return $first . $stars;
}
}
/**
* 过滤评论作者名(全局脱敏)
*/
add_filter( 'get_comment_author', 'developer_starter_filter_comment_author', 10, 3 );
function developer_starter_filter_comment_author( $author, $comment_id, $comment ) {
$privacy_enabled = developer_starter_get_option( 'comment_username_privacy', '' );
if ( $privacy_enabled && ! empty( $author ) ) {
return developer_starter_mask_username( $author );
}
return $author;
}
/**
* 过滤评论回复链接中的作者名
*/
add_filter( 'comment_reply_link', 'developer_starter_filter_reply_link', 10, 4 );
function developer_starter_filter_reply_link( $link, $args, $comment, $post ) {
$privacy_enabled = developer_starter_get_option( 'comment_username_privacy', '' );
if ( $privacy_enabled ) {
// 获取原始作者名并进行脱敏替换
$original_author = get_comment_author( $comment );
// 由于 get_comment_author 已经被过滤,这里不需要再次脱敏
// 但需要确保回复链接文本中的作者名也被脱敏
}
return $link;
}
/**
* 过滤评论回复标题中的作者名
*/
add_filter( 'comment_form_defaults', 'developer_starter_filter_reply_title', 10, 1 );
function developer_starter_filter_reply_title( $defaults ) {
$privacy_enabled = developer_starter_get_option( 'comment_username_privacy', '' );
if ( $privacy_enabled ) {
// 修改回复标题格式,使用过滤后的作者名
$defaults['title_reply_to'] = __( '回复 %s', 'developer-starter' );
}
return $defaults;
}
/**
* 主题模板标签函数
*/
require_once DEVELOPER_STARTER_INC . '/template-tags.php';
/**
* 自定义器扩展
*/
require_once DEVELOPER_STARTER_INC . '/customizer/class-customizer.php';
/**
* 将国家代码转换为国旗 Emoji
*/
function developer_starter_country_to_flag( $country_code ) {
$country_code = strtoupper( trim( $country_code ) );
// 如果已经是 emoji(以字节判断)或包含 http,直接返回
if ( strlen( $country_code ) > 10 || strpos( $country_code, 'HTTP' ) === 0 ) {
return $country_code;
}
// 只处理2位国家代码
if ( strlen( $country_code ) !== 2 ) {
return $country_code;
}
// 将国家代码转换为区域指示符号
// A = 0x1F1E6, B = 0x1F1E7, ...
$first = 0x1F1E6 + ord( $country_code[0] ) - ord( 'A' );
$second = 0x1F1E6 + ord( $country_code[1] ) - ord( 'A' );
return mb_convert_encoding( '&#' . $first . ';&#' . $second . ';', 'UTF-8', 'HTML-ENTITIES' );
}
/**
* 输出语言切换弹窗到页面底部
*/
function developer_starter_output_translate_modal() {
$translate_enable = developer_starter_get_option( 'translate_enable', '' );
$translate_languages = developer_starter_get_option( 'translate_languages', array() );
if ( ! $translate_enable || empty( $translate_languages ) ) {
return;
}
?>
<!-- 语言切换弹窗 - Apple风格 -->
<div class="translate-modal-overlay" id="translate-modal-overlay"></div>
<div class="translate-modal" id="translate-modal">
<div class="translate-modal-header">
<h3>选择语言</h3>
<button type="button" class="translate-modal-close" id="translate-modal-close">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</div>
<div class="translate-modal-body">
<div class="translate-lang-grid">
<?php foreach ( $translate_languages as $lang ) :
if ( empty( $lang['name'] ) || empty( $lang['code'] ) ) continue;
?>
<a href="javascript:;" class="translate-lang-item" data-lang="<?php echo esc_attr( $lang['code'] ); ?>">
<?php if ( ! empty( $lang['icon'] ) ) : ?>
<?php if ( strpos( $lang['icon'], 'http' ) === 0 ) : ?>
<img src="<?php echo esc_url( $lang['icon'] ); ?>" alt="" class="lang-icon" />
<?php else : ?>
<span class="lang-icon-emoji"><?php echo developer_starter_country_to_flag( $lang['icon'] ); ?></span>
<?php endif; ?>
<?php endif; ?>
<span class="lang-name"><?php echo esc_html( $lang['name'] ); ?></span>
</a>
<?php endforeach; ?>
</div>
</div>
</div>
<?php
}
add_action( 'wp_footer', 'developer_starter_output_translate_modal' );
/**
* 输出顶部登录弹窗到页面底部
*/
function developer_starter_output_login_modal() {
$header_login_enable = developer_starter_get_option( 'header_login_enable', '' );
// 只有启用了顶部登录按钮且用户未登录时才输出
// 注意:登录用户访问文章页面时缓存已被禁用(见 functions.php 开头)
if ( ! $header_login_enable || is_user_logged_in() ) {
return;
}
$captcha_enable = developer_starter_get_option( 'auth_captcha_enable', '' );
$register_page_id = developer_starter_get_option( 'register_page_id', '' );
$forgot_page_id = developer_starter_get_option( 'forgot_password_page_id', '' );
?>
<!-- 顶部登录弹窗 -->
<div class="login-modal-overlay" id="login-modal-overlay"></div>
<div class="login-modal" id="login-modal">
<div class="login-modal-header">
<h3>用户登录</h3>
<button type="button" class="login-modal-close" id="login-modal-close">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</div>
<div class="login-modal-body">
<form id="header-login-form" class="login-modal-form" novalidate>
<div class="modal-form-group">
<input type="text" id="header-username" name="username" placeholder="用户名或邮箱" required autocomplete="username" />
</div>
<div class="modal-form-group">
<input type="password" id="header-password" name="password" placeholder="密码" required autocomplete="current-password" />
</div>
<?php if ( $captcha_enable ) : ?>
<div class="modal-form-group">
<div class="slider-captcha modal-captcha" id="header-slider-captcha">
<div class="captcha-track">
<div class="captcha-slider">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
</div>
<div class="captcha-progress"></div>
<span class="captcha-text">向右滑动验证</span>
</div>
</div>
<input type="hidden" name="captcha_verified" id="header-captcha-verified" value="false" />
</div>
<?php endif; ?>
<div class="modal-form-message" id="header-form-message"></div>
<button type="submit" class="login-modal-submit" id="header-login-submit">
<span class="btn-text">登 录</span>
<span class="btn-loading" style="display:none">
<svg class="spinner" viewBox="0 0 24 24" width="20" height="20"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3" fill="none" stroke-linecap="round" stroke-dasharray="31.416" stroke-dashoffset="10"><animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite"/></circle></svg>
</span>
</button>
<?php wp_nonce_field( 'developer_starter_auth', 'header_auth_nonce' ); ?>
</form>
<div class="login-modal-footer">
<?php if ( $register_page_id && get_option( 'users_can_register' ) ) : ?>
<a href="<?php echo esc_url( get_permalink( $register_page_id ) ); ?>">注册账号</a>
<?php endif; ?>
<?php if ( $forgot_page_id ) : ?>
<a href="<?php echo esc_url( get_permalink( $forgot_page_id ) ); ?>">忘记密码?</a>
<?php endif; ?>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var loginBtn = document.getElementById('header-login-toggle');
var loginModal = document.getElementById('login-modal');
var loginOverlay = document.getElementById('login-modal-overlay');
var loginClose = document.getElementById('login-modal-close');
var loginForm = document.getElementById('header-login-form');
if (!loginBtn || !loginModal) return;
// 打开弹窗
loginBtn.addEventListener('click', function() {
loginModal.classList.add('active');
loginOverlay.classList.add('active');
document.body.style.overflow = 'hidden';
});
// 关闭弹窗
function closeModal() {
loginModal.classList.remove('active');
loginOverlay.classList.remove('active');
document.body.style.overflow = '';
}
loginClose.addEventListener('click', closeModal);
loginOverlay.addEventListener('click', closeModal);
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closeModal();
});
// 用户菜单下拉
var userToggle = document.getElementById('header-user-toggle');
var userDropdown = document.getElementById('user-dropdown');
if (userToggle && userDropdown) {
userToggle.addEventListener('click', function(e) {
e.stopPropagation();
userDropdown.classList.toggle('active');
});
document.addEventListener('click', function() {
userDropdown.classList.remove('active');
});
}
// 滑动验证码
var captcha = document.getElementById('header-slider-captcha');
if (captcha) {
initHeaderCaptcha(captcha);
}
// 表单提交
loginForm.addEventListener('submit', function(e) {
e.preventDefault();
var submitBtn = document.getElementById('header-login-submit');
var message = document.getElementById('header-form-message');
var formData = new FormData(loginForm);
formData.append('action', 'developer_starter_login');
formData.append('nonce', document.querySelector('[name="header_auth_nonce"]').value);
submitBtn.disabled = true;
submitBtn.querySelector('.btn-text').style.display = 'none';
submitBtn.querySelector('.btn-loading').style.display = 'inline-flex';
fetch('<?php echo admin_url( 'admin-ajax.php' ); ?>', {
method: 'POST',
body: formData
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.success) {
message.className = 'modal-form-message success';
message.textContent = data.data.message;
setTimeout(function() {
window.location.reload();
}, 1000);
} else {
message.className = 'modal-form-message error';
message.textContent = data.data.message;
submitBtn.disabled = false;
submitBtn.querySelector('.btn-text').style.display = 'inline';
submitBtn.querySelector('.btn-loading').style.display = 'none';
}
})
.catch(function() {
message.className = 'modal-form-message error';
message.textContent = '网络错误,请稍后再试';
submitBtn.disabled = false;
submitBtn.querySelector('.btn-text').style.display = 'inline';
submitBtn.querySelector('.btn-loading').style.display = 'none';
});
});
});
function initHeaderCaptcha(container) {
var slider = container.querySelector('.captcha-slider');
var progress = container.querySelector('.captcha-progress');
var text = container.querySelector('.captcha-text');
var track = container.querySelector('.captcha-track');
var verified = document.getElementById('header-captcha-verified');
var isDragging = false;
var startX = 0;
var sliderWidth = slider.offsetWidth;
var trackWidth = track.offsetWidth - sliderWidth;
function handleStart(e) {
if (verified.value === 'true') return;
isDragging = true;
startX = (e.touches ? e.touches[0].clientX : e.clientX) - slider.offsetLeft;
slider.style.transition = 'none';
progress.style.transition = 'none';
}
function handleMove(e) {
if (!isDragging) return;
e.preventDefault();
var x = (e.touches ? e.touches[0].clientX : e.clientX) - startX;
x = Math.max(0, Math.min(x, trackWidth));
slider.style.left = x + 'px';
progress.style.width = (x + sliderWidth) + 'px';
}
function handleEnd() {
if (!isDragging) return;
isDragging = false;
slider.style.transition = 'left 0.3s';
progress.style.transition = 'width 0.3s';
var x = parseInt(slider.style.left) || 0;
if (x >= trackWidth - 5) {
verified.value = 'true';
container.classList.add('verified');
text.textContent = '验证成功';
slider.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg>';
} else {
slider.style.left = '0';
progress.style.width = sliderWidth + 'px';
}
}
slider.addEventListener('mousedown', handleStart);
document.addEventListener('mousemove', handleMove);
document.addEventListener('mouseup', handleEnd);
slider.addEventListener('touchstart', handleStart);
document.addEventListener('touchmove', handleMove, { passive: false });
document.addEventListener('touchend', handleEnd);
}
</script>
<?php
}
add_action( 'wp_footer', 'developer_starter_output_login_modal' );
/**
* WordPress 优化功能
*/
function developer_starter_optimizations() {
// 禁用 Emoji 脚本
if ( developer_starter_get_option( 'disable_emoji', '' ) ) {
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'admin_print_styles', 'print_emoji_styles' );
remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
add_filter( 'tiny_mce_plugins', function( $plugins ) {
return is_array( $plugins ) ? array_diff( $plugins, array( 'wpemoji' ) ) : array();
} );
add_filter( 'wp_resource_hints', function( $urls, $relation_type ) {
if ( 'dns-prefetch' === $relation_type ) {
$urls = array_filter( $urls, function( $url ) {
return strpos( $url, 'https://s.w.org/images/core/emoji/' ) === false;
} );
}
return $urls;
}, 10, 2 );
}
// 禁用 oEmbed
if ( developer_starter_get_option( 'disable_embeds', '' ) ) {
remove_action( 'rest_api_init', 'wp_oembed_register_route' );
remove_filter( 'oembed_dataparse', 'wp_filter_oembed_result', 10 );
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
remove_action( 'wp_head', 'wp_oembed_add_host_js' );
add_filter( 'embed_oembed_discover', '__return_false' );
add_filter( 'rewrite_rules_array', function( $rules ) {
foreach ( $rules as $rule => $rewrite ) {
if ( strpos( $rewrite, 'embed=true' ) !== false ) {
unset( $rules[ $rule ] );
}
}
return $rules;
} );
}
// 禁用 XML-RPC
if ( developer_starter_get_option( 'disable_xmlrpc', '' ) ) {
add_filter( 'xmlrpc_enabled', '__return_false' );
add_filter( 'wp_headers', function( $headers ) {
unset( $headers['X-Pingback'] );
return $headers;
} );
remove_action( 'wp_head', 'rsd_link' );
}
// 隐藏 WordPress 版本号(仅移除HTML中的generator标签,不影响资源文件版本号)
if ( developer_starter_get_option( 'remove_wp_version', '' ) ) {
remove_action( 'wp_head', 'wp_generator' );
add_filter( 'the_generator', '__return_empty_string' );
// 注意:资源文件版本号的移除由独立选项 remove_assets_version 控制
}
// 限制 REST API 访问
if ( developer_starter_get_option( 'disable_rest_api', '' ) ) {
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
if ( ! is_user_logged_in() ) {
return new WP_Error( 'rest_not_logged_in', '仅允许登录用户访问 REST API', array( 'status' => 401 ) );
}
return $result;
} );
}
// 移除短链接
if ( developer_starter_get_option( 'remove_shortlink', '' ) ) {
remove_action( 'wp_head', 'wp_shortlink_wp_head', 10 );
remove_action( 'template_redirect', 'wp_shortlink_header', 11 );
}
// 移除 RSD/WLW 链接
if ( developer_starter_get_option( 'remove_rsd_wlw', '' ) ) {
remove_action( 'wp_head', 'rsd_link' );
remove_action( 'wp_head', 'wlwmanifest_link' );
}
// 禁用 Pingback/Trackback
if ( developer_starter_get_option( 'disable_pingback', '' ) ) {
// 禁用 pingback
add_filter( 'xmlrpc_methods', function( $methods ) {
unset( $methods['pingback.ping'] );
unset( $methods['pingback.extensions.getPingbacks'] );
return $methods;
} );
// 移除 X-Pingback header
add_filter( 'wp_headers', function( $headers ) {
unset( $headers['X-Pingback'] );
return $headers;
} );
// 禁用 trackback
add_filter( 'pings_open', '__return_false', 9999 );
// 关闭文章的 ping 状态
add_action( 'pre_ping', function( &$links ) {
$links = array();
} );
}
// 限制修订版本
if ( developer_starter_get_option( 'disable_revisions', '' ) ) {
if ( ! defined( 'WP_POST_REVISIONS' ) ) {
define( 'WP_POST_REVISIONS', 3 );
}
}
// 禁用 Gutenberg
if ( developer_starter_get_option( 'disable_gutenberg', '' ) ) {
add_filter( 'use_block_editor_for_post', '__return_false', 10 );
add_filter( 'use_block_editor_for_post_type', '__return_false', 10 );
add_action( 'wp_enqueue_scripts', function() {
wp_dequeue_style( 'wp-block-library' );
wp_dequeue_style( 'wp-block-library-theme' );
wp_dequeue_style( 'wc-block-style' );
wp_dequeue_style( 'global-styles' );
}, 100 );
}
// 禁用区块小工具(恢复经典小工具界面)
if ( developer_starter_get_option( 'disable_block_widgets', '' ) ) {
add_filter( 'gutenberg_use_widgets_block_editor', '__return_false' );
add_filter( 'use_widgets_block_editor', '__return_false' );
}
// ===== 输出优化(Head 清理)=====
// 移除相邻文章链接
if ( developer_starter_get_option( 'remove_adjacent_posts', '' ) ) {
remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 );
}
// 移除 Feed 链接
if ( developer_starter_get_option( 'remove_feed_links', '' ) ) {
remove_action( 'wp_head', 'feed_links_extra', 3 );
remove_action( 'wp_head', 'feed_links', 2 );
}
// 移除 JSON API 链接
if ( developer_starter_get_option( 'remove_json_api_link', '' ) ) {
remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
remove_action( 'template_redirect', 'rest_output_link_header', 11 );
}
// 移除 DNS 预取提示
if ( developer_starter_get_option( 'remove_dns_prefetch_hints', '' ) ) {
add_filter( 'wp_resource_hints', function( $hints, $relation_type ) {
if ( 'dns-prefetch' === $relation_type ) {
return array();
}
return $hints;
}, 10, 2 );
}
// 移除 Gutenberg 样式
if ( developer_starter_get_option( 'remove_gutenberg_css', '' ) ) {
add_action( 'wp_enqueue_scripts', function() {
wp_dequeue_style( 'wp-block-library' );
wp_dequeue_style( 'wp-block-library-theme' );
wp_dequeue_style( 'classic-theme-styles' );
}, 999 );
}
// 移除全局样式
if ( developer_starter_get_option( 'remove_global_styles', '' ) ) {
remove_action( 'wp_enqueue_scripts', 'wp_enqueue_global_styles' );
remove_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' );
}
}
add_action( 'init', 'developer_starter_optimizations', 1 );
/**
* 移除资源版本号
*/
function developer_starter_remove_version_query( $src ) {
if ( strpos( $src, 'ver=' ) ) {
$src = remove_query_arg( 'ver', $src );
}
return $src;
}
/**
* 移除所有资源文件的版本号(独立选项)
*/
function developer_starter_remove_assets_version() {
if ( developer_starter_get_option( 'remove_assets_version', '' ) ) {
add_filter( 'style_loader_src', 'developer_starter_remove_version_query', 9999 );
add_filter( 'script_loader_src', 'developer_starter_remove_version_query', 9999 );
}
}
add_action( 'init', 'developer_starter_remove_assets_version', 1 );
/**
* HTML 压缩功能
*/
function developer_starter_html_minify_start() {
if ( ! developer_starter_get_option( 'html_minify', '' ) ) {
return;
}
// 不在后台和 AJAX 请求中压缩
if ( is_admin() || defined( 'DOING_AJAX' ) || defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) ) {
return;
}
// 不压缩 feed
if ( is_feed() ) {
return;
}
ob_start( 'developer_starter_html_minify_callback' );
}
add_action( 'template_redirect', 'developer_starter_html_minify_start', 1 );
/**
* HTML 压缩回调函数
*/
function developer_starter_html_minify_callback( $html ) {
if ( empty( $html ) ) {
return $html;
}
// 保护 script 和 style 标签内容
$protected = array();
$index = 0;
// 保护 <script> 内容
$html = preg_replace_callback( '/<script[^>]*>.*?<\/script>/is', function( $matches ) use ( &$protected, &$index ) {
$key = '<!--PROTECTED_SCRIPT_' . $index . '-->';
$protected[$key] = $matches[0];
$index++;
return $key;
}, $html );
// 保护 <style> 内容
$html = preg_replace_callback( '/<style[^>]*>.*?<\/style>/is', function( $matches ) use ( &$protected, &$index ) {
$key = '<!--PROTECTED_STYLE_' . $index . '-->';
$protected[$key] = $matches[0];
$index++;
return $key;
}, $html );
// 保护 <pre> 和 <textarea> 内容
$html = preg_replace_callback( '/<(pre|textarea)[^>]*>.*?<\/\1>/is', function( $matches ) use ( &$protected, &$index ) {
$key = '<!--PROTECTED_PRE_' . $index . '-->';
$protected[$key] = $matches[0];
$index++;
return $key;
}, $html );
// 移除 HTML 注释(保护条件注释)
$html = preg_replace( '/<!--(?!\[|PROTECTED).*?-->/s', '', $html );
// 移除多余空白(但保留单个空格)
$html = preg_replace( '/\s+/', ' ', $html );
// 移除标签间的空白
$html = preg_replace( '/>\s+</', '><', $html );
// 恢复受保护的内容
foreach ( $protected as $key => $value ) {
$html = str_replace( $key, $value, $html );
}
return $html;
}
/**
* DNS 预解析和预连接
*/
function developer_starter_output_dns_prefetch() {
// DNS 预解析
$dns_prefetch = developer_starter_get_option( 'dns_prefetch', '' );
if ( $dns_prefetch ) {
$domains = array_filter( array_map( 'trim', explode( "\n", $dns_prefetch ) ) );
foreach ( $domains as $domain ) {
$domain = str_replace( array( 'http://', 'https://', '//' ), '', $domain );
echo '<link rel="dns-prefetch" href="//' . esc_attr( $domain ) . '">' . "\n";
}
}
// 预连接
$preconnect = developer_starter_get_option( 'preconnect_urls', '' );
if ( $preconnect ) {
$domains = array_filter( array_map( 'trim', explode( "\n", $preconnect ) ) );
foreach ( $domains as $domain ) {
$domain = str_replace( array( 'http://', 'https://', '//' ), '', $domain );
echo '<link rel="preconnect" href="https://' . esc_attr( $domain ) . '" crossorigin>' . "\n";
}
}
}
add_action( 'wp_head', 'developer_starter_output_dns_prefetch', 1 );
/**
* 心跳控制
*/
function developer_starter_heartbeat_control() {