6d4368fbd1
Features: - Modern UI with dark mode support - Code highlighting with copy button - Auto table of contents - Reading time & views counter - Responsive design - Admin settings page - AJAX search
460 lines
14 KiB
PHP
Executable File
460 lines
14 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* TechBlog Pro Theme Functions
|
|
*
|
|
* @package TechBlog Pro
|
|
* @version 1.0.0
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
// Theme Constants
|
|
define('TECHBLOG_VERSION', '1.0.0');
|
|
define('TECHBLOG_DIR', get_template_directory());
|
|
define('TECHBLOG_URI', get_template_directory_uri());
|
|
|
|
// Include admin options
|
|
require_once TECHBLOG_DIR . '/inc/admin-options.php';
|
|
|
|
/**
|
|
* Theme Setup
|
|
*/
|
|
function techblog_setup() {
|
|
// Add theme support
|
|
add_theme_support('title-tag');
|
|
add_theme_support('post-thumbnails');
|
|
add_theme_support('custom-logo', array(
|
|
'height' => 40,
|
|
'width' => 200,
|
|
'flex-height' => true,
|
|
'flex-width' => true,
|
|
));
|
|
add_theme_support('html5', array(
|
|
'search-form',
|
|
'comment-form',
|
|
'comment-list',
|
|
'gallery',
|
|
'caption',
|
|
'style',
|
|
'script',
|
|
));
|
|
add_theme_support('editor-styles');
|
|
add_theme_support('responsive-embeds');
|
|
add_theme_support('wp-block-styles');
|
|
|
|
// Register Navigation Menus
|
|
register_nav_menus(array(
|
|
'primary' => esc_html__('主导航菜单', 'techblog'),
|
|
'footer' => esc_html__('页脚菜单', 'techblog'),
|
|
));
|
|
|
|
// Set content width
|
|
if (!isset($content_width)) {
|
|
$content_width = 780;
|
|
}
|
|
}
|
|
add_action('after_setup_theme', 'techblog_setup');
|
|
|
|
/**
|
|
* Enqueue Styles and Scripts
|
|
*/
|
|
function techblog_scripts() {
|
|
// Google Fonts
|
|
wp_enqueue_style('techblog-fonts',
|
|
'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap',
|
|
array(),
|
|
null
|
|
);
|
|
|
|
// Main Stylesheet
|
|
wp_enqueue_style('techblog-style',
|
|
get_stylesheet_uri(),
|
|
array(),
|
|
TECHBLOG_VERSION
|
|
);
|
|
|
|
// Main JavaScript
|
|
wp_enqueue_script('techblog-main',
|
|
TECHBLOG_URI . '/js/main.js',
|
|
array(),
|
|
TECHBLOG_VERSION,
|
|
true
|
|
);
|
|
|
|
// Localize script
|
|
wp_localize_script('techblog-main', 'techblog', array(
|
|
'ajaxurl' => admin_url('admin-ajax.php'),
|
|
'nonce' => wp_create_nonce('techblog-nonce'),
|
|
));
|
|
}
|
|
add_action('wp_enqueue_scripts', 'techblog_scripts');
|
|
|
|
/**
|
|
* Register Sidebars
|
|
*/
|
|
function techblog_widgets_init() {
|
|
register_sidebar(array(
|
|
'name' => esc_html__('主侧边栏', 'techblog'),
|
|
'id' => 'sidebar-main',
|
|
'description' => esc_html__('文章页面右侧的侧边栏', 'techblog'),
|
|
'before_widget' => '<div id="%1$s" class="sidebar-widget %2$s">',
|
|
'after_widget' => '</div>',
|
|
'before_title' => '<h3 class="widget-title">',
|
|
'after_title' => '</h3>',
|
|
));
|
|
|
|
register_sidebar(array(
|
|
'name' => esc_html__('页脚栏 1', 'techblog'),
|
|
'id' => 'footer-1',
|
|
'description' => esc_html__('页脚第一列', 'techblog'),
|
|
'before_widget' => '<div id="%1$s" class="footer-section %2$s">',
|
|
'after_widget' => '</div>',
|
|
'before_title' => '<h3>',
|
|
'after_title' => '</h3>',
|
|
));
|
|
|
|
register_sidebar(array(
|
|
'name' => esc_html__('页脚栏 2', 'techblog'),
|
|
'id' => 'footer-2',
|
|
'description' => esc_html__('页脚第二列', 'techblog'),
|
|
'before_widget' => '<div id="%1$s" class="footer-section %2$s">',
|
|
'after_widget' => '</div>',
|
|
'before_title' => '<h3>',
|
|
'after_title' => '</h3>',
|
|
));
|
|
|
|
register_sidebar(array(
|
|
'name' => esc_html__('页脚栏 3', 'techblog'),
|
|
'id' => 'footer-3',
|
|
'description' => esc_html__('页脚第三列', 'techblog'),
|
|
'before_widget' => '<div id="%1$s" class="footer-section %2$s">',
|
|
'after_widget' => '</div>',
|
|
'before_title' => '<h3>',
|
|
'after_title' => '</h3>',
|
|
));
|
|
}
|
|
add_action('widgets_init', 'techblog_widgets_init');
|
|
|
|
/**
|
|
* Custom Excerpt Length
|
|
*/
|
|
function techblog_excerpt_length($length) {
|
|
return 25;
|
|
}
|
|
add_filter('excerpt_length', 'techblog_excerpt_length');
|
|
|
|
/**
|
|
* Custom Excerpt More
|
|
*/
|
|
function techblog_excerpt_more($more) {
|
|
return '...';
|
|
}
|
|
add_filter('excerpt_more', 'techblog_excerpt_more');
|
|
|
|
/**
|
|
* Add Code Language Class to Pre Tags
|
|
*/
|
|
function techblog_code_block_attributes($block_content, $block) {
|
|
if ($block['blockName'] === 'core/code') {
|
|
if (!empty($block['attrs']['language'])) {
|
|
$lang = esc_attr($block['attrs']['language']);
|
|
$block_content = str_replace(
|
|
'<pre class="wp-block-code',
|
|
'<pre class="wp-block-code lang-' . $lang,
|
|
$block_content
|
|
);
|
|
}
|
|
}
|
|
return $block_content;
|
|
}
|
|
add_filter('render_block', 'techblog_code_block_attributes', 10, 2);
|
|
|
|
/**
|
|
* Generate Table of Contents
|
|
*/
|
|
function techblog_generate_toc($content) {
|
|
if (!is_single()) {
|
|
return $content;
|
|
}
|
|
|
|
preg_match_all('/<h([2-3])[^>]*>(.*?)<\/h[2-3]>/is', $content, $matches, PREG_SET_ORDER);
|
|
|
|
if (count($matches) < 3) {
|
|
return $content;
|
|
}
|
|
|
|
$toc = '<div class="toc-container"><nav class="toc">';
|
|
$toc .= '<div class="toc-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6h16M4 12h16M4 18h16"/></svg> 目录</div>';
|
|
$toc .= '<ul class="toc-list">';
|
|
|
|
$headings = array();
|
|
|
|
foreach ($matches as $match) {
|
|
$level = $match[1];
|
|
$text = strip_tags($match[2]);
|
|
$id = sanitize_title($text);
|
|
$id = preg_replace('/[^a-z0-9\-]/', '', $id);
|
|
|
|
// Ensure unique IDs
|
|
if (in_array($id, $headings)) {
|
|
$id .= '-' . count($headings);
|
|
}
|
|
$headings[] = $id;
|
|
|
|
$class = $level == 3 ? ' class="toc-h3"' : '';
|
|
$toc .= '<li><a href="#' . esc_attr($id) . '"' . $class . '>' . esc_html($text) . '</a></li>';
|
|
|
|
// Add ID to heading in content
|
|
$content = str_replace(
|
|
$match[0],
|
|
'<h' . $level . ' id="' . esc_attr($id) . '">' . $match[2] . '</h' . $level . '>',
|
|
$content
|
|
);
|
|
}
|
|
|
|
$toc .= '</ul></nav></div>';
|
|
|
|
// Insert TOC after first paragraph or before first heading
|
|
$first_p = strpos($content, '</p>');
|
|
if ($first_p !== false) {
|
|
$content = substr($content, 0, $first_p + 4) . $toc . substr($content, $first_p + 4);
|
|
} else {
|
|
$content = $toc . $content;
|
|
}
|
|
|
|
return $content;
|
|
}
|
|
add_filter('the_content', 'techblog_generate_toc', 20);
|
|
|
|
/**
|
|
* Add Copy Button to Code Blocks
|
|
*/
|
|
function techblog_add_code_copy_button($content) {
|
|
if (!is_single() && !is_page()) {
|
|
return $content;
|
|
}
|
|
|
|
$content = preg_replace_callback(
|
|
'/<pre([^>]*)>(.*?)<\/pre>/is',
|
|
function($matches) {
|
|
$attrs = $matches[1];
|
|
$code = $matches[2];
|
|
|
|
// Extract language if present
|
|
$lang = '';
|
|
if (preg_match('/lang-([a-z0-9]+)/', $attrs, $lang_match)) {
|
|
$lang = strtoupper($lang_match[1]);
|
|
}
|
|
|
|
$header = '<div class="code-header">';
|
|
$header .= '<span class="code-lang">' . ($lang ?: 'CODE') . '</span>';
|
|
$header .= '<button class="copy-btn" onclick="copyCode(this)">';
|
|
$header .= '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>';
|
|
$header .= '复制</button></div>';
|
|
|
|
return '<pre' . $attrs . '>' . $header . $code . '</pre>';
|
|
},
|
|
$content
|
|
);
|
|
|
|
return $content;
|
|
}
|
|
add_filter('the_content', 'techblog_add_code_copy_button', 25);
|
|
|
|
/**
|
|
* Custom Walker for Navigation Menu
|
|
*/
|
|
class TechBlog_Nav_Walker extends Walker_Nav_Menu {
|
|
function start_el(&$output, $item, $depth = 0, $args = null, $id = 0) {
|
|
$classes = empty($item->classes) ? array() : (array) $item->classes;
|
|
$class = join(' ', array_filter($classes));
|
|
|
|
if (in_array('current-menu-item', $classes) || in_array('current_page_item', $classes)) {
|
|
$class .= ' current';
|
|
}
|
|
|
|
$output .= '<a href="' . esc_url($item->url) . '" class="' . esc_attr($class) . '">';
|
|
$output .= esc_html($item->title);
|
|
$output .= '</a>';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reading Time
|
|
*/
|
|
function techblog_reading_time() {
|
|
$content = get_the_content();
|
|
$word_count = str_word_count(strip_tags($content));
|
|
$reading_time = ceil($word_count / 200); // Average reading speed
|
|
return $reading_time;
|
|
}
|
|
|
|
/**
|
|
* Post Views (Simple implementation)
|
|
*/
|
|
function techblog_get_post_views() {
|
|
$count = get_post_meta(get_the_ID(), 'post_views', true);
|
|
return $count ? intval($count) : 0;
|
|
}
|
|
|
|
function techblog_set_post_views() {
|
|
if (!is_single()) return;
|
|
|
|
$post_id = get_the_ID();
|
|
$count = get_post_meta($post_id, 'post_views', true);
|
|
|
|
if ($count == '') {
|
|
$count = 0;
|
|
delete_post_meta($post_id, 'post_views');
|
|
add_post_meta($post_id, 'post_views', '0');
|
|
} else {
|
|
$count++;
|
|
update_post_meta($post_id, 'post_views', $count);
|
|
}
|
|
}
|
|
add_action('wp_head', 'techblog_set_post_views');
|
|
|
|
/**
|
|
* Format View Count
|
|
*/
|
|
function techblog_format_views($count) {
|
|
if ($count >= 10000) {
|
|
return round($count / 10000, 1) . 'w';
|
|
} elseif ($count >= 1000) {
|
|
return round($count / 1000, 1) . 'k';
|
|
}
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* Custom Comment Form
|
|
*/
|
|
function techblog_comment_form_defaults($defaults) {
|
|
$defaults['comment_notes_before'] = '';
|
|
$defaults['comment_field'] = '<div class="comment-form-field">
|
|
<textarea id="comment" name="comment" rows="5" required></textarea>
|
|
</div>';
|
|
return $defaults;
|
|
}
|
|
add_filter('comment_form_defaults', 'techblog_comment_form_defaults');
|
|
|
|
/**
|
|
* Theme Customizer
|
|
*/
|
|
function techblog_customize_register($wp_customize) {
|
|
// Hero Section
|
|
$wp_customize->add_section('techblog_hero', array(
|
|
'title' => esc_html__('首页横幅', 'techblog'),
|
|
'priority' => 30,
|
|
));
|
|
|
|
$wp_customize->add_setting('hero_title', array(
|
|
'default' => '探索技术世界',
|
|
'sanitize_callback' => 'sanitize_text_field',
|
|
));
|
|
$wp_customize->add_control('hero_title', array(
|
|
'label' => esc_html__('横幅标题', 'techblog'),
|
|
'section' => 'techblog_hero',
|
|
'type' => 'text',
|
|
));
|
|
|
|
$wp_customize->add_setting('hero_description', array(
|
|
'default' => '分享最新的IT技术、编程教程、系统运维经验',
|
|
'sanitize_callback' => 'sanitize_textarea_field',
|
|
));
|
|
$wp_customize->add_control('hero_description', array(
|
|
'label' => esc_html__('横幅描述', 'techblog'),
|
|
'section' => 'techblog_hero',
|
|
'type' => 'textarea',
|
|
));
|
|
|
|
// Social Links
|
|
$wp_customize->add_section('techblog_social', array(
|
|
'title' => esc_html__('社交媒体', 'techblog'),
|
|
'priority' => 35,
|
|
));
|
|
|
|
$social_platforms = array(
|
|
'github' => 'GitHub',
|
|
'twitter' => 'Twitter / X',
|
|
'gitee' => 'Gitee',
|
|
'email' => '邮箱',
|
|
);
|
|
|
|
foreach ($social_platforms as $key => $label) {
|
|
$wp_customize->add_setting('social_' . $key, array(
|
|
'default' => '',
|
|
'sanitize_callback' => 'esc_url_raw',
|
|
));
|
|
$wp_customize->add_control('social_' . $key, array(
|
|
'label' => $label,
|
|
'section' => 'techblog_social',
|
|
'type' => 'url',
|
|
));
|
|
}
|
|
}
|
|
add_action('customize_register', 'techblog_customize_register');
|
|
|
|
/**
|
|
* Custom Post Type for Projects (optional)
|
|
*/
|
|
function techblog_register_post_types() {
|
|
register_post_type('project', array(
|
|
'labels' => array(
|
|
'name' => esc_html__('项目', 'techblog'),
|
|
'singular_name' => esc_html__('项目', 'techblog'),
|
|
'add_new' => esc_html__('添加项目', 'techblog'),
|
|
'add_new_item' => esc_html__('添加新项目', 'techblog'),
|
|
'edit_item' => esc_html__('编辑项目', 'techblog'),
|
|
'all_items' => esc_html__('所有项目', 'techblog'),
|
|
'view_item' => esc_html__('查看项目', 'techblog'),
|
|
'search_items' => esc_html__('搜索项目', 'techblog'),
|
|
),
|
|
'public' => true,
|
|
'has_archive' => true,
|
|
'menu_icon' => 'dashicons-portfolio',
|
|
'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
|
|
'rewrite' => array('slug' => 'project'),
|
|
));
|
|
}
|
|
add_action('init', 'techblog_register_post_types');
|
|
|
|
/**
|
|
* AJAX Search
|
|
*/
|
|
function techblog_ajax_search() {
|
|
check_ajax_referer('techblog-nonce', 'nonce');
|
|
|
|
$search_term = sanitize_text_field($_POST['search']);
|
|
|
|
if (empty($search_term)) {
|
|
wp_send_json_error('请输入搜索关键词');
|
|
}
|
|
|
|
$query = new WP_Query(array(
|
|
's' => $search_term,
|
|
'posts_per_page' => 5,
|
|
'post_status' => 'publish',
|
|
));
|
|
|
|
$results = array();
|
|
|
|
if ($query->have_posts()) {
|
|
while ($query->have_posts()) {
|
|
$query->the_post();
|
|
$results[] = array(
|
|
'title' => get_the_title(),
|
|
'url' => get_the_permalink(),
|
|
'excerpt' => wp_trim_words(get_the_excerpt(), 20),
|
|
'date' => get_the_date('Y-m-d'),
|
|
);
|
|
}
|
|
}
|
|
|
|
wp_reset_postdata();
|
|
|
|
wp_send_json_success($results);
|
|
}
|
|
add_action('wp_ajax_techblog_search', 'techblog_ajax_search');
|
|
add_action('wp_ajax_nopriv_techblog_search', 'techblog_ajax_search');
|