__('Primary Menu', 'itstudio'),
));
load_theme_textdomain('itstudio', get_template_directory() . '/languages');
}
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_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' => __('Announcements', 'itstudio'),
'singular_name' => __('Announcement', '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' => __('News', 'itstudio'),
'singular_name' => __('News', '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 = '...';
}
$items[] = array(
'id' => $post_id,
'title' => $title,
'excerpt' => $excerpt,
'url' => $url,
'date' => get_the_date('Y-m-d', $post_id),
'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_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);
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);
}
}
$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_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_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');
if (!$is_join && is_404()) {
global $wp;
$request = isset($wp->request) ? trim((string) $wp->request, '/') : '';
$is_join = ($request === 'join');
}
return $is_join;
}
function itstudio_join_get_default_settings() {
return array(
'registration_start' => '',
'registration_end' => '',
'first_interview_date' => '',
'first_interview_end' => '',
'first_interview_location_cn' => '',
'first_interview_location_en' => '',
'second_interview_date' => '',
'second_interview_end' => '',
'second_interview_location_cn' => '',
'second_interview_location_en' => '',
'assessment_start_date' => '',
'assessment_end_date' => '',
'notice_start_date' => '',
'result_registration_records' => '',
'result_first_interview_records' => '',
'result_assessment_records' => '',
'result_second_interview_records' => '',
'result_admission_records' => '',
'photo_registration' => 0,
'photo_first_interview' => 0,
'photo_assessment' => 0,
'photo_second_interview' => 0,
'photo_public_notice' => 0,
'photo_inactive' => 0,
'signup_form_shortcode' => '',
);
}
function itstudio_join_get_photo_field_map() {
return array(
'registration' => 'photo_registration',
'first_interview' => 'photo_first_interview',
'assessment' => 'photo_assessment',
'second_interview' => 'photo_second_interview',
'public_notice' => 'photo_public_notice',
'inactive' => 'photo_inactive',
);
}
function itstudio_join_sanitize_datetime_local_value($value) {
$value = trim((string) $value);
if ($value === '') {
return '';
}
$value = preg_replace('/\s+/', 'T', $value);
// 兼容旧数据:仅日期
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
return $value;
}
// 兼容输入:YYYY-MM-DDTHH:MM 或 YYYY-MM-DDTHH:MM:SS
if (preg_match('/^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})(:\d{2})?$/', $value, $matches)) {
return $matches[1] . 'T' . $matches[2];
}
return '';
}
function itstudio_join_sanitize_date_value($value) {
$value = trim((string) $value);
if ($value === '') {
return '';
}
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
return '';
}
return $value;
}
function itstudio_join_sanitize_shortcode_value($value) {
if (!is_string($value)) {
return '';
}
return trim(sanitize_text_field(wp_unslash($value)));
}
function itstudio_join_sanitize_records_value($value) {
if (!is_string($value)) {
return '';
}
$value = sanitize_textarea_field(wp_unslash($value));
$value = str_replace(array("\r\n", "\r"), "\n", $value);
$lines = explode("\n", $value);
$clean_lines = array();
foreach ($lines as $line) {
$line = trim((string) $line);
if ($line === '') {
continue;
}
$clean_lines[] = $line;
}
return implode("\n", $clean_lines);
}
function itstudio_join_sanitize_settings($input) {
$defaults = itstudio_join_get_default_settings();
$input = is_array($input) ? $input : array();
$sanitized = array(
'registration_start' => itstudio_join_sanitize_datetime_local_value($input['registration_start'] ?? ''),
'registration_end' => itstudio_join_sanitize_datetime_local_value($input['registration_end'] ?? ''),
'first_interview_date' => itstudio_join_sanitize_datetime_local_value($input['first_interview_date'] ?? ''),
'first_interview_end' => itstudio_join_sanitize_datetime_local_value($input['first_interview_end'] ?? ''),
'first_interview_location_cn' => itstudio_join_sanitize_shortcode_value($input['first_interview_location_cn'] ?? ''),
'first_interview_location_en' => itstudio_join_sanitize_shortcode_value($input['first_interview_location_en'] ?? ''),
'second_interview_date' => itstudio_join_sanitize_datetime_local_value($input['second_interview_date'] ?? ''),
'second_interview_end' => itstudio_join_sanitize_datetime_local_value($input['second_interview_end'] ?? ''),
'second_interview_location_cn' => itstudio_join_sanitize_shortcode_value($input['second_interview_location_cn'] ?? ''),
'second_interview_location_en' => itstudio_join_sanitize_shortcode_value($input['second_interview_location_en'] ?? ''),
'assessment_start_date' => itstudio_join_sanitize_date_value($input['assessment_start_date'] ?? ''),
'assessment_end_date' => itstudio_join_sanitize_date_value($input['assessment_end_date'] ?? ''),
'notice_start_date' => itstudio_join_sanitize_date_value($input['notice_start_date'] ?? ''),
'result_registration_records' => itstudio_join_sanitize_records_value($input['result_registration_records'] ?? ''),
'result_first_interview_records' => itstudio_join_sanitize_records_value($input['result_first_interview_records'] ?? ''),
'result_assessment_records' => itstudio_join_sanitize_records_value($input['result_assessment_records'] ?? ''),
'result_second_interview_records' => itstudio_join_sanitize_records_value($input['result_second_interview_records'] ?? ''),
'result_admission_records' => itstudio_join_sanitize_records_value($input['result_admission_records'] ?? ''),
'signup_form_shortcode' => itstudio_join_sanitize_shortcode_value($input['signup_form_shortcode'] ?? ''),
);
foreach (itstudio_join_get_photo_field_map() as $field_key) {
$sanitized[$field_key] = isset($input[$field_key]) ? absint($input[$field_key]) : 0;
}
return array_merge($defaults, $sanitized);
}
function itstudio_join_get_settings() {
$defaults = itstudio_join_get_default_settings();
$stored = get_option('itstudio_join_settings', array());
if (!is_array($stored)) {
return $defaults;
}
return array_merge($defaults, itstudio_join_sanitize_settings($stored));
}
function itstudio_join_parse_datetime_local($value, $date_only_as_end_of_day = false) {
$value = itstudio_join_sanitize_datetime_local_value($value);
if ($value === '') {
return null;
}
$timezone = wp_timezone();
$format = 'Y-m-d\TH:i';
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
$format = 'Y-m-d';
}
$parsed = DateTimeImmutable::createFromFormat('!' . $format, $value, $timezone);
$errors = DateTimeImmutable::getLastErrors();
if (!($parsed instanceof DateTimeImmutable)) {
return null;
}
if (is_array($errors) && (($errors['warning_count'] ?? 0) > 0 || ($errors['error_count'] ?? 0) > 0)) {
return null;
}
if ($format === 'Y-m-d') {
return $date_only_as_end_of_day
? $parsed->setTime(23, 59, 59)
: $parsed->setTime(0, 0, 0);
}
return $parsed;
}
function itstudio_join_parse_date($value) {
$value = itstudio_join_sanitize_date_value($value);
if ($value === '') {
return null;
}
$timezone = wp_timezone();
$parsed = DateTimeImmutable::createFromFormat('!Y-m-d', $value, $timezone);
$errors = DateTimeImmutable::getLastErrors();
if (!($parsed instanceof DateTimeImmutable)) {
return null;
}
if (is_array($errors) && (($errors['warning_count'] ?? 0) > 0 || ($errors['error_count'] ?? 0) > 0)) {
return null;
}
return $parsed;
}
function itstudio_join_to_datetime_local_input_value($value, $date_only_as_end_of_day = false) {
$parsed = itstudio_join_parse_datetime_local($value, $date_only_as_end_of_day);
return $parsed instanceof DateTimeImmutable ? $parsed->format('Y-m-d\TH:i') : '';
}
function itstudio_join_to_date_input_value($value) {
$parsed = itstudio_join_parse_date($value);
if (!($parsed instanceof DateTimeImmutable)) {
$parsed = itstudio_join_parse_datetime_local($value, false);
}
return $parsed instanceof DateTimeImmutable ? $parsed->format('Y-m-d') : '';
}
function itstudio_join_get_result_field_map() {
return array(
'registration' => 'result_registration_records',
'first_interview' => 'result_first_interview_records',
'assessment' => 'result_assessment_records',
'second_interview' => 'result_second_interview_records',
'public_notice' => 'result_admission_records',
);
}
function itstudio_join_has_uploaded_result_for_stage($settings, $stage_key) {
$settings = is_array($settings) ? $settings : array();
$field_map = itstudio_join_get_result_field_map();
$field_key = isset($field_map[$stage_key]) ? $field_map[$stage_key] : '';
if ($field_key === '') {
return false;
}
return trim((string) ($settings[$field_key] ?? '')) !== '';
}
function itstudio_join_normalize_lookup_value($field, $value) {
$field = trim((string) $field);
$value = trim((string) $value);
if ($value === '') {
return '';
}
if ($field === 'qq') {
return preg_replace('/\D+/', '', $value);
}
if ($field === 'email') {
return strtolower($value);
}
if ($field === 'student_id') {
return strtoupper(preg_replace('/\s+/u', '', $value));
}
$value = preg_replace('/\s+/u', '', $value);
if (function_exists('mb_strtolower')) {
return mb_strtolower($value, 'UTF-8');
}
return strtolower($value);
}
function itstudio_join_parse_result_records($raw) {
$raw = str_replace(array("\r\n", "\r"), "\n", (string) $raw);
if ($raw === '') {
return array();
}
$records = array();
$lines = explode("\n", $raw);
foreach ($lines as $line) {
$line = trim((string) $line);
if ($line === '' || strpos($line, '#') === 0) {
continue;
}
$header_probe = preg_replace('/\s+/u', '', $line);
$header_probe = function_exists('mb_strtolower') ? mb_strtolower($header_probe, 'UTF-8') : strtolower($header_probe);
$is_cn_header = (strpos($header_probe, '姓名') !== false) && (strpos($header_probe, 'qq') !== false || strpos($header_probe, '邮箱') !== false || strpos($header_probe, '学号') !== false);
$is_en_header = (strpos($header_probe, 'name') !== false) && (strpos($header_probe, 'qq') !== false || strpos($header_probe, 'email') !== false || strpos($header_probe, 'student') !== false);
if ($is_cn_header || $is_en_header) {
continue;
}
$parts = preg_split('/[,\|,\t]+/u', $line);
$parts = is_array($parts) ? array_values(array_filter(array_map('trim', $parts), static function ($item) {
return $item !== '';
})) : array();
if (empty($parts)) {
continue;
}
$name = '';
$qq = '';
$email = '';
$student_id = '';
if (count($parts) === 1) {
$single = (string) $parts[0];
if (strpos($single, '@') !== false) {
$email = $single;
} elseif (preg_match('/^\d{5,}$/', $single)) {
$qq = $single;
} else {
$name = $single;
}
} else {
$name = (string) ($parts[0] ?? '');
$qq = (string) ($parts[1] ?? '');
$email = (string) ($parts[2] ?? '');
$student_id = (string) ($parts[3] ?? '');
}
$record = array(
'name' => itstudio_join_normalize_lookup_value('name', $name),
'qq' => itstudio_join_normalize_lookup_value('qq', $qq),
'email' => itstudio_join_normalize_lookup_value('email', $email),
'student_id' => itstudio_join_normalize_lookup_value('student_id', $student_id),
);
if ($record['name'] === '' && $record['qq'] === '' && $record['email'] === '' && $record['student_id'] === '') {
continue;
}
$records[] = $record;
}
return $records;
}
function itstudio_join_record_matches_query($record, $query) {
$record = is_array($record) ? $record : array();
$query = is_array($query) ? $query : array();
$has_any_query = false;
foreach (array('name', 'qq', 'email', 'student_id') as $field) {
$q = trim((string) ($query[$field] ?? ''));
if ($q === '') {
continue;
}
$has_any_query = true;
$r = trim((string) ($record[$field] ?? ''));
if ($r === '' || $r !== $q) {
return false;
}
}
return $has_any_query;
}
function itstudio_join_find_record_in_stage_results($settings, $stage_key, $query) {
$settings = is_array($settings) ? $settings : array();
$field_map = itstudio_join_get_result_field_map();
$field_key = isset($field_map[$stage_key]) ? $field_map[$stage_key] : '';
if ($field_key === '') {
return false;
}
$raw = (string) ($settings[$field_key] ?? '');
if (trim($raw) === '') {
return false;
}
$records = itstudio_join_parse_result_records($raw);
if (empty($records)) {
return false;
}
foreach ($records as $record) {
if (itstudio_join_record_matches_query($record, $query)) {
return true;
}
}
return false;
}
function itstudio_join_get_stage_status_by_key($runtime, $stage_key) {
$runtime = is_array($runtime) ? $runtime : array();
$stages = isset($runtime['stages']) && is_array($runtime['stages']) ? $runtime['stages'] : array();
foreach ($stages as $stage) {
if (!is_array($stage)) {
continue;
}
if ((string) ($stage['key'] ?? '') === (string) $stage_key) {
return (string) ($stage['status'] ?? 'pending');
}
}
return 'pending';
}
function itstudio_join_resolve_progress_lookup($runtime = array(), $request_source = null) {
$runtime = is_array($runtime) ? $runtime : array();
$settings = isset($runtime['settings']) && is_array($runtime['settings']) ? $runtime['settings'] : itstudio_join_get_settings();
$request_source = is_array($request_source) ? $request_source : $_GET;
$raw_name = isset($request_source['join_query_name']) ? sanitize_text_field(wp_unslash((string) $request_source['join_query_name'])) : '';
$raw_qq = isset($request_source['join_query_qq']) ? sanitize_text_field(wp_unslash((string) $request_source['join_query_qq'])) : '';
$raw_email = isset($request_source['join_query_email']) ? sanitize_text_field(wp_unslash((string) $request_source['join_query_email'])) : '';
$raw_student_id = isset($request_source['join_query_student_id']) ? sanitize_text_field(wp_unslash((string) $request_source['join_query_student_id'])) : '';
$query = array(
'name' => itstudio_join_normalize_lookup_value('name', $raw_name),
'qq' => itstudio_join_normalize_lookup_value('qq', $raw_qq),
'email' => itstudio_join_normalize_lookup_value('email', $raw_email),
'student_id' => itstudio_join_normalize_lookup_value('student_id', $raw_student_id),
);
$has_query_value = false;
foreach ($query as $value) {
if ($value !== '') {
$has_query_value = true;
break;
}
}
$submitted = isset($request_source['join_progress_lookup']) || $has_query_value;
$response = array(
'submitted' => $submitted,
'has_query' => $has_query_value,
'name' => $raw_name,
'qq' => $raw_qq,
'email' => $raw_email,
'student_id' => $raw_student_id,
'message_cn' => '',
'message_en' => '',
'tone' => 'info',
);
if (!$submitted) {
return $response;
}
if (!$has_query_value) {
$response['message_cn'] = '请至少填写姓名、QQ、邮箱、学号中的一项。';
$response['message_en'] = 'Please fill at least one item: name, QQ, email or student ID.';
$response['tone'] = 'warning';
return $response;
}
$status_registration = itstudio_join_get_stage_status_by_key($runtime, 'registration');
$status_first = itstudio_join_get_stage_status_by_key($runtime, 'first_interview');
$status_assessment = itstudio_join_get_stage_status_by_key($runtime, 'assessment');
$status_second = itstudio_join_get_stage_status_by_key($runtime, 'second_interview');
$status_notice = itstudio_join_get_stage_status_by_key($runtime, 'public_notice');
$uploaded_registration = itstudio_join_has_uploaded_result_for_stage($settings, 'registration');
$uploaded_first = itstudio_join_has_uploaded_result_for_stage($settings, 'first_interview');
$uploaded_assessment = itstudio_join_has_uploaded_result_for_stage($settings, 'assessment');
$uploaded_second = itstudio_join_has_uploaded_result_for_stage($settings, 'second_interview');
$uploaded_notice = itstudio_join_has_uploaded_result_for_stage($settings, 'public_notice');
if (!$uploaded_registration) {
$response['message_cn'] = '报名数据尚未上传,暂无法查询。';
$response['message_en'] = 'Registration data has not been uploaded yet.';
$response['tone'] = 'warning';
return $response;
}
$is_registered = itstudio_join_find_record_in_stage_results($settings, 'registration', $query);
if (!$is_registered) {
$response['message_cn'] = '未报名。';
$response['message_en'] = 'Not registered.';
$response['tone'] = 'error';
return $response;
}
if ($status_registration === 'active' || $status_registration === 'upcoming' || $status_first === 'upcoming' || $status_first === 'pending') {
$response['message_cn'] = '已报名。';
$response['message_en'] = 'Registered.';
$response['tone'] = 'success';
return $response;
}
if ($status_first === 'completed') {
if (!$uploaded_first) {
$response['message_cn'] = '第一次面试已结束,结果尚未上传。';
$response['message_en'] = 'Interview I has ended, but results are not uploaded yet.';
$response['tone'] = 'warning';
return $response;
}
$passed_first = itstudio_join_find_record_in_stage_results($settings, 'first_interview', $query);
if (!$passed_first) {
$response['message_cn'] = '未通过第一次面试,期待来年再次报名。';
$response['message_en'] = 'You did not pass Interview I. Welcome to apply again next year.';
$response['tone'] = 'error';
return $response;
}
if ($status_assessment === 'upcoming' || $status_assessment === 'pending' || $status_assessment === 'active') {
$response['message_cn'] = '恭喜,您已通过第一次面试。';
$response['message_en'] = 'Congratulations! You have passed Interview I.';
$response['tone'] = 'success';
return $response;
}
}
if ($status_assessment === 'completed') {
if (!$uploaded_assessment) {
$response['message_cn'] = '国庆能力摸底已结束,结果尚未上传。';
$response['message_en'] = 'Assessment stage has ended, but results are not uploaded yet.';
$response['tone'] = 'warning';
return $response;
}
$passed_assessment = itstudio_join_find_record_in_stage_results($settings, 'assessment', $query);
if (!$passed_assessment) {
$response['message_cn'] = '未通过国庆能力摸底,期待来年再次报名。';
$response['message_en'] = 'You did not pass the assessment stage. Welcome to apply again next year.';
$response['tone'] = 'error';
return $response;
}
if ($status_second === 'upcoming' || $status_second === 'pending' || $status_second === 'active') {
$response['message_cn'] = '恭喜,您已通过国庆能力摸底。';
$response['message_en'] = 'Congratulations! You have passed the assessment stage.';
$response['tone'] = 'success';
return $response;
}
}
if ($status_second === 'completed') {
if (!$uploaded_second) {
$response['message_cn'] = '第二次面试已结束,结果尚未上传。';
$response['message_en'] = 'Interview II has ended, but results are not uploaded yet.';
$response['tone'] = 'warning';
return $response;
}
$passed_second = itstudio_join_find_record_in_stage_results($settings, 'second_interview', $query);
if (!$passed_second) {
$response['message_cn'] = '未通过第二次面试,期待来年再次报名。';
$response['message_en'] = 'You did not pass Interview II. Welcome to apply again next year.';
$response['tone'] = 'error';
return $response;
}
if ($status_notice === 'pending' || $status_notice === 'upcoming' || $status_notice === 'active') {
if ($status_notice === 'active' && $uploaded_notice) {
$admitted = itstudio_join_find_record_in_stage_results($settings, 'public_notice', $query);
if ($admitted) {
$response['message_cn'] = '恭喜,您已被录取。';
$response['message_en'] = 'Congratulations! You have been admitted.';
$response['tone'] = 'success';
return $response;
}
$response['message_cn'] = '很遗憾,您未被录取,期待来年再次报名。';
$response['message_en'] = 'Sorry, you were not admitted. Welcome to apply again next year.';
$response['tone'] = 'error';
return $response;
}
$response['message_cn'] = '恭喜,您已通过第二次面试,请等待录取结果公布。';
$response['message_en'] = 'Congratulations! You have passed Interview II. Please wait for the final result.';
$response['tone'] = 'success';
return $response;
}
}
if (($status_notice === 'active' || $status_notice === 'completed') && $uploaded_notice) {
$admitted = itstudio_join_find_record_in_stage_results($settings, 'public_notice', $query);
if ($admitted) {
$response['message_cn'] = '恭喜,您已被录取。';
$response['message_en'] = 'Congratulations! You have been admitted.';
$response['tone'] = 'success';
} else {
$response['message_cn'] = '很遗憾,您未被录取,期待来年再次报名。';
$response['message_en'] = 'Sorry, you were not admitted. Welcome to apply again next year.';
$response['tone'] = 'error';
}
return $response;
}
$response['message_cn'] = '已报名。';
$response['message_en'] = 'Registered.';
$response['tone'] = 'success';
return $response;
}
function itstudio_join_datetime_to_ms($date) {
if (!($date instanceof DateTimeImmutable)) {
return null;
}
return (int) $date->format('U') * 1000;
}
function itstudio_join_resolve_stage_status($now, $start, $end) {
if (!($now instanceof DateTimeImmutable)) {
return 'pending';
}
if (!($start instanceof DateTimeImmutable) && !($end instanceof DateTimeImmutable)) {
return 'pending';
}
if ($start instanceof DateTimeImmutable && $now < $start) {
return 'upcoming';
}
if ($start instanceof DateTimeImmutable && $end instanceof DateTimeImmutable) {
if ($now >= $start && $now <= $end) {
return 'active';
}
if ($now > $end) {
return 'completed';
}
}
if ($start instanceof DateTimeImmutable && !($end instanceof DateTimeImmutable)) {
if ($now >= $start) {
return 'active';
}
}
if (!($start instanceof DateTimeImmutable) && $end instanceof DateTimeImmutable) {
return $now <= $end ? 'active' : 'completed';
}
return 'upcoming';
}
function itstudio_join_is_in_window($now, $start, $end) {
if (!($now instanceof DateTimeImmutable) || !($start instanceof DateTimeImmutable)) {
return false;
}
if ($now < $start) {
return false;
}
if ($end instanceof DateTimeImmutable && $now > $end) {
return false;
}
return true;
}
function itstudio_join_format_stage_range($start, $end, $all_day = false) {
if (!($start instanceof DateTimeImmutable) && !($end instanceof DateTimeImmutable)) {
return array(
'cn' => '时间待定',
'en' => 'Schedule TBA',
);
}
$format_cn_day = 'Y.m.d';
$format_cn_full = 'Y.m.d H:i';
$format_en_day = 'M j, Y';
$format_en_full = 'M j, Y H:i';
if ($start instanceof DateTimeImmutable && !($end instanceof DateTimeImmutable)) {
return array(
'cn' => $all_day ? $start->format($format_cn_day) : $start->format($format_cn_full),
'en' => $all_day ? $start->format($format_en_day) : $start->format($format_en_full),
);
}
if (!($start instanceof DateTimeImmutable) && $end instanceof DateTimeImmutable) {
return array(
'cn' => $all_day ? $end->format($format_cn_day) : $end->format($format_cn_full),
'en' => $all_day ? $end->format($format_en_day) : $end->format($format_en_full),
);
}
if (!($start instanceof DateTimeImmutable) || !($end instanceof DateTimeImmutable)) {
return array(
'cn' => '时间待定',
'en' => 'Schedule TBA',
);
}
$start_cn = $all_day ? $start->format($format_cn_day) : $start->format($format_cn_full);
$end_cn = $all_day ? $end->format($format_cn_day) : $end->format($format_cn_full);
$start_en = $all_day ? $start->format($format_en_day) : $start->format($format_en_full);
$end_en = $all_day ? $end->format($format_en_day) : $end->format($format_en_full);
if ($start_cn === $end_cn) {
return array(
'cn' => $start_cn,
'en' => $start_en,
);
}
return array(
'cn' => $start_cn . ' - ' . $end_cn,
'en' => $start_en . ' - ' . $end_en,
);
}
function itstudio_join_get_stage_photo_url($settings, $stage_key) {
$settings = is_array($settings) ? $settings : array();
$field_map = itstudio_join_get_photo_field_map();
$field_key = isset($field_map[$stage_key]) ? $field_map[$stage_key] : '';
$attachment_id = 0;
if ($field_key !== '' && isset($settings[$field_key])) {
$attachment_id = absint($settings[$field_key]);
}
if ($attachment_id > 0) {
$photo_url = wp_get_attachment_image_url($attachment_id, 'full');
if (is_string($photo_url) && $photo_url !== '') {
return $photo_url;
}
}
return '';
}
function itstudio_join_get_runtime_data() {
static $cached = null;
if (is_array($cached)) {
return $cached;
}
$settings = itstudio_join_get_settings();
$timezone = wp_timezone();
$now = new DateTimeImmutable('now', $timezone);
$registration_start = itstudio_join_parse_datetime_local($settings['registration_start'], false);
$registration_end = itstudio_join_parse_datetime_local($settings['registration_end'], true);
if ($registration_start instanceof DateTimeImmutable) {
$registration_start = $registration_start->setTime(0, 0, 0);
}
if ($registration_end instanceof DateTimeImmutable) {
$registration_end = $registration_end->setTime(23, 59, 59);
}
if ($registration_start instanceof DateTimeImmutable && $registration_end instanceof DateTimeImmutable && $registration_end < $registration_start) {
$registration_end = $registration_start;
}
$first_interview_start_raw = isset($settings['first_interview_date']) ? (string) $settings['first_interview_date'] : '';
$first_interview_end_raw = isset($settings['first_interview_end']) ? (string) $settings['first_interview_end'] : '';
$first_interview_start = itstudio_join_parse_datetime_local($first_interview_start_raw, false);
$first_interview_end = itstudio_join_parse_datetime_local($first_interview_end_raw, true);
if ($first_interview_start instanceof DateTimeImmutable && !($first_interview_end instanceof DateTimeImmutable)) {
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', trim($first_interview_start_raw))) {
$first_interview_end = $first_interview_start->setTime(23, 59, 59);
} else {
$first_interview_end = $first_interview_start;
}
} elseif (!($first_interview_start instanceof DateTimeImmutable) && $first_interview_end instanceof DateTimeImmutable) {
$first_interview_start = $first_interview_end;
} elseif ($first_interview_start instanceof DateTimeImmutable && $first_interview_end instanceof DateTimeImmutable && $first_interview_end < $first_interview_start) {
$first_interview_end = $first_interview_start;
}
$second_interview_start_raw = isset($settings['second_interview_date']) ? (string) $settings['second_interview_date'] : '';
$second_interview_end_raw = isset($settings['second_interview_end']) ? (string) $settings['second_interview_end'] : '';
$second_interview_start = itstudio_join_parse_datetime_local($second_interview_start_raw, false);
$second_interview_end = itstudio_join_parse_datetime_local($second_interview_end_raw, true);
if ($second_interview_start instanceof DateTimeImmutable && !($second_interview_end instanceof DateTimeImmutable)) {
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', trim($second_interview_start_raw))) {
$second_interview_end = $second_interview_start->setTime(23, 59, 59);
} else {
$second_interview_end = $second_interview_start;
}
} elseif (!($second_interview_start instanceof DateTimeImmutable) && $second_interview_end instanceof DateTimeImmutable) {
$second_interview_start = $second_interview_end;
} elseif ($second_interview_start instanceof DateTimeImmutable && $second_interview_end instanceof DateTimeImmutable && $second_interview_end < $second_interview_start) {
$second_interview_end = $second_interview_start;
}
$first_interview_location_cn = trim((string) ($settings['first_interview_location_cn'] ?? ''));
$first_interview_location_en = trim((string) ($settings['first_interview_location_en'] ?? ''));
if ($first_interview_location_en === '') {
$first_interview_location_en = $first_interview_location_cn;
}
$second_interview_location_cn = trim((string) ($settings['second_interview_location_cn'] ?? ''));
$second_interview_location_en = trim((string) ($settings['second_interview_location_en'] ?? ''));
if ($second_interview_location_en === '') {
$second_interview_location_en = $second_interview_location_cn;
}
$notice_start_day = itstudio_join_parse_date($settings['notice_start_date']);
$notice_start = $notice_start_day instanceof DateTimeImmutable ? $notice_start_day->setTime(0, 0, 0) : null;
$notice_end = $notice_start instanceof DateTimeImmutable ? $notice_start->modify('+6 days')->setTime(23, 59, 59) : null;
$recruitment_year = null;
if ($registration_start instanceof DateTimeImmutable) {
$recruitment_year = (int) $registration_start->format('Y');
} elseif ($notice_start instanceof DateTimeImmutable) {
$recruitment_year = (int) $notice_start->format('Y');
} else {
$recruitment_year = (int) $now->format('Y');
}
$default_assessment_start = DateTimeImmutable::createFromFormat('!Y-m-d', sprintf('%04d-10-01', $recruitment_year), $timezone);
$default_assessment_end_base = DateTimeImmutable::createFromFormat('!Y-m-d', sprintf('%04d-10-07', $recruitment_year), $timezone);
$default_assessment_end = $default_assessment_end_base instanceof DateTimeImmutable ? $default_assessment_end_base->setTime(23, 59, 59) : null;
$assessment_start_day = itstudio_join_parse_date($settings['assessment_start_date']);
$assessment_end_day = itstudio_join_parse_date($settings['assessment_end_date']);
$assessment_start = $assessment_start_day instanceof DateTimeImmutable
? $assessment_start_day->setTime(0, 0, 0)
: $default_assessment_start;
$assessment_end = $assessment_end_day instanceof DateTimeImmutable
? $assessment_end_day->setTime(23, 59, 59)
: $default_assessment_end;
if ($assessment_start_day instanceof DateTimeImmutable && !($assessment_end_day instanceof DateTimeImmutable)) {
$assessment_end = $assessment_start->setTime(23, 59, 59);
} elseif (!($assessment_start_day instanceof DateTimeImmutable) && $assessment_end_day instanceof DateTimeImmutable) {
$assessment_start = $assessment_end_day->setTime(0, 0, 0);
}
if ($assessment_start instanceof DateTimeImmutable && $assessment_end instanceof DateTimeImmutable && $assessment_end < $assessment_start) {
$assessment_end = $assessment_start->setTime(23, 59, 59);
}
$stage_seed = array(
array(
'key' => 'registration',
'label_cn' => '报名阶段',
'label_en' => 'Registration',
'short_cn' => '报名',
'short_en' => 'Reg',
'start' => $registration_start,
'end' => $registration_end,
'all_day' => true,
'location_cn' => '',
'location_en' => '',
'result_uploaded' => itstudio_join_has_uploaded_result_for_stage($settings, 'registration'),
),
array(
'key' => 'first_interview',
'label_cn' => '第一次面试',
'label_en' => 'Interview I',
'short_cn' => '一面',
'short_en' => 'I-1',
'start' => $first_interview_start,
'end' => $first_interview_end,
'all_day' => false,
'location_cn' => $first_interview_location_cn,
'location_en' => $first_interview_location_en,
'result_uploaded' => itstudio_join_has_uploaded_result_for_stage($settings, 'first_interview'),
),
array(
'key' => 'assessment',
'label_cn' => '国庆能力摸底',
'label_en' => 'Assessment',
'short_cn' => '摸底',
'short_en' => 'Assess',
'start' => $assessment_start,
'end' => $assessment_end,
'all_day' => true,
'location_cn' => '',
'location_en' => '',
'result_uploaded' => itstudio_join_has_uploaded_result_for_stage($settings, 'assessment'),
),
array(
'key' => 'second_interview',
'label_cn' => '第二次面试',
'label_en' => 'Interview II',
'short_cn' => '二面',
'short_en' => 'I-2',
'start' => $second_interview_start,
'end' => $second_interview_end,
'all_day' => false,
'location_cn' => $second_interview_location_cn,
'location_en' => $second_interview_location_en,
'result_uploaded' => itstudio_join_has_uploaded_result_for_stage($settings, 'second_interview'),
),
array(
'key' => 'public_notice',
'label_cn' => '录取结果公布',
'label_en' => 'Public Notice',
'short_cn' => '公布',
'short_en' => 'Notice',
'start' => $notice_start,
'end' => $notice_end,
'all_day' => true,
'location_cn' => '',
'location_en' => '',
'result_uploaded' => itstudio_join_has_uploaded_result_for_stage($settings, 'public_notice'),
),
);
$stages = array();
foreach ($stage_seed as $stage) {
$range = itstudio_join_format_stage_range($stage['start'], $stage['end'], !empty($stage['all_day']));
$status = itstudio_join_resolve_stage_status($now, $stage['start'], $stage['end']);
$stages[] = array(
'key' => $stage['key'],
'label_cn' => $stage['label_cn'],
'label_en' => $stage['label_en'],
'short_cn' => $stage['short_cn'],
'short_en' => $stage['short_en'],
'status' => $status,
'range_cn' => $range['cn'],
'range_en' => $range['en'],
'location_cn' => isset($stage['location_cn']) ? (string) $stage['location_cn'] : '',
'location_en' => isset($stage['location_en']) ? (string) $stage['location_en'] : '',
'result_uploaded' => !empty($stage['result_uploaded']),
'start_ts' => itstudio_join_datetime_to_ms($stage['start']),
'end_ts' => itstudio_join_datetime_to_ms($stage['end']),
);
}
$current_stage_index = -1;
foreach ($stages as $index => $stage) {
if ($stage['status'] === 'active') {
$current_stage_index = (int) $index;
break;
}
}
$next_stage_index = -1;
if ($current_stage_index < 0) {
foreach ($stages as $index => $stage) {
if (($stage['status'] ?? '') === 'upcoming') {
$next_stage_index = (int) $index;
break;
}
}
}
$current_stage_mode = 'inactive';
$display_stage_index = -1;
if ($current_stage_index >= 0 && isset($stages[$current_stage_index])) {
$display_stage_index = $current_stage_index;
$current_stage_mode = 'active';
} elseif ($next_stage_index >= 0 && isset($stages[$next_stage_index])) {
$display_stage_index = $next_stage_index;
$current_stage_mode = 'next';
}
$current_stage = ($display_stage_index >= 0 && isset($stages[$display_stage_index]))
? $stages[$display_stage_index]
: array(
'key' => 'inactive',
'label_cn' => '当前未在招新时段',
'label_en' => 'Recruitment is currently closed',
'short_cn' => '',
'short_en' => '',
'status' => 'inactive',
'range_cn' => '请关注后续通知',
'range_en' => 'Please check later updates',
'location_cn' => '',
'location_en' => '',
'result_uploaded' => false,
'start_ts' => null,
'end_ts' => null,
);
$is_registration_open = itstudio_join_is_in_window($now, $registration_start, $registration_end);
$is_query_open = false;
if ($registration_start instanceof DateTimeImmutable) {
if ($notice_end instanceof DateTimeImmutable) {
$is_query_open = itstudio_join_is_in_window($now, $registration_start, $notice_end);
} else {
$is_query_open = ($now >= $registration_start);
}
}
$is_notice_open = itstudio_join_is_in_window($now, $notice_start, $notice_end);
$current_stage_photo_url = itstudio_join_get_stage_photo_url($settings, (string) ($current_stage['key'] ?? ''));
if ($current_stage_photo_url === '') {
$current_stage_photo_url = get_template_directory_uri() . '/resources/it_logo_2024.svg';
}
$season_start = null;
$season_end = null;
foreach ($stage_seed as $stage_window) {
$stage_start = $stage_window['start'] instanceof DateTimeImmutable ? $stage_window['start'] : null;
$stage_end = $stage_window['end'] instanceof DateTimeImmutable ? $stage_window['end'] : null;
if (!($stage_start instanceof DateTimeImmutable) && !($stage_end instanceof DateTimeImmutable)) {
continue;
}
$window_start = $stage_start instanceof DateTimeImmutable ? $stage_start : $stage_end;
$window_end = $stage_end instanceof DateTimeImmutable ? $stage_end : $stage_start;
if (!($window_start instanceof DateTimeImmutable) || !($window_end instanceof DateTimeImmutable)) {
continue;
}
if (!($season_start instanceof DateTimeImmutable) || $window_start < $season_start) {
$season_start = $window_start;
}
if (!($season_end instanceof DateTimeImmutable) || $window_end > $season_end) {
$season_end = $window_end;
}
}
$show_progress_visual = false;
if ($season_start instanceof DateTimeImmutable && $season_end instanceof DateTimeImmutable) {
$show_progress_visual = ($now >= $season_start && $now <= $season_end);
} elseif ($current_stage_index >= 0) {
$show_progress_visual = true;
}
$cached = array(
'settings' => $settings,
'timezone' => $timezone->getName(),
'recruitment_year' => $recruitment_year,
'now_ts' => (int) $now->format('U') * 1000,
'stages' => $stages,
'current_stage_index' => $current_stage_index,
'current_stage_mode' => $current_stage_mode,
'current_stage' => $current_stage,
'is_registration_open' => $is_registration_open,
'is_query_open' => $is_query_open,
'is_notice_open' => $is_notice_open,
'show_progress_visual' => $show_progress_visual,
'current_stage_photo_url' => $current_stage_photo_url,
'query_deadline_cn' => $notice_end instanceof DateTimeImmutable ? $notice_end->format('Y-m-d H:i') : '',
'query_deadline_en' => $notice_end instanceof DateTimeImmutable ? $notice_end->format('M j, Y H:i') : '',
);
return $cached;
}
function itstudio_join_get_frontend_payload() {
$runtime = itstudio_join_get_runtime_data();
return array(
'nowTs' => (int) ($runtime['now_ts'] ?? 0),
'currentStageIndex' => (int) ($runtime['current_stage_index'] ?? -1),
'stages' => array_values(array_map(static function ($stage) {
return array(
'key' => (string) ($stage['key'] ?? ''),
'labelCn' => (string) ($stage['label_cn'] ?? ''),
'labelEn' => (string) ($stage['label_en'] ?? ''),
'shortCn' => (string) ($stage['short_cn'] ?? ''),
'shortEn' => (string) ($stage['short_en'] ?? ''),
'status' => (string) ($stage['status'] ?? 'pending'),
'rangeCn' => (string) ($stage['range_cn'] ?? ''),
'rangeEn' => (string) ($stage['range_en'] ?? ''),
'locationCn' => (string) ($stage['location_cn'] ?? ''),
'locationEn' => (string) ($stage['location_en'] ?? ''),
'resultUploaded' => !empty($stage['result_uploaded']),
'startTs' => isset($stage['start_ts']) ? $stage['start_ts'] : null,
'endTs' => isset($stage['end_ts']) ? $stage['end_ts'] : null,
);
}, (array) ($runtime['stages'] ?? array()))),
);
}
function itstudio_join_enqueue_assets() {
if (!itstudio_is_join_page_context()) {
return;
}
wp_enqueue_style(
'itstudio-join-page',
get_template_directory_uri() . '/assets/css/join-page.css',
array('itstudio-content'),
'1.1.0'
);
wp_enqueue_script(
'itstudio-animejs',
get_template_directory_uri() . '/assets/js/vendor/anime.min.js',
array(),
'3.2.2',
true
);
wp_enqueue_script(
'itstudio-join-canvas',
get_template_directory_uri() . '/assets/js/join-canvas.js',
array('itstudio-animejs'),
'1.1.0',
true
);
wp_localize_script('itstudio-join-canvas', 'itstudioJoinData', itstudio_join_get_frontend_payload());
}
add_action('wp_enqueue_scripts', 'itstudio_join_enqueue_assets', 30);
function itstudio_join_register_settings() {
register_setting(
'itstudio_join_settings_group',
'itstudio_join_settings',
array(
'type' => 'array',
'sanitize_callback' => 'itstudio_join_sanitize_settings',
'default' => itstudio_join_get_default_settings(),
)
);
}
add_action('admin_init', 'itstudio_join_register_settings');
function itstudio_join_register_settings_page() {
add_options_page(
'招新设置',
'招新设置',
'manage_options',
'itstudio-join-settings',
'itstudio_join_render_settings_page'
);
}
add_action('admin_menu', 'itstudio_join_register_settings_page');
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') : '';
?>
|
|
|
每行一条记录,格式:姓名,QQ,邮箱,学号。可用逗号、中文逗号、竖线或 Tab 分隔。
|
爱特工作室招新设置
用于配置「加入我们」页面的时间节点、阶段结果和表单。
提示:未检测到 Formidable Forms 插件。报名表单将无法在前台渲染。
提示:未检测到 WP Mail SMTP 插件。建议启用后再开放报名邮件通知。
阶段预览
国庆能力摸底默认固定为每年 10 月 1 日至 10 月 7 日;如填写上方“摸底开始/结束日期(调试)”则优先使用调试时间,留空则恢复默认固定窗口。
request) ? trim((string) $wp->request, '/') : '';
if ($request !== 'join') {
return;
}
$template = locate_template('page-join.php');
if (!$template) {
return;
}
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' => '加入我们',
'post_status' => 'publish',
'post_name' => 'join',
'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', static function ($parts) {
$parts['title'] = '加入我们';
return $parts;
});
status_header(200);
nocache_headers();
include $template;
exit;
}
add_action('template_redirect', 'itstudio_join_fallback', 9);