From aea6095c0a23d2104d1dc40414b01c3295de2adb Mon Sep 17 00:00:00 2001
From: OldTaoge <51744784+OldTaoge@users.noreply.github.com>
Date: Tue, 21 Jul 2026 09:55:39 +0800
Subject: [PATCH] convert to plugins+theme
---
README.md | 6 +-
.../includes/archive-search.php | 67 +
.../itstudio-content/includes/post-types.php | 145 ++
.../itstudio-content/includes/post-views.php | 203 ++
.../includes/template-helpers.php | 115 +
plugins/itstudio-content/itstudio-content.php | 42 +
.../includes/join-system.php | 1857 +++--------------
.../includes/recruitment-articles.php | 295 +++
.../itstudio-recruitment/includes/terms.php | 261 +++
.../itstudio-recruitment.php | 36 +
plugins/itstudio-services/includes/admin.php | 280 +++
plugins/itstudio-services/includes/meta.php | 141 ++
.../itstudio-services/includes/post-type.php | 53 +
.../itstudio-services/itstudio-services.php | 38 +
themes/ITStudioMainSite/.idea/.gitignore | 10 +
.../.idea/ITStudioMainSite.iml | 8 +
themes/ITStudioMainSite/.idea/modules.xml | 8 +
themes/ITStudioMainSite/.idea/vcs.xml | 6 +
404.php => themes/ITStudioMainSite/404.php | 0
themes/ITStudioMainSite/README.md | 291 +++
.../ITStudioMainSite/archive.php | 0
.../assets}/css/about-hero.css | 0
.../ITStudioMainSite/assets}/css/content.css | 0
.../ITStudioMainSite/assets}/css/footer.css | 0
.../assets}/css/front-page.css | 0
.../ITStudioMainSite/assets}/css/header.css | 0
.../ITStudioMainSite/assets}/css/intro.css | 0
.../assets}/css/join-page.css | 0
.../assets}/css/services-page.css | 0
.../ITStudioMainSite/assets}/js/hero-waves.js | 0
.../ITStudioMainSite/assets}/js/home-hero.js | 0
.../assets}/js/intro-scroll.js | 0
.../assets}/js/join-canvas.js | 0
.../assets}/js/landing-hero-canvas.js | 0
.../assets}/js/lang-toggle.js | 0
.../ITStudioMainSite/assets}/js/main.js | 0
.../assets}/js/single-title-fit.js | 0
.../ITStudioMainSite/assets}/js/stream.js | 0
.../assets}/js/theme-toggle.js | 0
.../assets}/js/vendor/anime.min.js | 0
.../docs/plugin-split-plan.md | 87 +
.../ITStudioMainSite/footer.php | 0
themes/ITStudioMainSite/functions.php | 412 ++++
.../ITStudioMainSite/header.php | 0
.../ITStudioMainSite/index.php | 0
.../ITStudioMainSite/page-about.php | 0
.../ITStudioMainSite/page-join.php | 0
.../ITStudioMainSite/page-services.php | 0
page.php => themes/ITStudioMainSite/page.php | 0
.../Organization-ITstudio-shield.svg | 0
.../ITStudioMainSite/resources}/head_logo.svg | 0
.../resources}/it_logo_2024.svg | 0
.../ITStudioMainSite/resources}/mainpage.jpg | Bin
.../ITStudioMainSite/resources}/ouc-logo.svg | 0
.../ITStudioMainSite/resources}/title.svg | 0
.../ITStudioMainSite/single.php | 0
.../ITStudioMainSite/style.css | 0
57 files changed, 2742 insertions(+), 1619 deletions(-)
create mode 100644 plugins/itstudio-content/includes/archive-search.php
create mode 100644 plugins/itstudio-content/includes/post-types.php
create mode 100644 plugins/itstudio-content/includes/post-views.php
create mode 100644 plugins/itstudio-content/includes/template-helpers.php
create mode 100644 plugins/itstudio-content/itstudio-content.php
rename functions.php => plugins/itstudio-recruitment/includes/join-system.php (63%)
create mode 100644 plugins/itstudio-recruitment/includes/recruitment-articles.php
create mode 100644 plugins/itstudio-recruitment/includes/terms.php
create mode 100644 plugins/itstudio-recruitment/itstudio-recruitment.php
create mode 100644 plugins/itstudio-services/includes/admin.php
create mode 100644 plugins/itstudio-services/includes/meta.php
create mode 100644 plugins/itstudio-services/includes/post-type.php
create mode 100644 plugins/itstudio-services/itstudio-services.php
create mode 100644 themes/ITStudioMainSite/.idea/.gitignore
create mode 100644 themes/ITStudioMainSite/.idea/ITStudioMainSite.iml
create mode 100644 themes/ITStudioMainSite/.idea/modules.xml
create mode 100644 themes/ITStudioMainSite/.idea/vcs.xml
rename 404.php => themes/ITStudioMainSite/404.php (100%)
create mode 100644 themes/ITStudioMainSite/README.md
rename archive.php => themes/ITStudioMainSite/archive.php (100%)
rename {assets => themes/ITStudioMainSite/assets}/css/about-hero.css (100%)
rename {assets => themes/ITStudioMainSite/assets}/css/content.css (100%)
rename {assets => themes/ITStudioMainSite/assets}/css/footer.css (100%)
rename {assets => themes/ITStudioMainSite/assets}/css/front-page.css (100%)
rename {assets => themes/ITStudioMainSite/assets}/css/header.css (100%)
rename {assets => themes/ITStudioMainSite/assets}/css/intro.css (100%)
rename {assets => themes/ITStudioMainSite/assets}/css/join-page.css (100%)
rename {assets => themes/ITStudioMainSite/assets}/css/services-page.css (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/hero-waves.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/home-hero.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/intro-scroll.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/join-canvas.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/landing-hero-canvas.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/lang-toggle.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/main.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/single-title-fit.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/stream.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/theme-toggle.js (100%)
rename {assets => themes/ITStudioMainSite/assets}/js/vendor/anime.min.js (100%)
create mode 100644 themes/ITStudioMainSite/docs/plugin-split-plan.md
rename footer.php => themes/ITStudioMainSite/footer.php (100%)
create mode 100644 themes/ITStudioMainSite/functions.php
rename header.php => themes/ITStudioMainSite/header.php (100%)
rename index.php => themes/ITStudioMainSite/index.php (100%)
rename page-about.php => themes/ITStudioMainSite/page-about.php (100%)
rename page-join.php => themes/ITStudioMainSite/page-join.php (100%)
rename page-services.php => themes/ITStudioMainSite/page-services.php (100%)
rename page.php => themes/ITStudioMainSite/page.php (100%)
rename {resources => themes/ITStudioMainSite/resources}/Organization-ITstudio-shield.svg (100%)
rename {resources => themes/ITStudioMainSite/resources}/head_logo.svg (100%)
rename {resources => themes/ITStudioMainSite/resources}/it_logo_2024.svg (100%)
rename {resources => themes/ITStudioMainSite/resources}/mainpage.jpg (100%)
rename {resources => themes/ITStudioMainSite/resources}/ouc-logo.svg (100%)
rename {resources => themes/ITStudioMainSite/resources}/title.svg (100%)
rename single.php => themes/ITStudioMainSite/single.php (100%)
rename style.css => themes/ITStudioMainSite/style.css (100%)
diff --git a/README.md b/README.md
index 7571d31..02b9c97 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,12 @@
-

+

@@ -35,7 +35,7 @@
1. 克隆本仓库到 WordPress 主题目录:
```bash
cd wp-content/themes
-git clone https://github.com/itstudio-2002/ITStudioMainSite.git
+git clone https://git.itouc.cn/ITStudio_OUC/ITStudioMainSite.git
```
2. 在 WordPress 后台激活主题:
diff --git a/plugins/itstudio-content/includes/archive-search.php b/plugins/itstudio-content/includes/archive-search.php
new file mode 100644
index 0000000..9983175
--- /dev/null
+++ b/plugins/itstudio-content/includes/archive-search.php
@@ -0,0 +1,67 @@
+get('itstudio_archive_extend_search')) {
+ return false;
+ }
+
+ $keyword = trim((string) $query->get('itstudio_archive_keyword'));
+ return $keyword !== '';
+}
+
+function itstudio_archive_extended_search_join($join, $query) {
+ if (!itstudio_archive_extended_search_enabled($query)) {
+ return $join;
+ }
+
+ global $wpdb;
+ if (strpos($join, $wpdb->users) !== false) {
+ return $join;
+ }
+
+ return $join . " LEFT JOIN {$wpdb->users} ON ({$wpdb->posts}.post_author = {$wpdb->users}.ID) ";
+}
+add_filter('posts_join', 'itstudio_archive_extended_search_join', 10, 2);
+
+function itstudio_archive_extended_search_where($where, $query) {
+ if (!itstudio_archive_extended_search_enabled($query)) {
+ return $where;
+ }
+
+ global $wpdb;
+ $keyword = trim((string) $query->get('itstudio_archive_keyword'));
+ $like = '%' . $wpdb->esc_like($keyword) . '%';
+
+ $search_sql = $wpdb->prepare(
+ " AND (
+ {$wpdb->posts}.post_title LIKE %s
+ OR {$wpdb->posts}.post_excerpt LIKE %s
+ OR {$wpdb->posts}.post_content LIKE %s
+ OR {$wpdb->users}.display_name LIKE %s
+ OR {$wpdb->users}.user_login LIKE %s
+ OR {$wpdb->users}.user_nicename LIKE %s
+ )",
+ $like,
+ $like,
+ $like,
+ $like,
+ $like,
+ $like
+ );
+
+ return $where . $search_sql;
+}
+add_filter('posts_where', 'itstudio_archive_extended_search_where', 10, 2);
diff --git a/plugins/itstudio-content/includes/post-types.php b/plugins/itstudio-content/includes/post-types.php
new file mode 100644
index 0000000..1512ef2
--- /dev/null
+++ b/plugins/itstudio-content/includes/post-types.php
@@ -0,0 +1,145 @@
+ array(
+ 'name' => __('公告', 'itstudio'),
+ 'singular_name' => __('公告', 'itstudio'),
+ ),
+ 'public' => true,
+ 'has_archive' => true,
+ 'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
+ 'taxonomies' => array('post_tag'),
+ 'menu_icon' => 'dashicons-megaphone',
+ 'show_in_rest' => true,
+ ));
+
+ register_post_type('news', array(
+ 'labels' => array(
+ 'name' => __('新闻', 'itstudio'),
+ 'singular_name' => __('新闻', 'itstudio'),
+ ),
+ 'public' => true,
+ 'has_archive' => 'news',
+ 'rewrite' => array(
+ 'slug' => 'news',
+ 'with_front' => false,
+ ),
+ 'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
+ 'taxonomies' => array('post_tag'),
+ 'menu_icon' => 'dashicons-media-document',
+ 'show_in_rest' => true,
+ ));
+
+ register_taxonomy_for_object_type('post_tag', 'announcement');
+ register_taxonomy_for_object_type('post_tag', 'news');
+}
+add_action('init', 'itstudio_content_register_post_types');
+
+/**
+ * 内容权重 ACF 字段组:数值越大文章在侧栏排序越靠前。
+ * 招新文章标记(itstudio_is_recruitment_article)不在此插件,由 itstudio-recruitment 负责。
+ */
+function itstudio_content_register_acf_fields() {
+ if (!function_exists('acf_add_local_field_group')) {
+ return;
+ }
+
+ acf_add_local_field_group(array(
+ 'key' => 'group_itstudio_content_priority',
+ 'title' => '内容权重',
+ 'fields' => array(
+ array(
+ 'key' => 'field_itstudio_weight',
+ 'label' => '权重',
+ 'name' => 'itstudio_weight',
+ 'type' => 'number',
+ 'instructions' => '数值越大,文章在侧栏排序越靠前。',
+ 'required' => 0,
+ 'default_value' => 0,
+ 'min' => 0,
+ 'step' => 1,
+ ),
+ ),
+ 'location' => array(
+ array(
+ array(
+ 'param' => 'post_type',
+ 'operator' => '==',
+ 'value' => 'post',
+ ),
+ ),
+ array(
+ array(
+ 'param' => 'post_type',
+ 'operator' => '==',
+ 'value' => 'announcement',
+ ),
+ ),
+ array(
+ array(
+ 'param' => 'post_type',
+ 'operator' => '==',
+ 'value' => 'news',
+ ),
+ ),
+ ),
+ 'position' => 'side',
+ 'style' => 'default',
+ 'active' => true,
+ 'show_in_rest' => 1,
+ ));
+}
+add_action('acf/init', 'itstudio_content_register_acf_fields');
+
+/**
+ * 新闻/公告在只有日期格式时补上时:分,提升列表时间精度。
+ */
+function itstudio_expand_news_notice_date_precision($the_date, $format, $post) {
+ $post_obj = $post instanceof WP_Post ? $post : get_post($post);
+ if (!($post_obj instanceof WP_Post)) {
+ return $the_date;
+ }
+
+ if (!in_array((string) $post_obj->post_type, array('announcement', 'news'), true)) {
+ return $the_date;
+ }
+
+ $format = (string) $format;
+ if ($format === '') {
+ $format = (string) get_option('date_format');
+ }
+
+ $lower = strtolower($format);
+ if (in_array($lower, array('c', 'r', 'u'), true)) {
+ return $the_date;
+ }
+
+ // Already has time precision.
+ if (preg_match('/[HhGgis]/', $format)) {
+ return $the_date;
+ }
+
+ $timestamp = function_exists('get_post_timestamp')
+ ? get_post_timestamp($post_obj, 'date')
+ : false;
+ if (!$timestamp) {
+ return $the_date;
+ }
+
+ $format_with_time = rtrim($format) . ' H:i';
+ return wp_date($format_with_time, (int) $timestamp, wp_timezone());
+}
+add_filter('get_the_date', 'itstudio_expand_news_notice_date_precision', 10, 3);
diff --git a/plugins/itstudio-content/includes/post-views.php b/plugins/itstudio-content/includes/post-views.php
new file mode 100644
index 0000000..4394b55
--- /dev/null
+++ b/plugins/itstudio-content/includes/post-views.php
@@ -0,0 +1,203 @@
+ $timestamp) {
+ $post_id = (int) $post_id;
+ $timestamp = (int) $timestamp;
+ if ($post_id > 0 && $timestamp > 0) {
+ $clean[(string) $post_id] = $timestamp;
+ }
+ }
+
+ return $clean;
+}
+
+function itstudio_write_view_cookie_map($map, $window_seconds) {
+ if (!headers_sent()) {
+ $cookie_name = itstudio_get_view_cookie_name();
+ $expire_at = time() + max(DAY_IN_SECONDS, (int) $window_seconds * 2);
+ $path = defined('COOKIEPATH') && COOKIEPATH ? COOKIEPATH : '/';
+ $domain = defined('COOKIE_DOMAIN') ? COOKIE_DOMAIN : '';
+ $secure = is_ssl();
+ $http_only = true;
+ $encoded = wp_json_encode($map);
+ if (!is_string($encoded)) {
+ return;
+ }
+
+ if (PHP_VERSION_ID >= 70300) {
+ setcookie($cookie_name, $encoded, array(
+ 'expires' => $expire_at,
+ 'path' => $path,
+ 'domain' => $domain,
+ 'secure' => $secure,
+ 'httponly' => $http_only,
+ 'samesite' => 'Lax',
+ ));
+ } else {
+ setcookie($cookie_name, $encoded, $expire_at, $path, $domain, $secure, $http_only);
+ }
+
+ $_COOKIE[$cookie_name] = $encoded;
+ }
+}
+
+function itstudio_should_count_post_view($post_id) {
+ $post_id = (int) $post_id;
+ if ($post_id <= 0) {
+ return false;
+ }
+
+ if (itstudio_is_probably_bot_request()) {
+ return false;
+ }
+
+ $window_seconds = (int) apply_filters('itstudio_post_view_window_seconds', 12 * HOUR_IN_SECONDS);
+ $window_seconds = max(60, $window_seconds);
+ $max_entries = (int) apply_filters('itstudio_post_view_cookie_max_entries', 120);
+ $max_entries = max(10, $max_entries);
+
+ $now = time();
+ $key = (string) $post_id;
+ $map = itstudio_read_view_cookie_map();
+
+ foreach ($map as $id => $timestamp) {
+ if (($now - (int) $timestamp) > $window_seconds) {
+ unset($map[$id]);
+ }
+ }
+
+ if (isset($map[$key]) && ($now - (int) $map[$key]) < $window_seconds) {
+ return false;
+ }
+
+ $map[$key] = $now;
+ if (count($map) > $max_entries) {
+ asort($map, SORT_NUMERIC);
+ $map = array_slice($map, -$max_entries, null, true);
+ }
+
+ itstudio_write_view_cookie_map($map, $window_seconds);
+
+ return true;
+}
+
+function itstudio_track_post_views() {
+ if (is_admin() || wp_doing_ajax() || wp_doing_cron()) {
+ return;
+ }
+
+ if (!is_singular(array('post', 'announcement', 'news')) || is_preview() || is_feed() || is_trackback() || is_embed()) {
+ return;
+ }
+
+ if (!isset($_SERVER['REQUEST_METHOD']) || strtoupper((string) $_SERVER['REQUEST_METHOD']) !== 'GET') {
+ return;
+ }
+
+ $post_id = (int) get_queried_object_id();
+ if ($post_id <= 0) {
+ return;
+ }
+
+ if (!itstudio_should_count_post_view($post_id)) {
+ return;
+ }
+
+ $views = itstudio_get_post_views($post_id) + 1;
+ update_post_meta($post_id, 'post_views_count', $views);
+ update_post_meta($post_id, 'itstudio_views', $views);
+}
+add_action('template_redirect', 'itstudio_track_post_views', 20);
diff --git a/plugins/itstudio-content/includes/template-helpers.php b/plugins/itstudio-content/includes/template-helpers.php
new file mode 100644
index 0000000..df0337e
--- /dev/null
+++ b/plugins/itstudio-content/includes/template-helpers.php
@@ -0,0 +1,115 @@
+ $term_obj->slug,
+ ),
+ $archive_url
+ );
+}
diff --git a/plugins/itstudio-content/itstudio-content.php b/plugins/itstudio-content/itstudio-content.php
new file mode 100644
index 0000000..e6b383f
--- /dev/null
+++ b/plugins/itstudio-content/itstudio-content.php
@@ -0,0 +1,42 @@
+ __('Primary Menu', 'itstudio'),
- ));
-
- load_theme_textdomain('itstudio', get_template_directory() . '/languages');
+if (!defined('ABSPATH')) {
+ exit;
}
-add_action('after_setup_theme', 'itstudio_theme_setup');
-
-add_filter('comments_open', '__return_false', 20, 2);
-add_filter('pings_open', '__return_false', 20, 2);
-add_filter('comments_array', '__return_empty_array', 10, 2);
-
-function itstudio_disable_comments_post_types() {
- $post_types = array('post', 'page', 'announcement', 'news', 'service');
- foreach ($post_types as $post_type) {
- if (post_type_supports($post_type, 'comments')) {
- remove_post_type_support($post_type, 'comments');
- }
- if (post_type_supports($post_type, 'trackbacks')) {
- remove_post_type_support($post_type, 'trackbacks');
- }
- }
-}
-add_action('init', 'itstudio_disable_comments_post_types', 100);
-
-function itstudio_hide_comments_menu() {
- remove_menu_page('edit-comments.php');
-}
-add_action('admin_menu', 'itstudio_hide_comments_menu', 999);
-
-function itstudio_hide_admin_bar_comments() {
- remove_action('admin_bar_menu', 'wp_admin_bar_comments_menu', 60);
-}
-add_action('init', 'itstudio_hide_admin_bar_comments');
-
-function itstudio_redirect_comments_admin_pages() {
- global $pagenow;
- if ($pagenow === 'edit-comments.php' || $pagenow === 'comment.php') {
- wp_safe_redirect(admin_url());
- exit;
- }
-}
-add_action('admin_init', 'itstudio_redirect_comments_admin_pages');
-
-function itstudio_remove_comments_dashboard_widget() {
- remove_meta_box('dashboard_recent_comments', 'dashboard', 'normal');
-}
-add_action('wp_dashboard_setup', 'itstudio_remove_comments_dashboard_widget');
-
-function itstudio_apply_site_identity() {
- $site_name = '爱特工作室';
- $site_tagline = '爱特工作室官方网站';
-
- if (get_option('blogname') !== $site_name) {
- update_option('blogname', $site_name);
- }
-
- if (get_option('blogdescription') !== $site_tagline) {
- update_option('blogdescription', $site_tagline);
- }
-}
-add_action('init', 'itstudio_apply_site_identity', 20);
-
-function itstudio_output_favicon() {
- $favicon_url = get_template_directory_uri() . '/resources/it_logo_2024.svg';
- echo '
' . "\n";
- echo '
' . "\n";
-}
-
-function itstudio_output_theme_bootstrap_script() {
- echo '
' . "\n";
- echo '' . "\n";
-}
-
-function itstudio_output_lang_bootstrap_script() {
- echo '' . "\n";
- echo '' . "\n";
-}
-function itstudio_disable_default_site_icon() {
- remove_action('wp_head', 'wp_site_icon', 99);
- remove_action('admin_head', 'wp_site_icon', 99);
- remove_action('login_head', 'wp_site_icon', 99);
-}
-add_action('init', 'itstudio_disable_default_site_icon');
-add_action('wp_head', 'itstudio_output_theme_bootstrap_script', 0);
-add_action('wp_head', 'itstudio_output_lang_bootstrap_script', 1);
-add_action('wp_head', 'itstudio_output_favicon', 1);
-add_action('admin_head', 'itstudio_output_favicon', 1);
-add_action('login_head', 'itstudio_output_favicon', 1);
-
-function itstudio_enqueue_scripts() {
- // 基础样式 (Style.css)
- wp_enqueue_style('itstudio-style', get_stylesheet_uri(), array(), '2.1.2');
-
- wp_enqueue_style('itstudio-header', get_template_directory_uri() . '/assets/css/header.css', array('itstudio-style'), '2.1.2');
- wp_enqueue_style('itstudio-footer', get_template_directory_uri() . '/assets/css/footer.css', array('itstudio-style'), '2.1.2');
- wp_enqueue_style('itstudio-content', get_template_directory_uri() . '/assets/css/content.css', array('itstudio-style'), '2.1.2');
-
- // 仅在首页加载首页样式
- if (is_front_page() || is_home()) {
- wp_enqueue_style('itstudio-front-page', get_template_directory_uri() . '/assets/css/front-page.css', array('itstudio-style'), '2.1.2');
- wp_enqueue_script('itstudio-landing-hero-canvas', get_template_directory_uri() . '/assets/js/landing-hero-canvas.js', array(), '1.0.0', true);
- }
-
- // 仅在工作室介绍页加载(包含 /about fallback)
- $is_about = is_page('about') || is_page_template('page-about.php');
- if (!$is_about && is_404()) {
- global $wp;
- $request = isset($wp->request) ? trim($wp->request, '/') : '';
- $is_about = ($request === 'about');
- }
-
- if ($is_about) {
- wp_enqueue_style('itstudio-about-hero', get_template_directory_uri() . '/assets/css/about-hero.css', array('itstudio-content'), '2.1.2');
- wp_enqueue_script('itstudio-animejs', get_template_directory_uri() . '/assets/js/vendor/anime.min.js', array(), '3.2.2', true);
- wp_enqueue_script('itstudio-about-hero-waves', get_template_directory_uri() . '/assets/js/hero-waves.js', array('itstudio-animejs'), '1.0.0', true);
- wp_enqueue_script('itstudio-about-hero', get_template_directory_uri() . '/assets/js/home-hero.js', array('itstudio-animejs'), '1.0.0', true);
- }
-
- // 仅在便民服务页加载(包含 /services fallback)
- $is_services = is_page('services') || is_page_template('page-services.php');
- if (!$is_services && is_404()) {
- global $wp;
- $request = isset($wp->request) ? trim($wp->request, '/') : '';
- $is_services = ($request === 'services');
- }
-
- if ($is_services) {
- wp_enqueue_style('itstudio-services-page', get_template_directory_uri() . '/assets/css/services-page.css', array('itstudio-content'), '1.0.0');
- }
-
- // Scripts
- wp_enqueue_script('itstudio-theme-toggle', get_template_directory_uri() . '/assets/js/theme-toggle.js', array(), '1.0.0', true);
- wp_enqueue_script('itstudio-lang-toggle', get_template_directory_uri() . '/assets/js/lang-toggle.js', array(), '1.0.0', true);
- wp_enqueue_script('itstudio-main', get_template_directory_uri() . '/assets/js/main.js', array(), '1.0.0', true);
-
- if (is_singular(array('post', 'announcement', 'news'))) {
- wp_enqueue_script('itstudio-single-title-fit', get_template_directory_uri() . '/assets/js/single-title-fit.js', array(), '1.0.0', true);
- }
-}
-add_action('wp_enqueue_scripts', 'itstudio_enqueue_scripts');
-
-function itstudio_expand_news_notice_date_precision($the_date, $format, $post) {
- $post_obj = $post instanceof WP_Post ? $post : get_post($post);
- if (!($post_obj instanceof WP_Post)) {
- return $the_date;
- }
-
- if (!in_array((string) $post_obj->post_type, array('announcement', 'news'), true)) {
- return $the_date;
- }
-
- $format = (string) $format;
- if ($format === '') {
- $format = (string) get_option('date_format');
- }
-
- $lower = strtolower($format);
- if (in_array($lower, array('c', 'r', 'u'), true)) {
- return $the_date;
- }
-
- // Already has time precision.
- if (preg_match('/[HhGgis]/', $format)) {
- return $the_date;
- }
-
- $timestamp = function_exists('get_post_timestamp')
- ? get_post_timestamp($post_obj, 'date')
- : false;
- if (!$timestamp) {
- return $the_date;
- }
-
- $format_with_time = rtrim($format) . ' H:i';
- return wp_date($format_with_time, (int) $timestamp, wp_timezone());
-}
-add_filter('get_the_date', 'itstudio_expand_news_notice_date_precision', 10, 3);
-
-function itstudio_register_sidebars() {
- register_sidebar(array(
- 'name' => __('Footer - Column 1', 'itstudio'),
- 'id' => 'footer-1',
- 'description' => __('Footer widget area 1', 'itstudio'),
- 'before_widget' => '',
- 'before_title' => '
',
- ));
-
- register_sidebar(array(
- 'name' => __('Footer - Column 2', 'itstudio'),
- 'id' => 'footer-2',
- 'description' => __('Footer widget area 2', 'itstudio'),
- 'before_widget' => '',
- 'before_title' => '
',
- ));
-}
-add_action('widgets_init', 'itstudio_register_sidebars');
-
-function itstudio_intro_body_class($classes) {
- $is_about = is_page('about') || is_page_template('page-about.php');
- if (!$is_about && is_404()) {
- global $wp;
- $request = isset($wp->request) ? trim($wp->request, '/') : '';
- $is_about = ($request === 'about');
- }
-
- if ($is_about) {
- $classes[] = 'intro-about';
- }
-
- return $classes;
-}
-add_filter('body_class', 'itstudio_intro_body_class');
-
-function itstudio_custom_post_types() {
- register_post_type('announcement', array(
- 'labels' => array(
- 'name' => __('公告', 'itstudio'),
- 'singular_name' => __('公告', 'itstudio'),
- ),
- 'public' => true,
- 'has_archive' => true,
- 'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
- 'taxonomies' => array('post_tag'),
- 'menu_icon' => 'dashicons-megaphone',
- 'show_in_rest' => true,
- ));
-
- register_post_type('news', array(
- 'labels' => array(
- 'name' => __('新闻', 'itstudio'),
- 'singular_name' => __('新闻', 'itstudio'),
- ),
- 'public' => true,
- 'has_archive' => 'news',
- 'rewrite' => array(
- 'slug' => 'news',
- 'with_front' => false,
- ),
- 'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
- 'taxonomies' => array('post_tag'),
- 'menu_icon' => 'dashicons-media-document',
- 'show_in_rest' => true,
- ));
-
- register_taxonomy('service_category', array('service'), array(
- 'labels' => array(
- 'name' => __('服务分类', 'itstudio'),
- 'singular_name' => __('服务分类', 'itstudio'),
- ),
- 'hierarchical' => true,
- 'public' => true,
- 'show_ui' => true,
- 'show_admin_column' => false,
- 'show_in_rest' => true,
- 'rewrite' => array(
- 'slug' => 'service-category',
- 'with_front' => false,
- ),
- ));
-
- register_post_type('service', array(
- 'labels' => array(
- 'name' => __('便民服务', 'itstudio'),
- 'singular_name' => __('便民服务', 'itstudio'),
- 'menu_name' => __('便民服务', 'itstudio'),
- 'add_new_item' => __('新增便民服务', 'itstudio'),
- 'edit_item' => __('编辑便民服务', 'itstudio'),
- ),
- 'public' => true,
- 'show_ui' => true,
- 'show_in_menu' => true,
- 'show_in_nav_menus' => false,
- 'exclude_from_search' => true,
- 'publicly_queryable' => true,
- 'has_archive' => false,
- 'rewrite' => array(
- 'slug' => 'service',
- 'with_front' => false,
- ),
- 'supports' => array('title', 'excerpt', 'thumbnail', 'page-attributes'),
- 'taxonomies' => array('service_category'),
- 'menu_icon' => 'dashicons-admin-tools',
- 'show_in_rest' => true,
- ));
-
- register_taxonomy_for_object_type('post_tag', 'announcement');
- register_taxonomy_for_object_type('post_tag', 'news');
-}
-add_action('init', 'itstudio_custom_post_types');
-
-function itstudio_register_acf_fields() {
- if (!function_exists('acf_add_local_field_group')) {
- return;
- }
-
- acf_add_local_field_group(array(
- 'key' => 'group_itstudio_content_priority',
- 'title' => '内容权重',
- 'fields' => array(
- array(
- 'key' => 'field_itstudio_weight',
- 'label' => '权重',
- 'name' => 'itstudio_weight',
- 'type' => 'number',
- 'instructions' => '数值越大,文章在侧栏排序越靠前。',
- 'required' => 0,
- 'default_value' => 0,
- 'min' => 0,
- 'step' => 1,
- ),
- ),
- 'location' => array(
- array(
- array(
- 'param' => 'post_type',
- 'operator' => '==',
- 'value' => 'post',
- ),
- ),
- array(
- array(
- 'param' => 'post_type',
- 'operator' => '==',
- 'value' => 'announcement',
- ),
- ),
- array(
- array(
- 'param' => 'post_type',
- 'operator' => '==',
- 'value' => 'news',
- ),
- ),
- ),
- 'position' => 'side',
- 'style' => 'default',
- 'active' => true,
- 'show_in_rest' => 1,
- ));
-
- acf_add_local_field_group(array(
- 'key' => 'group_itstudio_recruitment_article',
- 'title' => '招新文章标记',
- 'fields' => array(
- array(
- 'key' => 'field_itstudio_is_recruitment_article',
- 'label' => '是否为招新文章',
- 'name' => 'itstudio_is_recruitment_article',
- 'type' => 'true_false',
- 'instructions' => '勾选后,该文章会在“加入我们”页面顶部新闻条中显示(按发布时间排序)。',
- 'required' => 0,
- 'default_value' => 0,
- 'ui' => 1,
- 'ui_on_text' => '是',
- 'ui_off_text' => '否',
- ),
- ),
- 'location' => array(
- array(
- array(
- 'param' => 'post_type',
- 'operator' => '==',
- 'value' => 'announcement',
- ),
- ),
- array(
- array(
- 'param' => 'post_type',
- 'operator' => '==',
- 'value' => 'news',
- ),
- ),
- array(
- array(
- 'param' => 'post_type',
- 'operator' => '==',
- 'value' => 'post',
- ),
- ),
- ),
- 'position' => 'side',
- 'style' => 'default',
- 'active' => true,
- 'show_in_rest' => 1,
- ));
-}
-add_action('acf/init', 'itstudio_register_acf_fields');
-
-function itstudio_get_recruitment_article_meta_key() {
- return 'itstudio_is_recruitment_article';
-}
-
-function itstudio_normalize_recruitment_flag($value) {
- if (is_bool($value)) {
- return $value;
- }
-
- if (is_numeric($value)) {
- return ((int) $value) > 0;
- }
-
- $value = strtolower(trim((string) $value));
- return in_array($value, array('1', 'true', 'yes', 'on', 'y'), true);
-}
-
-function itstudio_is_recruitment_article($post_id) {
- $post_id = (int) $post_id;
- if ($post_id <= 0) {
- return false;
- }
-
- $meta_key = itstudio_get_recruitment_article_meta_key();
- $meta_keys = array(
- $meta_key,
- '_itstudio_is_recruitment_article',
- 'itstudio_join_article',
- 'join_recruitment_article',
- 'is_recruitment_article',
- );
-
- foreach ($meta_keys as $key) {
- $raw = get_post_meta($post_id, $key, true);
- if ($raw !== '' && $raw !== null && itstudio_normalize_recruitment_flag($raw)) {
- return true;
- }
- }
-
- if (function_exists('get_field')) {
- $acf_keys = array(
- 'itstudio_is_recruitment_article',
- 'is_recruitment_article',
- 'itstudio_join_article',
- );
- foreach ($acf_keys as $acf_key) {
- $raw = get_field($acf_key, $post_id, false);
- if ($raw !== '' && $raw !== null && itstudio_normalize_recruitment_flag($raw)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-function itstudio_add_recruitment_meta_boxes() {
- $screens = array('announcement', 'news', 'post');
- foreach ($screens as $screen) {
- add_meta_box(
- 'itstudio_recruitment_flag',
- __('招新文章', 'itstudio'),
- 'itstudio_render_recruitment_meta_box',
- $screen,
- 'side',
- 'high'
- );
- }
-}
-add_action('add_meta_boxes', 'itstudio_add_recruitment_meta_boxes');
-
-function itstudio_render_recruitment_meta_box($post) {
- $meta_key = itstudio_get_recruitment_article_meta_key();
- $checked = itstudio_is_recruitment_article((int) $post->ID);
- wp_nonce_field('itstudio_save_recruitment_meta', 'itstudio_recruitment_meta_nonce');
- ?>
-
-
-
-
-
-
-
- format('Y');
- $display_year = isset($join_runtime['recruitment_year']) && is_numeric($join_runtime['recruitment_year'])
- ? (int) $join_runtime['recruitment_year']
- : $now_year;
-
- $season_start_ts = null;
- $season_end_ts = null;
- $stages = isset($join_runtime['stages']) && is_array($join_runtime['stages']) ? $join_runtime['stages'] : array();
- foreach ($stages as $stage) {
- if (!is_array($stage)) {
- continue;
- }
- $start_ts = isset($stage['start_ts']) && is_numeric($stage['start_ts']) ? (int) $stage['start_ts'] : null;
- $end_ts = isset($stage['end_ts']) && is_numeric($stage['end_ts']) ? (int) $stage['end_ts'] : null;
- if ($start_ts !== null && ($season_start_ts === null || $start_ts < $season_start_ts)) {
- $season_start_ts = $start_ts;
- }
- if ($end_ts !== null && ($season_end_ts === null || $end_ts > $season_end_ts)) {
- $season_end_ts = $end_ts;
- }
- }
-
- $now_ts = (int) (isset($join_runtime['now_ts']) && is_numeric($join_runtime['now_ts']) ? $join_runtime['now_ts'] : ((int) $now->format('U') * 1000));
- if ($season_start_ts !== null && $now_ts < $season_start_ts && $display_year > $now_year) {
- // 下年招新未开始:继续展示本年招新资讯
- $display_year = $now_year;
- }
-
- $query = new WP_Query(array(
- 'post_type' => array('announcement', 'news', 'post'),
- 'post_status' => 'publish',
- 'posts_per_page' => 80,
- 'orderby' => 'date',
- 'order' => 'DESC',
- 'no_found_rows' => true,
- 'ignore_sticky_posts' => true,
- 'date_query' => array(
- array(
- 'year' => $display_year,
- ),
- ),
- ));
-
- $items = array();
- if ($query->have_posts()) {
- foreach ($query->posts as $post) {
- if (count($items) >= $limit) {
- break;
- }
-
- $post_id = (int) $post->ID;
- if (!itstudio_is_recruitment_article($post_id)) {
- continue;
- }
-
- $title = trim((string) get_the_title($post_id));
- $url = (string) get_permalink($post_id);
- if ($title === '' || $url === '') {
- continue;
- }
-
- $excerpt = function_exists('itstudio_get_post_excerpt_chars')
- ? itstudio_get_post_excerpt_chars($post_id, 72)
- : wp_html_excerpt(trim(wp_strip_all_tags((string) get_post_field('post_excerpt', $post_id))), 72, '...');
-
- if ($excerpt === '') {
- $excerpt = '...';
- }
-
- $author_id = (int) get_post_field('post_author', $post_id);
- $author = trim((string) get_the_author_meta('display_name', $author_id));
- if ($author === '') {
- $author = 'Unknown';
- }
-
- $items[] = array(
- 'id' => $post_id,
- 'title' => $title,
- 'excerpt' => $excerpt,
- 'url' => $url,
- 'date' => get_the_date('Y-m-d H:i', $post_id),
- 'date_iso' => get_the_date('c', $post_id),
- 'author' => $author,
- 'type' => get_post_type($post_id),
- );
- }
- }
- wp_reset_postdata();
-
- return array(
- 'display_year' => $display_year,
- 'items' => $items,
- );
-}
-
-function itstudio_get_service_url_meta_key() {
- return '_itstudio_service_url';
-}
-
-function itstudio_get_service_title_cn_meta_key() {
- return '_itstudio_service_title_cn';
-}
-
-function itstudio_get_service_title_en_meta_key() {
- return '_itstudio_service_title_en';
-}
-
-function itstudio_get_service_excerpt_cn_meta_key() {
- return '_itstudio_service_excerpt_cn';
-}
-
-function itstudio_get_service_excerpt_en_meta_key() {
- return '_itstudio_service_excerpt_en';
-}
-
-function itstudio_get_service_campus_only_meta_key() {
- return '_itstudio_service_campus_only';
-}
-
-function itstudio_get_service_category_name_cn_meta_key() {
- return 'itstudio_service_category_name_cn';
-}
-
-function itstudio_get_service_category_name_en_meta_key() {
- return 'itstudio_service_category_name_en';
-}
-
-function itstudio_get_service_category_i18n_labels($term) {
- if (!$term || is_wp_error($term)) {
- return array(
- 'cn' => '未分类',
- 'en' => 'Uncategorized',
- );
- }
-
- $term_id = (int) $term->term_id;
- $name_cn = trim((string) get_term_meta($term_id, itstudio_get_service_category_name_cn_meta_key(), true));
- $name_en = trim((string) get_term_meta($term_id, itstudio_get_service_category_name_en_meta_key(), true));
-
- if ($name_cn === '') {
- $name_cn = (string) $term->name;
- }
- if ($name_en === '') {
- $name_en = $name_cn;
- }
-
- return array(
- 'cn' => $name_cn,
- 'en' => $name_en,
- );
-}
-
-function itstudio_get_service_i18n_content($service_id, $excerpt_limit = 90) {
- $service_id = (int) $service_id;
- if ($service_id <= 0) {
- return array(
- 'title_cn' => '',
- 'title_en' => '',
- 'excerpt_cn' => '',
- 'excerpt_en' => '',
- );
- }
-
- $title_cn = trim((string) get_post_meta($service_id, itstudio_get_service_title_cn_meta_key(), true));
- $title_en = trim((string) get_post_meta($service_id, itstudio_get_service_title_en_meta_key(), true));
- $excerpt_cn = trim((string) get_post_meta($service_id, itstudio_get_service_excerpt_cn_meta_key(), true));
- $excerpt_en = trim((string) get_post_meta($service_id, itstudio_get_service_excerpt_en_meta_key(), true));
-
- $fallback_title = trim((string) get_the_title($service_id));
- if ($fallback_title === '') {
- $fallback_title = '未命名服务';
- }
-
- $fallback_excerpt = function_exists('itstudio_get_post_excerpt_chars')
- ? itstudio_get_post_excerpt_chars($service_id, $excerpt_limit)
- : wp_html_excerpt(wp_strip_all_tags((string) get_post_field('post_excerpt', $service_id)), $excerpt_limit, '...');
- $fallback_excerpt = trim((string) $fallback_excerpt);
- if ($fallback_excerpt === '') {
- $fallback_excerpt = '暂无简介';
- }
-
- if ($title_cn === '') {
- $title_cn = $fallback_title;
- }
- if ($title_en === '') {
- $title_en = $title_cn;
- }
- if ($excerpt_cn === '') {
- $excerpt_cn = $fallback_excerpt;
- }
- if ($excerpt_en === '') {
- $excerpt_en = $excerpt_cn;
- }
-
- return array(
- 'title_cn' => $title_cn,
- 'title_en' => $title_en,
- 'excerpt_cn' => $excerpt_cn,
- 'excerpt_en' => $excerpt_en,
- );
-}
-
-function itstudio_add_service_meta_boxes() {
- add_meta_box(
- 'itstudio_service_link',
- __('服务双语与链接', 'itstudio'),
- 'itstudio_render_service_link_meta_box',
- 'service',
- 'normal',
- 'high'
- );
-}
-add_action('add_meta_boxes', 'itstudio_add_service_meta_boxes');
-
-function itstudio_render_service_link_meta_box($post) {
- $service_url = (string) get_post_meta($post->ID, itstudio_get_service_url_meta_key(), true);
- $title_cn = (string) get_post_meta($post->ID, itstudio_get_service_title_cn_meta_key(), true);
- $title_en = (string) get_post_meta($post->ID, itstudio_get_service_title_en_meta_key(), true);
- $excerpt_cn = (string) get_post_meta($post->ID, itstudio_get_service_excerpt_cn_meta_key(), true);
- $excerpt_en = (string) get_post_meta($post->ID, itstudio_get_service_excerpt_en_meta_key(), true);
- $is_campus_only = itstudio_is_service_campus_only($post->ID);
- wp_nonce_field('itstudio_save_service_meta', 'itstudio_service_meta_nonce');
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- trim($title_cn),
- itstudio_get_service_title_en_meta_key() => trim($title_en),
- itstudio_get_service_excerpt_cn_meta_key() => trim($excerpt_cn),
- itstudio_get_service_excerpt_en_meta_key() => trim($excerpt_en),
- );
-
- foreach ($meta_updates as $meta_key => $value) {
- if ($value === '') {
- delete_post_meta($post_id, $meta_key);
- } else {
- update_post_meta($post_id, $meta_key, $value);
- }
- }
-
- $campus_only_meta_key = itstudio_get_service_campus_only_meta_key();
- $is_campus_only = isset($_POST['itstudio_service_campus_only']) && (string) wp_unslash($_POST['itstudio_service_campus_only']) === '1';
- if ($is_campus_only) {
- update_post_meta($post_id, $campus_only_meta_key, '1');
- } else {
- delete_post_meta($post_id, $campus_only_meta_key);
- }
-
- $url_meta_key = itstudio_get_service_url_meta_key();
- $raw_url = isset($_POST['itstudio_service_url']) ? trim((string) wp_unslash($_POST['itstudio_service_url'])) : '';
-
- if ($raw_url === '') {
- delete_post_meta($post_id, $url_meta_key);
- return;
- }
-
- if (strpos($raw_url, '/') === 0) {
- $raw_url = home_url($raw_url);
- }
-
- $service_url = esc_url_raw($raw_url);
- if ($service_url === '') {
- delete_post_meta($post_id, $url_meta_key);
- return;
- }
-
- update_post_meta($post_id, $url_meta_key, $service_url);
-}
-add_action('save_post_service', 'itstudio_save_service_meta');
-
-function itstudio_service_category_add_fields($taxonomy) {
- wp_nonce_field('itstudio_save_service_category_meta', 'itstudio_service_category_meta_nonce');
- ?>
-
-
-
-
-
-
-
-
- term_id;
- $name_cn = (string) get_term_meta($term_id, itstudio_get_service_category_name_cn_meta_key(), true);
- $name_en = (string) get_term_meta($term_id, itstudio_get_service_category_name_en_meta_key(), true);
- wp_nonce_field('itstudio_save_service_category_meta', 'itstudio_service_category_meta_nonce');
- ?>
-
- |
- |
-
-
- |
- |
-
- trim($name_cn),
- itstudio_get_service_category_name_en_meta_key() => trim($name_en),
- );
-
- foreach ($term_meta as $meta_key => $value) {
- if ($value === '') {
- delete_term_meta($term_id, $meta_key);
- } else {
- update_term_meta($term_id, $meta_key, $value);
- }
- }
-}
-add_action('created_service_category', 'itstudio_save_service_category_meta');
-add_action('edited_service_category', 'itstudio_save_service_category_meta');
-
-function itstudio_get_service_target_url($service_id) {
- $service_id = (int) $service_id;
- if ($service_id <= 0) {
- return '';
- }
-
- $meta_key = itstudio_get_service_url_meta_key();
- $url = (string) get_post_meta($service_id, $meta_key, true);
- if ($url !== '') {
- return $url;
- }
-
- return (string) get_permalink($service_id);
-}
-
-function itstudio_is_service_campus_only($service_id) {
- $service_id = (int) $service_id;
- if ($service_id <= 0) {
- return false;
- }
-
- return (string) get_post_meta($service_id, itstudio_get_service_campus_only_meta_key(), true) === '1';
-}
-
-function itstudio_service_admin_columns($columns) {
- $columns['service_category'] = __('分类', 'itstudio');
- $columns['service_url'] = __('跳转链接', 'itstudio');
- return $columns;
-}
-add_filter('manage_service_posts_columns', 'itstudio_service_admin_columns');
-
-function itstudio_service_admin_custom_column($column, $post_id) {
- if ($column === 'service_category') {
- $terms = get_the_terms($post_id, 'service_category');
- if (empty($terms) || is_wp_error($terms)) {
- echo '
' . esc_html__('未分类', 'itstudio') . '';
- return;
- }
-
- $labels = array();
- foreach ($terms as $term) {
- $i18n = itstudio_get_service_category_i18n_labels($term);
- $label = $i18n['cn'];
- if ($i18n['en'] !== $i18n['cn']) {
- $label .= ' / ' . $i18n['en'];
- }
- $labels[] = $label;
- }
-
- echo esc_html(implode(' | ', $labels));
- return;
- }
-
- if ($column === 'service_url') {
- $url = itstudio_get_service_target_url($post_id);
- if ($url === '') {
- echo '
-';
- return;
- }
-
- echo '
' . esc_html($url) . '';
- }
-}
-add_action('manage_service_posts_custom_column', 'itstudio_service_admin_custom_column', 10, 2);
-
-function itstudio_archive_document_title($parts) {
- if (is_post_type_archive('announcement')) {
- $parts['title'] = '公告通知';
- } elseif (is_post_type_archive('news')) {
- $parts['title'] = '社团新闻';
- }
-
- return $parts;
-}
-add_filter('document_title_parts', 'itstudio_archive_document_title', 20);
-
-// Fallback: render /about even if the page isn't created in WP admin.
-function itstudio_about_fallback() {
- if (!is_404()) {
- return;
- }
-
- global $wp;
- $request = isset($wp->request) ? trim($wp->request, '/') : '';
- if ($request !== 'about') {
- return;
- }
-
- $template = locate_template('page-about.php');
- if ($template) {
- global $wp_query;
- if ($wp_query) {
- $wp_query->is_404 = false;
- $wp_query->is_page = true;
- $wp_query->is_singular = true;
- $virtual_post = new WP_Post((object) array(
- 'ID' => 0,
- 'post_type' => 'page',
- 'post_parent' => 0,
- 'post_title' => __('工作室介绍', 'itstudio'),
- 'post_status' => 'publish',
- 'post_name' => 'about',
- 'post_content' => '',
- ));
- $wp_query->post = $virtual_post;
- $wp_query->posts = array($virtual_post);
- $wp_query->queried_object = $virtual_post;
- $wp_query->queried_object_id = 0;
- $wp_query->post_count = 1;
- $wp_query->found_posts = 1;
- $wp_query->max_num_pages = 1;
- global $post;
- $post = $virtual_post;
- setup_postdata($post);
- }
- add_filter('document_title_parts', function ($parts) {
- $parts['title'] = __('工作室介绍', 'itstudio');
- return $parts;
- });
- status_header(200);
- nocache_headers();
- include $template;
- exit;
- }
-}
-add_action('template_redirect', 'itstudio_about_fallback');
-
-// Fallback: render /news via archive.php even if the page isn't created in WP admin.
-function itstudio_news_fallback() {
- if (!is_404()) {
- return;
- }
-
- global $wp;
- $request = isset($wp->request) ? trim($wp->request, '/') : '';
- if ($request !== 'news') {
- return;
- }
-
- $template = locate_template('archive.php');
- if ($template) {
- global $wp_query;
- if ($wp_query) {
- $wp_query->is_404 = false;
- $wp_query->is_page = true;
- $wp_query->is_singular = true;
- $virtual_post = new WP_Post((object) array(
- 'ID' => 0,
- 'post_type' => 'page',
- 'post_parent' => 0,
- 'post_title' => __('社团新闻', 'itstudio'),
- 'post_status' => 'publish',
- 'post_name' => 'news',
- 'post_content' => '',
- ));
- $wp_query->post = $virtual_post;
- $wp_query->posts = array($virtual_post);
- $wp_query->queried_object = $virtual_post;
- $wp_query->queried_object_id = 0;
- $wp_query->post_count = 1;
- $wp_query->found_posts = 1;
- $wp_query->max_num_pages = 1;
- global $post;
- $post = $virtual_post;
- setup_postdata($post);
- }
- add_filter('document_title_parts', function ($parts) {
- $parts['title'] = __('社团新闻', 'itstudio');
- return $parts;
- });
- $GLOBALS['itstudio_archive_mode'] = 'news';
- status_header(200);
- nocache_headers();
- include $template;
- unset($GLOBALS['itstudio_archive_mode']);
- exit;
- }
-}
-add_action('template_redirect', 'itstudio_news_fallback');
-
-// Fallback: render /services even if the page isn't created in WP admin.
-function itstudio_services_fallback() {
- if (!is_404()) {
- return;
- }
-
- global $wp;
- $request = isset($wp->request) ? trim($wp->request, '/') : '';
- if ($request !== 'services') {
- return;
- }
-
- $template = locate_template('page-services.php');
- if ($template) {
- global $wp_query;
- if ($wp_query) {
- $wp_query->is_404 = false;
- $wp_query->is_page = true;
- $wp_query->is_singular = true;
- $virtual_post = new WP_Post((object) array(
- 'ID' => 0,
- 'post_type' => 'page',
- 'post_parent' => 0,
- 'post_title' => __('便民服务', 'itstudio'),
- 'post_status' => 'publish',
- 'post_name' => 'services',
- 'post_content' => '',
- ));
- $wp_query->post = $virtual_post;
- $wp_query->posts = array($virtual_post);
- $wp_query->queried_object = $virtual_post;
- $wp_query->queried_object_id = 0;
- $wp_query->post_count = 1;
- $wp_query->found_posts = 1;
- $wp_query->max_num_pages = 1;
- global $post;
- $post = $virtual_post;
- setup_postdata($post);
- }
- add_filter('document_title_parts', function ($parts) {
- $parts['title'] = __('便民服务', 'itstudio');
- return $parts;
- });
- status_header(200);
- nocache_headers();
- include $template;
- exit;
- }
-}
-add_action('template_redirect', 'itstudio_services_fallback');
-
-function itstudio_get_post_views($post_id) {
- $post_id = (int) $post_id;
- if ($post_id <= 0) {
- return 0;
- }
-
- $meta_keys = array(
- 'post_views_count',
- 'itstudio_views',
- 'views',
- 'post_views',
- 'view_count',
- 'views_count',
- );
-
- $max_views = 0;
- foreach ($meta_keys as $meta_key) {
- $raw = get_post_meta($post_id, $meta_key, true);
- if ($raw !== '' && is_numeric($raw)) {
- $max_views = max($max_views, (int) $raw);
- }
- }
-
- return max(0, $max_views);
-}
-
-function itstudio_get_post_weight($post_id, $field_name = 'itstudio_weight') {
- $post_id = (int) $post_id;
- if ($post_id <= 0) {
- return 0;
- }
-
- if (!function_exists('get_field')) {
- return 0;
- }
-
- $raw = get_field($field_name, $post_id, false);
- if ($raw === '' || $raw === null || !is_numeric($raw)) {
- return 0;
- }
-
- return (int) $raw;
-}
-
-function itstudio_get_post_char_count($post_id) {
- $post_id = (int) $post_id;
- if ($post_id <= 0) {
- return 0;
- }
-
- $content = (string) get_post_field('post_content', $post_id);
- $plain_text = trim(wp_strip_all_tags($content));
- if ($plain_text === '') {
- return 0;
- }
-
- if (function_exists('mb_strlen')) {
- return (int) mb_strlen($plain_text, 'UTF-8');
- }
-
- return (int) strlen($plain_text);
-}
-
-function itstudio_get_post_excerpt_chars($post_id, $limit = 200) {
- $post_id = (int) $post_id;
- $limit = max(1, (int) $limit);
- if ($post_id <= 0) {
- return '';
- }
-
- $excerpt = (string) get_post_field('post_excerpt', $post_id);
- if (trim($excerpt) === '') {
- $excerpt = (string) get_post_field('post_content', $post_id);
- }
-
- $excerpt = trim(wp_strip_all_tags($excerpt));
- if ($excerpt === '') {
- return '';
- }
-
- return wp_html_excerpt($excerpt, $limit, '...');
-}
-
-function itstudio_get_archive_url_by_post_type($post_type) {
- $post_type = sanitize_key((string) $post_type);
- if ($post_type === '') {
- return home_url('/');
- }
-
- $archive_url = get_post_type_archive_link($post_type);
- if ($archive_url) {
- return $archive_url;
- }
-
- if ($post_type === 'news') {
- return home_url('/news/');
- }
-
- if ($post_type === 'announcement') {
- return home_url('/announcement/');
- }
-
- return home_url('/');
-}
-
-function itstudio_get_archive_tag_filter_url($term, $post_type) {
- $term_obj = null;
- if ($term instanceof WP_Term) {
- $term_obj = $term;
- } else {
- $term_obj = get_term($term, 'post_tag');
- }
-
- if (!($term_obj instanceof WP_Term) || is_wp_error($term_obj)) {
- return '';
- }
-
- $post_type = sanitize_key((string) $post_type);
- if (!in_array($post_type, array('news', 'announcement'), true)) {
- return '';
- }
-
- $archive_url = itstudio_get_archive_url_by_post_type($post_type);
- return add_query_arg(
- array(
- 'tag' => $term_obj->slug,
- ),
- $archive_url
- );
-}
-
-function itstudio_archive_extended_search_enabled($query) {
- if (!($query instanceof WP_Query)) {
- return false;
- }
-
- if (!$query->get('itstudio_archive_extend_search')) {
- return false;
- }
-
- $keyword = trim((string) $query->get('itstudio_archive_keyword'));
- return $keyword !== '';
-}
-
-function itstudio_archive_extended_search_join($join, $query) {
- if (!itstudio_archive_extended_search_enabled($query)) {
- return $join;
- }
-
- global $wpdb;
- if (strpos($join, $wpdb->users) !== false) {
- return $join;
- }
-
- return $join . " LEFT JOIN {$wpdb->users} ON ({$wpdb->posts}.post_author = {$wpdb->users}.ID) ";
-}
-add_filter('posts_join', 'itstudio_archive_extended_search_join', 10, 2);
-
-function itstudio_archive_extended_search_where($where, $query) {
- if (!itstudio_archive_extended_search_enabled($query)) {
- return $where;
- }
-
- global $wpdb;
- $keyword = trim((string) $query->get('itstudio_archive_keyword'));
- $like = '%' . $wpdb->esc_like($keyword) . '%';
-
- $search_sql = $wpdb->prepare(
- " AND (
- {$wpdb->posts}.post_title LIKE %s
- OR {$wpdb->posts}.post_excerpt LIKE %s
- OR {$wpdb->posts}.post_content LIKE %s
- OR {$wpdb->users}.display_name LIKE %s
- OR {$wpdb->users}.user_login LIKE %s
- OR {$wpdb->users}.user_nicename LIKE %s
- )",
- $like,
- $like,
- $like,
- $like,
- $like,
- $like
- );
-
- return $where . $search_sql;
-}
-add_filter('posts_where', 'itstudio_archive_extended_search_where', 10, 2);
-
-function itstudio_is_probably_bot_request() {
- $user_agent = strtolower(trim((string) ($_SERVER['HTTP_USER_AGENT'] ?? '')));
- if ($user_agent === '') {
- return true;
- }
-
- $bot_signatures = array(
- 'bot',
- 'spider',
- 'crawl',
- 'slurp',
- 'headless',
- 'preview',
- 'facebookexternalhit',
- 'discordbot',
- 'telegrambot',
- 'linkedinbot',
- 'applebot',
- 'googlebot',
- 'bingbot',
- 'wget',
- 'curl',
- 'python-requests',
- 'postmanruntime',
- );
-
- foreach ($bot_signatures as $signature) {
- if (strpos($user_agent, $signature) !== false) {
- return true;
- }
- }
-
- $purpose = strtolower((string) ($_SERVER['HTTP_PURPOSE'] ?? ''));
- $sec_purpose = strtolower((string) ($_SERVER['HTTP_SEC_PURPOSE'] ?? ''));
- $x_moz = strtolower((string) ($_SERVER['HTTP_X_MOZ'] ?? ''));
- if (strpos($purpose, 'prefetch') !== false || strpos($sec_purpose, 'prefetch') !== false || $x_moz === 'prefetch') {
- return true;
- }
-
- return false;
-}
-
-function itstudio_get_view_cookie_name() {
- return 'itstudio_viewed_posts';
-}
-
-function itstudio_read_view_cookie_map() {
- $cookie_name = itstudio_get_view_cookie_name();
- $raw_cookie = isset($_COOKIE[$cookie_name]) ? wp_unslash((string) $_COOKIE[$cookie_name]) : '';
- if ($raw_cookie === '') {
- return array();
- }
-
- $decoded = json_decode($raw_cookie, true);
- if (!is_array($decoded)) {
- return array();
- }
-
- $clean = array();
- foreach ($decoded as $post_id => $timestamp) {
- $post_id = (int) $post_id;
- $timestamp = (int) $timestamp;
- if ($post_id > 0 && $timestamp > 0) {
- $clean[(string) $post_id] = $timestamp;
- }
- }
-
- return $clean;
-}
-
-function itstudio_write_view_cookie_map($map, $window_seconds) {
- if (!headers_sent()) {
- $cookie_name = itstudio_get_view_cookie_name();
- $expire_at = time() + max(DAY_IN_SECONDS, (int) $window_seconds * 2);
- $path = defined('COOKIEPATH') && COOKIEPATH ? COOKIEPATH : '/';
- $domain = defined('COOKIE_DOMAIN') ? COOKIE_DOMAIN : '';
- $secure = is_ssl();
- $http_only = true;
- $encoded = wp_json_encode($map);
- if (!is_string($encoded)) {
- return;
- }
-
- if (PHP_VERSION_ID >= 70300) {
- setcookie($cookie_name, $encoded, array(
- 'expires' => $expire_at,
- 'path' => $path,
- 'domain' => $domain,
- 'secure' => $secure,
- 'httponly' => $http_only,
- 'samesite' => 'Lax',
- ));
- } else {
- setcookie($cookie_name, $encoded, $expire_at, $path, $domain, $secure, $http_only);
- }
-
- $_COOKIE[$cookie_name] = $encoded;
- }
-}
-
-function itstudio_should_count_post_view($post_id) {
- $post_id = (int) $post_id;
- if ($post_id <= 0) {
- return false;
- }
-
- if (itstudio_is_probably_bot_request()) {
- return false;
- }
-
- $window_seconds = (int) apply_filters('itstudio_post_view_window_seconds', 12 * HOUR_IN_SECONDS);
- $window_seconds = max(60, $window_seconds);
- $max_entries = (int) apply_filters('itstudio_post_view_cookie_max_entries', 120);
- $max_entries = max(10, $max_entries);
-
- $now = time();
- $key = (string) $post_id;
- $map = itstudio_read_view_cookie_map();
-
- foreach ($map as $id => $timestamp) {
- if (($now - (int) $timestamp) > $window_seconds) {
- unset($map[$id]);
- }
- }
-
- if (isset($map[$key]) && ($now - (int) $map[$key]) < $window_seconds) {
- return false;
- }
-
- $map[$key] = $now;
- if (count($map) > $max_entries) {
- asort($map, SORT_NUMERIC);
- $map = array_slice($map, -$max_entries, null, true);
- }
-
- itstudio_write_view_cookie_map($map, $window_seconds);
-
- return true;
-}
-
-function itstudio_track_post_views() {
- if (is_admin() || wp_doing_ajax() || wp_doing_cron()) {
- return;
- }
-
- if (!is_singular(array('post', 'announcement', 'news')) || is_preview() || is_feed() || is_trackback() || is_embed()) {
- return;
- }
-
- if (!isset($_SERVER['REQUEST_METHOD']) || strtoupper((string) $_SERVER['REQUEST_METHOD']) !== 'GET') {
- return;
- }
-
- $post_id = (int) get_queried_object_id();
- if ($post_id <= 0) {
- return;
- }
-
- if (!itstudio_should_count_post_view($post_id)) {
- return;
- }
-
- $views = itstudio_get_post_views($post_id) + 1;
- update_post_meta($post_id, 'post_views_count', $views);
- update_post_meta($post_id, 'itstudio_views', $views);
-}
-add_action('template_redirect', 'itstudio_track_post_views', 20);
function itstudio_is_join_page_context() {
$is_join = is_page('join') || is_page_template('page-join.php');
@@ -1737,8 +188,19 @@ function itstudio_join_sanitize_settings($input) {
return array_merge($defaults, $sanitized);
}
-function itstudio_join_get_settings() {
+function itstudio_join_get_settings($term_id = null) {
$defaults = itstudio_join_get_default_settings();
+
+ // 学期感知:无参时取当前生效学期;有参时取指定学期。
+ if (function_exists('itstudio_join_get_terms')) {
+ $target_id = $term_id !== null ? (string) $term_id : itstudio_join_get_active_term_id();
+ $terms = itstudio_join_get_terms();
+ if ($target_id !== '' && isset($terms[$target_id]) && is_array($terms[$target_id]['settings'] ?? null)) {
+ return array_merge($defaults, itstudio_join_sanitize_settings($terms[$target_id]['settings']));
+ }
+ }
+
+ // 兜底:迁移尚未发生时读旧的单一选项。
$stored = get_option('itstudio_join_settings', array());
if (!is_array($stored)) {
return $defaults;
@@ -3482,6 +1944,120 @@ function itstudio_join_register_settings_page() {
}
add_action('admin_menu', 'itstudio_join_register_settings_page');
+/**
+ * 统一跳回招新设置页并带上提示参数。
+ */
+function itstudio_join_settings_redirect($args) {
+ $args = array_merge(array('page' => 'itstudio-join-settings'), $args);
+ wp_safe_redirect(add_query_arg($args, admin_url('options-general.php')));
+ exit;
+}
+
+/**
+ * 错误码转中文提示(供跳转后展示)。
+ */
+function itstudio_join_settings_error_message($code) {
+ $map = array(
+ 'delete_active' => '无法删除“当前生效”学期,请先把其它学期设为生效。',
+ 'delete_last' => '至少要保留一个学期。',
+ 'delete_failed' => '删除失败,学期不存在。',
+ 'save_failed' => '保存失败,学期不存在。',
+ 'need_year' => '请填写学年或自定义名称。',
+ );
+ return isset($map[$code]) ? $map[$code] : '操作失败。';
+}
+
+/**
+ * 保存某学期的配置(含学期元信息)。
+ */
+function itstudio_join_handle_save_term_settings() {
+ if (!current_user_can('manage_options')) {
+ wp_die('权限不足');
+ }
+ check_admin_referer('itstudio_join_save_term_settings');
+
+ $term_id = isset($_POST['itstudio_join_term_id']) ? sanitize_text_field(wp_unslash($_POST['itstudio_join_term_id'])) : '';
+ $raw = (isset($_POST['itstudio_join_settings']) && is_array($_POST['itstudio_join_settings'])) ? wp_unslash($_POST['itstudio_join_settings']) : array();
+ $meta = (isset($_POST['itstudio_join_term_meta']) && is_array($_POST['itstudio_join_term_meta'])) ? wp_unslash($_POST['itstudio_join_term_meta']) : array();
+
+ if (!empty($meta)) {
+ itstudio_join_update_term_meta(
+ $term_id,
+ isset($meta['academic_year']) ? $meta['academic_year'] : '',
+ isset($meta['season']) ? $meta['season'] : 'fall',
+ isset($meta['label']) ? $meta['label'] : ''
+ );
+ }
+
+ if (!itstudio_join_save_term_settings($term_id, $raw)) {
+ itstudio_join_settings_redirect(array('term' => $term_id, 'error' => 'save_failed'));
+ }
+
+ itstudio_join_settings_redirect(array('term' => $term_id, 'updated' => '1'));
+}
+add_action('admin_post_itstudio_join_save_term_settings', 'itstudio_join_handle_save_term_settings');
+
+/**
+ * 新增学期。
+ */
+function itstudio_join_handle_create_term() {
+ if (!current_user_can('manage_options')) {
+ wp_die('权限不足');
+ }
+ check_admin_referer('itstudio_join_create_term');
+
+ $year = isset($_POST['academic_year']) ? sanitize_text_field(wp_unslash($_POST['academic_year'])) : '';
+ $season = isset($_POST['season']) ? sanitize_text_field(wp_unslash($_POST['season'])) : 'fall';
+ $label = isset($_POST['label']) ? sanitize_text_field(wp_unslash($_POST['label'])) : '';
+
+ if (trim($year) === '' && trim($label) === '') {
+ itstudio_join_settings_redirect(array('error' => 'need_year'));
+ }
+
+ $id = itstudio_join_create_term($year, $season, $label, null);
+ itstudio_join_settings_redirect(array('term' => $id, 'created' => '1'));
+}
+add_action('admin_post_itstudio_join_create_term', 'itstudio_join_handle_create_term');
+
+/**
+ * 把某学期设为当前生效。
+ */
+function itstudio_join_handle_activate_term() {
+ if (!current_user_can('manage_options')) {
+ wp_die('权限不足');
+ }
+ check_admin_referer('itstudio_join_activate_term');
+
+ $term_id = isset($_POST['term_id']) ? sanitize_text_field(wp_unslash($_POST['term_id'])) : '';
+ itstudio_join_set_active_term($term_id);
+ itstudio_join_settings_redirect(array('term' => $term_id, 'activated' => '1'));
+}
+add_action('admin_post_itstudio_join_activate_term', 'itstudio_join_handle_activate_term');
+
+/**
+ * 删除某学期(不能删当前生效或最后一个)。
+ */
+function itstudio_join_handle_delete_term() {
+ if (!current_user_can('manage_options')) {
+ wp_die('权限不足');
+ }
+ check_admin_referer('itstudio_join_delete_term');
+
+ $term_id = isset($_POST['term_id']) ? sanitize_text_field(wp_unslash($_POST['term_id'])) : '';
+ $terms = itstudio_join_get_terms();
+ if (count($terms) <= 1) {
+ itstudio_join_settings_redirect(array('term' => $term_id, 'error' => 'delete_last'));
+ }
+ if (itstudio_join_get_active_term_id() === $term_id) {
+ itstudio_join_settings_redirect(array('term' => $term_id, 'error' => 'delete_active'));
+ }
+ if (!itstudio_join_delete_term($term_id)) {
+ itstudio_join_settings_redirect(array('term' => $term_id, 'error' => 'delete_failed'));
+ }
+ itstudio_join_settings_redirect(array('deleted' => '1'));
+}
+add_action('admin_post_itstudio_join_delete_term', 'itstudio_join_handle_delete_term');
+
function itstudio_join_render_photo_field_row($field_key, $label, $settings) {
$attachment_id = isset($settings[$field_key]) ? absint($settings[$field_key]) : 0;
$preview_url = $attachment_id > 0 ? wp_get_attachment_image_url($attachment_id, 'medium_large') : '';
@@ -3576,14 +2152,41 @@ function itstudio_join_render_settings_page() {
wp_enqueue_media();
- $settings = itstudio_join_get_settings();
+ $terms = itstudio_join_get_terms();
+ $active_id = itstudio_join_get_active_term_id();
+ $editing_term_id = isset($_GET['term']) ? sanitize_text_field(wp_unslash($_GET['term'])) : '';
+ if ($editing_term_id === '' || !isset($terms[$editing_term_id])) {
+ $editing_term_id = $active_id;
+ }
+ $editing_term = isset($terms[$editing_term_id]) ? $terms[$editing_term_id] : null;
+ $is_editing_active = ($editing_term_id === $active_id);
+ $seasons = itstudio_join_get_seasons();
+
+ $settings = itstudio_join_get_settings($editing_term_id);
$runtime = itstudio_join_get_runtime_data();
$formidable_active = shortcode_exists('formidable') || class_exists('FrmFormsController');
$smtp_active = class_exists('\WPMailSMTP\WP') || defined('WPMS_PLUGIN_VER');
+ $admin_post_url = admin_url('admin-post.php');
?>
爱特工作室招新设置
-
用于配置「加入我们」页面的时间节点、阶段结果和表单。
+
用于配置「加入我们」页面的时间节点、阶段结果和表单。前台始终展示当前生效学期。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3597,8 +2200,84 @@ function itstudio_join_render_settings_page() {
-