九、插件开发

9.1 插件文件结构

my-plugin/
├── my-plugin.php                主插件文件(必须)
├── readme.txt                   插件说明(WordPress.org 要求)
├── uninstall.php                卸载脚本
├── includes/
│   ├── class-my-plugin.php      主类
│   ├── class-my-plugin-admin.php    后台类
│   └── class-my-plugin-frontend.php 前台类
├── admin/
│   ├── css/
│   ├── js/
│   └── views/
├── public/
│   ├── css/
│   ├── js/
│   └── views/
├── templates/
│   └── my-template.php
└── languages/
    └── my-plugin.pot

9.2 插件主文件

<?php
/**
 * Plugin Name:       My Custom Plugin
 * Plugin URI:        https://example.com/my-plugin
 * Description:       A custom WordPress plugin for demonstration.
 * Version:           1.0.0
 * Requires at least: 6.0
 * Requires PHP:      7.4
 * Author:            Your Name
 * Author URI:        https://example.com
 * License:           GPL v2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       my-plugin
 * Domain Path:       /languages
 */

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

// 常量定义
define('MY_PLUGIN_VERSION', '1.0.0');
define('MY_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('MY_PLUGIN_URL', plugin_dir_url(__FILE__));

// 激活钩子
register_activation_hook(__FILE__, 'my_plugin_activate');
function my_plugin_activate() {
    // 创建数据库表
    global $wpdb;
    $table_name = $wpdb->prefix . 'my_plugin_data';
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE $table_name (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        name varchar(100) NOT NULL,
        value text,
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id)
    ) $charset_collate;";

    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);

    // 设置默认选项
    add_option('my_plugin_settings', array(
        'enabled'      => true,
        'title'        => 'My Plugin',
        'items_per_page' => 10,
    ));

    // 设置默认选项
    flush_rewrite_rules();
}

// 停用钩子
register_deactivation_hook(__FILE__, 'my_plugin_deactivate');
function my_plugin_deactivate() {
    flush_rewrite_rules();
}

// 加载国际化
function my_plugin_load_textdomain() {
    load_plugin_textdomain('my-plugin', false, dirname(plugin_basename(__FILE__)) . '/languages');
}
add_action('init', 'my_plugin_load_textdomain');

// 加载后台脚本
function my_plugin_admin_scripts($hook) {
    if (strpos($hook, 'my-plugin') === false) {
        return;
    }

    wp_enqueue_style('my-plugin-admin', MY_PLUGIN_URL . 'admin/css/admin.css', array(), MY_PLUGIN_VERSION);
    wp_enqueue_script('my-plugin-admin', MY_PLUGIN_URL . 'admin/js/admin.js', array('jquery'), MY_PLUGIN_VERSION, true);

    wp_localize_script('my-plugin-admin', 'myPluginAdmin', array(
        'ajaxUrl' => admin_url('admin-ajax.php'),
        'nonce'   => wp_create_nonce('my_plugin_nonce'),
    ));
}
add_action('admin_enqueue_scripts', 'my_plugin_admin_scripts');

// 加载前台脚本
function my_plugin_frontend_scripts() {
    wp_enqueue_style('my-plugin-frontend', MY_PLUGIN_URL . 'public/css/frontend.css', array(), MY_PLUGIN_VERSION);
    wp_enqueue_script('my-plugin-frontend', MY_PLUGIN_URL . 'public/js/frontend.js', array(), MY_PLUGIN_VERSION, true);
}
add_action('wp_enqueue_scripts', 'my_plugin_frontend_scripts');

9.3 添加后台菜单页面

<?php
// 添加顶级菜单
function my_plugin_menu() {
    add_menu_page(
        'My Plugin',                 // 页面标题
        'My Plugin',                 // 菜单标题
        'manage_options',            // 权限
        'my-plugin',                 // Slug
        'my_plugin_settings_page',   // 回调函数
        'dashicons-admin-plugins',   // 图标
        80                           // 位置
    );

    // 添加子菜单
    add_submenu_page(
        'my-plugin',
        'Settings',
        'Settings',
        'manage_options',
        'my-plugin-settings',
        'my_plugin_settings_page'
    );

    add_submenu_page(
        'my-plugin',
        'Data',
        'Data',
        'manage_options',
        'my-plugin-data',
        'my_plugin_data_page'
    );

    // 隐藏重复的子菜单(第一个子菜单 = 顶级菜单)
    global $submenu;
    unset($submenu['my-plugin'][0]);
}
add_action('admin_menu', 'my_plugin_menu');

// 设置页面内容
function my_plugin_settings_page() {
    ?>
    <div class="wrap">
        <h1>My Plugin Settings</h1>
        <form method="post" action="options.php">
            <?php
            settings_fields('my_plugin_settings_group');
            do_settings_sections('my-plugin-settings');
            submit_button();
            ?>
        </form>
    </div>
    <?php
}

// 注册设置
function my_plugin_register_settings() {
    register_setting('my_plugin_settings_group', 'my_plugin_settings', array(
        'sanitize_callback' => 'my_plugin_sanitize_settings',
    ));

    add_settings_section(
        'my_plugin_general_section',
        'General Settings',
        'my_plugin_section_callback',
        'my-plugin-settings'
    );

    add_settings_field(
        'my_plugin_enabled',
        'Enable Plugin',
        'my_plugin_enabled_callback',
        'my-plugin-settings',
        'my_plugin_general_section'
    );

    add_settings_field(
        'my_plugin_title',
        'Plugin Title',
        'my_plugin_title_callback',
        'my-plugin-settings',
        'my_plugin_general_section'
    );
}
add_action('admin_init', 'my_plugin_register_settings');

// 字段回调
function my_plugin_enabled_callback() {
    $options = get_option('my_plugin_settings');
    ?>
    <input type="checkbox" name="my_plugin_settings[enabled]" value="1" <?php checked(1, $options['enabled'] ?? 0); ?>>
    <?php
}

function my_plugin_title_callback() {
    $options = get_option('my_plugin_settings');
    ?>
    <input type="text" name="my_plugin_settings[title]" value="<?php echo esc_attr($options['title'] ?? ''); ?>" class="regular-text">
    <?php
}

// 清理回调
function my_plugin_sanitize_settings($input) {
    $sanitized = array();
    $sanitized['enabled'] = !empty($input['enabled']) ? 1 : 0;
    $sanitized['title'] = sanitize_text_field($input['title'] ?? '');
    return $sanitized;
}

9.4 AJAX 处理

<?php
// AJAX 处理(登录用户)
function my_plugin_ajax_handler() {
    // 验证 nonce
    if (!wp_verify_nonce($_POST['nonce'] ?? '', 'my_plugin_nonce')) {
        wp_send_json_error('Security check failed');
    }

    // 验证权限
    if (!current_user_can('manage_options')) {
        wp_send_json_error('Permission denied');
    }

    $action_type = sanitize_text_field($_POST['action_type'] ?? '');

    switch ($action_type) {
        case 'save_data':
            $name = sanitize_text_field($_POST['name'] ?? '');
            $value = sanitize_textarea_field($_POST['value'] ?? '');

            global $wpdb;
            $result = $wpdb->insert($wpdb->prefix . 'my_plugin_data', array(
                'name'  => $name,
                'value' => $value,
            ));

            if ($result) {
                wp_send_json_success(array('message' => 'Data saved successfully'));
            } else {
                wp_send_json_error('Failed to save data');
            }
            break;

        case 'get_data':
            global $wpdb;
            $data = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}my_plugin_data ORDER BY created_at DESC LIMIT 10");
            wp_send_json_success($data);
            break;

        default:
            wp_send_json_error('Unknown action');
    }
}
add_action('wp_ajax_my_plugin_action', 'my_plugin_ajax_handler');

// AJAX 处理(未登录用户)
// add_action('wp_ajax_nopriv_my_plugin_action', 'my_plugin_ajax_handler');

前端 AJAX 调用(JavaScript):

jQuery(document).ready(function($) {
    // 保存数据
    $.ajax({
        url: myPluginAdmin.ajaxUrl,
        type: 'POST',
        data: {
            action: 'my_plugin_action',
            nonce: myPluginAdmin.nonce,
            action_type: 'save_data',
            name: 'test',
            value: 'test value'
        },
        success: function(response) {
            if (response.success) {
                console.log(response.data.message);
            }
        }
    });
});

十、WordPress 钩子系统

10.1 Action(动作钩子)

// 添加动作
add_action('hook_name', 'callback_function', $priority, $accepted_args);

// 示例:在页面底部添加内容
function my_custom_footer_content() {
    echo '<p>Powered by My Theme</p>';
}
add_action('wp_footer', 'my_custom_footer_content');

// 常用 Action 钩子
// init                  WordPress 初始化后(加载主题/插件后)
// wp_loaded             所有内容加载完成后
// template_redirect     模板加载前
// wp_head               <head> 标签内
// wp_footer             </body> 标签前
// wp_body_open          <body> 标签打开后
// after_setup_theme     主题设置后
// wp_enqueue_scripts    前台脚本加载
// admin_enqueue_scripts 后台脚本加载
// save_post             保存文章后
// publish_post          发布文章后
// delete_post           删除文章后
// user_register         用户注册后
// wp_login              用户登录后
// wp_logout             用户登出后
// comment_post          发表评论后
// switch_theme          切换主题后
// admin_menu            添加后台菜单
// widgets_init          注册小工具

10.2 Filter(过滤器钩子)

// 添加过滤器
add_filter('hook_name', 'callback_function', $priority, $accepted_args);

// 示例:修改文章标题
function my_custom_title($title) {
    if (is_single()) {
        $title = $title . ' - My Blog';
    }
    return $title;
}
add_filter('the_title', 'my_custom_title');

// 示例:修改摘要长度
function my_excerpt_length($length) {
    return 50;
}
add_filter('excerpt_length', 'my_excerpt_length', 999);

// 常用 Filter 钩子
// the_title             文章标题
// the_content           文章内容
// the_excerpt           文章摘要
// excerpt_length        摘要长度
// excerpt_more          摘要后缀
// wp_title              页面标题
// body_class            body 类名
// post_class            文章类名
// upload_mimes          允许上传的文件类型
// login_redirect        登录后跳转
// wp_mail_from          邮件发送者
// wp_mail_from_name     邮件发送者名称
// comment_text          评论内容
// wp_nav_menu_items     菜单项 HTML
// widget_display_callback 小工具显示
// the_editor            编辑器内容
// query_vars            查询变量
// cron_schedules        自定义 cron 间隔

10.3 自定义钩子

// 自定义 Action
do_action('my_custom_action', $arg1, $arg2);

// 其他代码中使用
add_action('my_custom_action', 'my_callback_function', 10, 2);
function my_callback_function($arg1, $arg2) {
    // 处理逻辑
}

// 自定义 Filter
$value = apply_filters('my_custom_filter', $original_value, $arg1);

// 其他代码中使用
add_filter('my_custom_filter', 'my_filter_function', 10, 2);
function my_filter_function($value, $arg1) {
    return $value . ' modified';
}

十一、REST API 二次开发

11.1 WordPress 内置 REST API

# 基础端点
GET /wp-json/                         # API 信息
GET /wp-json/wp/v2/posts              # 获取文章列表
GET /wp-json/wp/v2/posts/{id}         # 获取单篇文章
GET /wp-json/wp/v2/pages              # 获取页面
GET /wp-json/wp/v2/categories         # 获取分类
GET /wp-json/wp/v2/tags               # 获取标签
GET /wp-json/wp/v2/users              # 获取用户(需权限)
GET /wp-json/wp/v2/media              # 获取媒体
GET /wp-json/wp/v2/comments           # 获取评论
GET /wp-json/wp/v2/settings           # 获取设置(需权限)

# 带参数查询
GET /wp-json/wp/v2/posts?per_page=5&page=1
GET /wp-json/wp/v2/posts?search=keyword
GET /wp-json/wp/v2/posts?categories=1,2
GET /wp-json/wp/v2/posts?orderby=date&order=desc
GET /wp-json/wp/v2/posts?author=1

# 使用 curl 测试
curl https://example.com/wp-json/wp/v2/posts
curl https://example.com/wp-json/wp/v2/posts?per_page=3

11.2 注册自定义 REST API 端点

<?php
// 注册自定义端点
function my_plugin_register_rest_routes() {
    register_rest_route('my-plugin/v1', '/data', array(
        'methods'             => 'GET',
        'callback'            => 'my_plugin_get_data',
        'permission_callback' => 'my_plugin_check_permission',
        'args'                => array(
            'per_page' => array(
                'default'           => 10,
                'sanitize_callback' => 'absint',
            ),
            'page' => array(
                'default'           => 1,
                'sanitize_callback' => 'absint',
            ),
        ),
    ));

    register_rest_route('my-plugin/v1', '/data', array(
        'methods'             => 'POST',
        'callback'            => 'my_plugin_create_data',
        'permission_callback' => 'my_plugin_check_permission',
    ));

    register_rest_route('my-plugin/v1', '/data/(?P<id>\d+)', array(
        'methods'             => 'PUT',
        'callback'            => 'my_plugin_update_data',
        'permission_callback' => 'my_plugin_check_permission',
    ));

    register_rest_route('my-plugin/v1', '/data/(?P<id>\d+)', array(
        'methods'             => 'DELETE',
        'callback'            => 'my_plugin_delete_data',
        'permission_callback' => 'my_plugin_check_permission',
    ));
}
add_action('rest_api_init', 'my_plugin_register_rest_routes');

// 权限检查
function my_plugin_check_permission($request) {
    return current_user_can('edit_posts');
}

// GET - 获取数据
function my_plugin_get_data($request) {
    global $wpdb;
    $per_page = $request->get_param('per_page');
    $page = $request->get_param('page');
    $offset = ($page - 1) * $per_page;

    $data = $wpdb->get_results($wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}my_plugin_data LIMIT %d OFFSET %d",
        $per_page, $offset
    ));

    $total = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}my_plugin_data");

    return new WP_REST_Response(array(
        'data'       => $data,
        'total'      => (int) $total,
        'page'       => (int) $page,
        'per_page'   => (int) $per_page,
        'total_pages' => ceil($total / $per_page),
    ), 200);
}

// POST - 创建数据
function my_plugin_create_data($request) {
    global $wpdb;

    $name = sanitize_text_field($request->get_param('name'));
    $value = sanitize_textarea_field($request->get_param('value'));

    $result = $wpdb->insert($wpdb->prefix . 'my_plugin_data', array(
        'name'  => $name,
        'value' => $value,
    ));

    if ($result) {
        return new WP_REST_Response(array(
            'id'      => $wpdb->insert_id,
            'message' => 'Created successfully',
        ), 201);
    }

    return new WP_REST_Response(array('message' => 'Failed to create'), 500);
}

// PUT - 更新数据
function my_plugin_update_data($request) {
    global $wpdb;
    $id = $request->get_param('id');

    $result = $wpdb->update(
        $wpdb->prefix . 'my_plugin_data',
        array(
            'name'  => sanitize_text_field($request->get_param('name')),
            'value' => sanitize_textarea_field($request->get_param('value')),
        ),
        array('id' => $id)
    );

    return new WP_REST_Response(array('message' => 'Updated successfully'), 200);
}

// DELETE - 删除数据
function my_plugin_delete_data($request) {
    global $wpdb;
    $id = $request->get_param('id');

    $result = $wpdb->delete($wpdb->prefix . 'my_plugin_data', array('id' => $id));

    return new WP_REST_Response(array('message' => 'Deleted successfully'), 200);
}

11.3 修改现有 REST API

<?php
// 修改文章 API 返回的字段
function my_plugin_modify_post_response($response, $post) {
    $data = $response->get_data();
    $data['custom_field'] = get_post_meta($post->ID, 'custom_field', true);
    $data['reading_time'] = ceil(str_word_count(strip_tags($post->post_content)) / 200) . ' min';
    $response->set_data($data);
    return $response;
}
add_filter('rest_prepare_post', 'my_plugin_modify_post_response', 10, 2);

// 注册自定义文章字段
function my_plugin_register_post_meta() {
    register_post_meta('post', 'custom_field', array(
        'show_in_rest'  => true,
        'single'        => true,
        'type'          => 'string',
        'auth_callback' => function() {
            return current_user_can('edit_posts');
        },
    ));
}
add_action('init', 'my_plugin_register_post_meta');

十二、性能优化

12.1 缓存策略

# 1. 页面缓存(WP Rocket / W3 Total Cache / LiteSpeed Cache)
# 2. 浏览器缓存(Nginx/Apache 配置)
# 3. 对象缓存(Redis / Memcached)
# 4. CDN(Cloudflare / 阿里云 CDN / 腾讯云 CDN)

Nginx 浏览器缓存配置:

location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg|webp)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
    access_log off;
}

Redis 对象缓存:

# 安装 Redis
sudo apt install -y redis-server php-redis

# WordPress 安装 Redis Object Cache 插件
# 或手动配置 drop-in 文件

# wp-content/object-cache.php(Redis Object Cache 插件会自动创建)

12.2 数据库优化

-- 查看数据库大小
SELECT
    table_name,
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb
FROM information_schema.tables
WHERE table_schema = 'wordpress'
ORDER BY (data_length + index_length) DESC;

-- 清理文章修订版本
DELETE FROM wp_posts WHERE post_type = 'revision';

-- 清理自动草稿
DELETE FROM wp_posts WHERE post_status = 'auto-draft';

-- 清理回收站文章
DELETE FROM wp_posts WHERE post_status = 'trash';

-- 清理垃圾评论
DELETE FROM wp_comments WHERE comment_approved = 'spam';

-- 清理过期的临时数据
DELETE FROM wp_options WHERE option_name LIKE '_transient_%' AND option_value < UNIX_TIMESTAMP() - 86400;

-- 清理过期的临时数据(二)
DELETE FROM wp_options WHERE option_name LIKE '_site_transient_%' AND option_value < UNIX_TIMESTAMP() - 86400;

-- 优化表
OPTIMIZE TABLE wp_posts;
OPTIMIZE TABLE wp_postmeta;
OPTIMIZE TABLE wp_options;
OPTIMIZE TABLE wp_comments;
OPTIMIZE TABLE wp_commentmeta;

12.3 PHP 优化

# php.ini 优化
sudo nano /etc/php/8.1/fpm/php.ini

# 内存
memory_limit = 256M

# 上传
upload_max_filesize = 64M
post_max_size = 64M

# 执行时间
max_execution_time = 300
max_input_time = 300

# OPcache(重要!生产环境必须开启)
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60
opcache.save_comments = 1

# 重启 PHP
sudo systemctl restart php8.1-fpm

12.4 图片优化

1. 上传前压缩
   - TinyPNG / Squoosh / ImageOptim
   - 目标:每张图 < 200KB

2. 使用 WebP 格式
   - 插件:ShortPixel / Imagify / Converter for Media
   - 手动转换:cwebp input.png -o output.webp

3. 懒加载(Lazy Load)
   - WordPress 5.5+ 内置
   - 插件:WP Rocket / a3 Lazy Load

4. 响应式图片
   - WordPress 自动添加 srcset

5. 图片 CDN
   - Cloudflare / 阿里云 OSS + CDN

12.5 其他优化

// functions.php 中添加优化代码

// 1. 禁用 Emoji 脚本(不需要时)
function disable_emoji() {
    remove_action('wp_head', 'print_emoji_detection_script', 7);
    remove_action('wp_print_styles', 'print_emoji_styles');
}
add_action('init', 'disable_emoji');

// 2. 移除不必要的头部信息
remove_action('wp_head', 'wp_generator');           // WordPress 版本号
remove_action('wp_head', 'wlwmanifest_link');       // Windows Live Writer
remove_action('wp_head', 'rsd_link');               // RSD
remove_action('wp_head', 'wp_shortlink_wp_head');   // 短链接

// 3. 禁用 XML-RPC(减少攻击面)
add_filter('xmlrpc_enabled', '__return_false');

// 4. 移除查询字符串
function remove_query_strings($src) {
    if (strpos($src, '?ver=')) {
        $src = remove_query_arg('ver', $src);
    }
    return $src;
}
add_filter('style_loader_src', 'remove_query_strings');
add_filter('script_loader_src', 'remove_query_strings');

// 5. 限制修订版本数量
define('WP_POST_REVISIONS', 3);

// 6. 禁用文章自动保存
define('AUTOSAVE_INTERVAL', 300);   // 5 分钟

// 7. 禁用文章版本控制(极端情况)
// define('WP_POST_REVISIONS', false);

十三、安全加固

13.1 基本安全措施

// wp-config.php 安全配置

// 禁用文件编辑器
define('DISALLOW_FILE_EDIT', true);

// 禁用插件和主题安装(生产环境)
// define('DISALLOW_FILE_MODS', true);

// 强制 SSL(后台)
define('FORCE_SSL_ADMIN', true);

// 自动更新
define('WP_AUTO_UPDATE_CORE', 'minor');   // 仅小版本更新

// 文件系统
define('FS_METHOD', 'direct');

13.2 文件权限

# 正确的文件权限
# 目录:755
# 文件:644
# wp-config.php:600(更安全)
# .htaccess:644

find /var/www/wordpress -type d -exec chmod 755 {} \;
find /var/www/wordpress -type f -exec chmod 644 {} \;
chmod 600 /var/www/wordpress/wp-config.php

# 文件所有者
chown -R www-data:www-data /var/www/wordpress   # Debian/Ubuntu
# chown -R nginx:nginx /var/www/wordpress       # CentOS/Nginx

13.3 敏感文件保护

Nginx:

# 禁止访问敏感文件
location ~* /\.ht {
    deny all;
}
location = /wp-config.php {
    deny all;
}
location = /xmlrpc.php {
    deny all;
}
location ~* /wp-content/debug\.log {
    deny all;
}
location ~* /readme\.html {
    deny all;
}
location ~* /license\.txt {
    deny all;
}

Apache(.htaccess):

# 保护 wp-config.php
<Files wp-config.php>
    Order Allow,Deny
    Deny from all
</Files>

# 禁止目录浏览
Options -Indexes

# 保护 .htaccess
<Files .htaccess>
    Order Allow,Deny
    Deny from all
</Files>

# 禁止 XML-RPC
<Files xmlrpc.php>
    Order Allow,Deny
    Deny from all
</Files>

13.4 登录安全

// 1. 修改登录 URL(插件:WPS Hide Login)
// 默认:/wp-admin / wp-login.php
// 修改后:/my-secret-login

// 2. 限制登录尝试(插件:Limit Login Attempts Reloaded)
// 或手动添加代码

// 3. 双因素认证(插件:WP 2FA / Google Authenticator)

// 4. 添加登录验证码
function my_login_captcha() {
    ?>
    <p>
        <label for="captcha">What is 3 + 4?</label><br>
        <input type="text" name="captcha" id="captcha" class="input" required>
    </p>
    <?php
}
add_action('login_form', 'my_login_captcha');

function my_verify_login_captcha($user, $password) {
    $answer = $_POST['captcha'] ?? '';
    if ($answer != '7') {
        return new WP_Error('captcha_error', 'Incorrect captcha answer.');
    }
    return $user;
}
add_filter('authenticate', 'my_verify_login_captcha', 20, 3);

13.5 安全插件

推荐安全插件组合:
├── Wordfence Security       防火墙 + 恶意软件扫描
├── Limit Login Attempts     限制登录尝试
├── Really Simple SSL        SSL 管理
├── UpdraftPlus              备份
└── WP Activity Log          活动日志

13.6 日常安全检查

# 1. 保持 WordPress、主题、插件最新
# 2. 删除不使用的主题和插件
# 3. 定期备份数据库和文件
# 4. 使用强密码(12+ 字符)
# 5. 限制用户权限(最小权限原则)
# 6. 启用 HTTPS
# 7. 禁用文件编辑器
# 8. 定期安全扫描
# 9. 监控登录日志
# 10. 使用 Web 应用防火墙(WAF)

十四、SEO 优化

14.1 基本 SEO 设置

1. 固定链接设置(设置 → 固定链接)
   推荐:/post-name/ 或 /category/post-name/

2. 站点标题和描述(设置 → 常规)
   标题:包含关键词
   描述:简洁描述站点内容

3. 设置首页(设置 → 阅读)
   静态页面 or 最新文章

4. 搜索引擎可见性
   开发时勾选"阻止搜索引擎"
   上线后取消勾选

5. SSL 证书(HTTPS)
   HTTPS 是 Google 排名因素

14.2 SEO 插件配置(Yoast SEO)

Yoast SEO 设置:
├── 常规
│   ├── 站点标题模板
│   ├── 分隔符(- | ~)
│   └── 知识图谱设置
├── 搜索外观
│   ├── 首页标题和描述
│   ├── 文章类型(标题模板、描述模板)
│   ├── 分类和标签
│   └── 面包屑导航
├── 社交
│   ├── Facebook / Twitter
│   ├── Open Graph 元标签
│   └── 社交图片
├── 站点地图(Sitemap)
│   ├── 自动生成 XML Sitemap
│   └── 包含/排除内容类型
├── 高级
│   ├── 面包屑导航
│   ├── 永久链接清理
│   └── RSS 优化
└── 工具
    ├── 导入/导出设置
    └── 文件编辑器

14.3 页面级 SEO 优化

每篇文章/页面的 SEO 设置:
├── SEO 标题(Title Tag)
│   格式:关键词 - 站点名称
│   长度:50-60 字符
│
├── Meta 描述(Description)
│   包含关键词
│   吸引点击
│   长度:150-160 字符
│
├── URL 别名(Slug)
│   简短、包含关键词
│   使用连字符分隔
│   避免中文 URL
│
├── 焦点关键词(Focus Keyphrase)
│   主要目标关键词
│   检查关键词密度
│
├── 内容优化
│   标题层级(H1-H6)
│   关键词自然分布
│   内部链接
│   外部链接(权威来源)
│   图片 alt 标签
│   文章长度(1500+ 字)
│
├── 特色图片
│   包含关键词的文件名
│   适当尺寸(1200x630)
│   alt 标签
│
└── Schema 标记(结构化数据)
    文章、面包屑、FAQ、评论等

14.4 技术 SEO

# 1. XML Sitemap
# Yoast SEO 自动生成:https://example.com/sitemap_index.xml

# 2. robots.txt
# https://example.com/robots.txt
User-agent: *
Disallow: /wp-admin/
Disallow: /wp-includes/
Allow: /wp-admin/admin-ajax.php
Sitemap: https://example.com/sitemap_index.xml

# 3. 301 重定向
# 插件:Redirection
# 或 Nginx:
# location /old-url/ {
#     return 301 /new-url/;
# }

# 4. 面包屑导航
# Yoast SEO 内置支持

# 5. 页面速度
# Google PageSpeed Insights: https://pagespeed.web.dev
# 目标:移动端 ≥ 80,桌面端 ≥ 90

# 6. 移动端适配
# 响应式设计
# Google Mobile-Friendly Test

# 7. Core Web Vitals
# LCP(最大内容绘制)< 2.5s
# FID(首次输入延迟)< 100ms
# CLS(累积布局偏移)< 0.1

十五、多站点管理

15.1 开启多站点

// wp-config.php 中添加
define('WP_ALLOW_MULTISITE', true);
后台 → 工具 → 网络安装:
1. 选择子域名或子目录
2. 填写网络标题和管理员邮箱
3. 点击"安装"

然后按照提示将代码添加到 wp-config.php 和 .htaccess

15.2 多站点管理

/wp-admin/network/    网络管理后台

功能:
├── 站点管理
│   ├── 添加新站点
│   ├── 编辑站点
│   ├── 删除站点
│   └── 站点列表
├── 用户管理
│   ├── 网络级用户
│   ├── 站点级用户
│   └── 超级管理员
├── 主题管理
│   ├── 网络启用主题
│   └── 站点可选主题
├── 插件管理
│   ├── 网络启用插件
│   └── 站点可选插件
├── 设置
│   ├── 网络设置
│   ├── 注册设置
│   └── 上传设置
└── 更新
    ├── WordPress 核心
    ├── 主题
    └── 插件

十六、数据库管理

16.1 核心数据表

wp_options             站点设置选项
wp_posts               文章、页面、附件、修订版本
wp_postmeta            文章自定义字段
wp_users               用户信息
wp_usermeta            用户自定义字段
wp_comments            评论
wp_commentmeta         评论自定义字段
wp_terms               分类/标签
wp_term_taxonomy       分类法
wp_term_relationships  分类关系
wp_termmeta            分类自定义字段
wp_links               链接(旧版功能)

16.2 常用 SQL 操作

-- 查看所有选项
SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes';

-- 修改站点 URL
UPDATE wp_options SET option_value = 'https://new-domain.com' WHERE option_name = 'siteurl';
UPDATE wp_options SET option_value = 'https://new-domain.com' WHERE option_name = 'home';

-- 修改管理员密码
UPDATE wp_users SET user_pass = MD5('newpassword') WHERE user_login = 'admin';
-- 注意:WordPress 使用 phpass,建议通过后台修改

-- 禁用所有插件
UPDATE wp_options SET option_value = 'a:0:{}' WHERE option_name = 'active_plugins';

-- 修改主题
UPDATE wp_options SET option_value = 'twentytwentyfour' WHERE option_name = 'template';
UPDATE wp_options SET option_value = 'twentytwentyfour' WHERE option_name = 'stylesheet';

-- 修改固定链接(/post-name/)
UPDATE wp_options SET option_value = '/%postname%/' WHERE option_name = 'permalink_structure';

-- 查看文章和自定义字段
SELECT p.ID, p.post_title, p.post_status, pm.meta_key, pm.meta_value
FROM wp_posts p
LEFT JOIN wp_postmeta pm ON p.ID = pm.post_id
WHERE p.post_type = 'post' AND p.post_status = 'publish'
ORDER BY p.post_date DESC;

-- 批量替换 URL(域名迁移)
UPDATE wp_options SET option_value = REPLACE(option_value, 'http://old.com', 'https://new.com') WHERE option_name = 'siteurl' OR option_name = 'home';
UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://old.com', 'https://new.com');
UPDATE wp_posts SET guid = REPLACE(guid, 'http://old.com', 'https://new.com');
UPDATE wp_postmeta SET meta_value = REPLACE(meta_value, 'http://old.com', 'https://new.com');

16.3 数据库备份与恢复

# 备份
mysqldump -u root -p wordpress > wordpress_backup.sql
mysqldump -u root -p --all-databases > all_backup.sql

# 压缩备份
mysqldump -u root -p wordpress | gzip > wordpress_backup.sql.gz

# 恢复
mysql -u root -p wordpress < wordpress_backup.sql
gunzip -c wordpress_backup.sql.gz | mysql -u root -p wordpress

# 定时备份(crontab)
# 0 2 * * * mysqldump -u root -p'password' wordpress | gzip > /backup/wordpress_$(date +\%Y\%m\%d).sql.gz

十七、Docker 部署

17.1 Docker Compose 配置

# docker-compose.yml
version: '3.8'

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress
    restart: always
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: YourStrongPassword123!
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_TABLE_PREFIX: wp_
      WORDPRESS_DEBUG: "false"
    volumes:
      - wordpress_data:/var/www/html
      - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
    depends_on:
      - db

  db:
    image: mysql:8.0
    container_name: wordpress-db
    restart: always
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: YourStrongPassword123!
      MYSQL_ROOT_PASSWORD: RootPassword123!
    volumes:
      - db_data:/var/lib/mysql
    command: --default-authentication-plugin=mysql_native_password

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: phpmyadmin
    restart: always
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
      PMA_PORT: 3306
    depends_on:
      - db

  redis:
    image: redis:7-alpine
    container_name: wordpress-redis
    restart: always
    volumes:
      - redis_data:/data

volumes:
  wordpress_data:
  db_data:
  redis_data:

PHP 上传配置(uploads.ini):

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 300
# 启动
docker compose up -d

# 查看状态
docker compose ps

# 查看日志
docker compose logs -f wordpress

# 进入容器
docker exec -it wordpress bash

# 停止
docker compose down

# 停止并删除数据卷
docker compose down -v

17.2 Nginx + Docker(反向代理)

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 300;
    }

    client_max_body_size 64M;
}

十八、常用 WP-CLI 命令

18.1 安装 WP-CLI

# 下载
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar

# 移动到 PATH
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp

# 验证
wp --info

18.2 核心命令

# WordPress 核心
wp core download                          # 下载 WordPress
wp core install                           # 安装 WordPress
wp core update                            # 更新 WordPress
wp core version                           # 查看版本

# 安装 WordPress
wp core install --url="https://example.com" \
    --title="My Site" \
    --admin_user="admin" \
    --admin_password="StrongPass123!" \
    --admin_email="admin@example.com" \
    --locale="zh_CN" \
    --skip-email

# 数据库
wp db create                              # 创建数据库
wp db export backup.sql                   # 导出数据库
wp db import backup.sql                   # 导入数据库
wp db optimize                            # 优化数据库
wp db repair                              # 修复数据库
wp search-replace 'old.com' 'new.com'     # 批量替换

# 文章
wp post list                              # 列出文章
wp post create --post_title="Hello" --post_content="World" --post_status=publish
wp post update 1 --post_title="New Title"
wp post delete 1 --force
wp post generate --count=10               # 生成测试文章

# 页面
wp post list --post_type=page

# 用户
wp user list                              # 列出用户
wp user create username email@example.com --role=author --user_pass="password"
wp user update 1 --user_pass="newpassword"
wp user delete 2 --reassign=1
wp user generate --count=5                # 生成测试用户

# 主题
wp theme list                             # 列出主题
wp theme install theme-name --activate    # 安装并激活
wp theme activate theme-name              # 激活
wp theme delete theme-name                # 删除

# 插件
wp plugin list                            # 列出插件
wp plugin install plugin-name --activate  # 安装并激活
wp plugin activate plugin-name            # 激活
wp plugin deactivate plugin-name          # 停用
wp plugin deactivate --all                # 停用所有
wp plugin delete plugin-name              # 删除
wp plugin update --all                    # 更新所有插件

# 选项(设置)
wp option get siteurl                     # 获取站点 URL
wp option update blogname "New Title"     # 修改站点标题
wp option list                            # 列出所有选项

# 分类/标签
wp term list category                     # 列出分类
wp term create category "News"            # 创建分类

# 媒体
wp media import image.jpg                 # 导入图片

# 转储缓存
wp cache flush                            # 清除缓存
wp rewrite flush                          # 刷新固定链接

# 评估
wp eval 'echo get_bloginfo("name");'      # 执行 PHP 代码
wp shell                                  # 交互式 PHP Shell

# 检查
wp doctor check                           # 站点健康检查
wp healthcheck                            # 健康检查

十九、故障排查

19.1 白屏(White Screen of Death)

// 1. 开启调试模式
// wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

// 查看日志
tail -f /var/www/wordpress/wp-content/debug.log

// 2. 禁用所有插件(通过数据库)
mysql -u root -p wordpress -e "UPDATE wp_options SET option_value='a:0:{}' WHERE option_name='active_plugins';"

// 3. 切换默认主题(通过数据库)
mysql -u root -p wordpress -e "UPDATE wp_options SET option_value='twentytwentyfour' WHERE option_name='template';"
mysql -u root -p wordpress -e "UPDATE wp_options SET option_value='twentytwentyfour' WHERE option_name='stylesheet';"

// 4. 检查 PHP 内存限制
// php.ini 或 wp-config.php
define('WP_MEMORY_LIMIT', '256M');

// 5. 重新上传 WordPress 核心文件
wp core download --force

19.2 500 Internal Server Error

# 1. 检查错误日志
tail -f /var/log/nginx/error.log
tail -f /var/log/apache2/error.log

# 2. 检查 .htaccess(Apache)
# 备份后删除 .htaccess,看是否恢复
mv .htaccess .htaccess.bak

# 3. 检查 PHP 版本兼容性
php -v

# 4. 检查文件权限
find /var/www/wordpress -type d -exec chmod 755 {} \;
find /var/www/wordpress -type f -exec chmod 644 {} \;

# 5. 增加 PHP 内存和执行时间
# php.ini:
# memory_limit = 256M
# max_execution_time = 300

19.3 数据库连接错误

// "建立数据库连接时出错"

// 1. 检查 wp-config.php 中的数据库信息
define('DB_NAME', 'wordpress');
define('DB_USER', 'wpuser');
define('DB_PASSWORD', 'password');
define('DB_HOST', 'localhost');

// 2. 检查 MySQL 服务
sudo systemctl status mysql
sudo systemctl restart mysql

// 3. 检查数据库用户权限
mysql -u root -p -e "SHOW GRANTS FOR 'wpuser'@'localhost';"

// 4. 测试数据库连接
mysql -u wpuser -p'password' wordpress -e "SELECT 1;"

19.4 固定链接不工作(404 错误)

# Apache
# 确保 mod_rewrite 已启用
sudo a2enmod rewrite
sudo systemctl restart apache2

# 确保 AllowOverride All
# <Directory /var/www/wordpress>
#     AllowOverride All
# </Directory>

# Nginx
# 确保配置中有:
# location / {
#     try_files $uri $uri/ /index.php?$args;
# }

# 重新保存固定链接
# 后台 → 设置 → 固定链接 → 直接点击"保存更改"

# WP-CLI
wp rewrite flush

19.5 上传文件失败

# 1. 检查 PHP 上传限制
# php.ini:
# upload_max_filesize = 64M
# post_max_size = 64M

# 2. 检查目录权限
chmod -R 755 /var/www/wordpress/wp-content/uploads
chown -R www-data:www-data /var/www/wordpress/wp-content/uploads

# 3. 检查磁盘空间
df -h

# 4. 检查 SELinux(CentOS)
sudo chcon -R -t httpd_sys_rw_content_t /var/www/wordpress/wp-content/uploads/

19.6 网站速度慢

排查步骤:
1. 测试页面速度(PageSpeed Insights / GTmetrix)
2. 检查服务器负载(top / htop)
3. 检查数据库查询(Query Monitor 插件)
4. 检查 PHP 版本(建议 8.1+)
5. 启用缓存(WP Rocket / W3 Total Cache)
6. 启用 OPcache
7. 优化图片
8. 使用 CDN
9. 减少插件数量
10. 优化数据库

19.7 常见错误速查

错误 可能原因 解决方案
白屏 PHP 错误 / 内存不足 开启 WP_DEBUG,禁用插件
500 Error .htaccess / PHP 错误 检查 .htaccess,查看错误日志
数据库连接错误 配置错误 / MySQL 未启动 检查 wp-config.php,重启 MySQL
404 错误 固定链接 / .htaccess 重新保存固定链接
上传失败 上传限制 / 权限 修改 php.ini,检查权限
内存不足 PHP 内存限制 增加 WP_MEMORY_LIMIT
重定向循环 SSL 配置 / 缓存 检查 HTTPS 设置,清除缓存
更新失败 文件权限 / 磁盘空间 修复权限,检查磁盘
邮件不发送 服务器 SMTP 安装 WP Mail SMTP 插件

二十、完整实战示例

20.1 一键部署脚本

#!/bin/bash
# deploy_wordpress.sh
set -e

DOMAIN="example.com"
DB_NAME="wordpress"
DB_USER="wpuser"
DB_PASS=$(openssl rand -base64 24)
WP_DIR="/var/www/wordpress"
ADMIN_USER="admin"
ADMIN_PASS=$(openssl rand -base64 16)
ADMIN_EMAIL="admin@example.com"

echo "=== WordPress 一键部署 ==="

# 1. 安装 LAMP/LNMP
echo "[1/7] 安装环境..."
apt update && apt install -y nginx php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip php-intl mysql-server certbot python3-certbot-nginx

# 2. 创建数据库
echo "[2/7] 创建数据库..."
mysql -u root -p -e "
CREATE DATABASE IF NOT EXISTS $DB_NAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';
GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';
FLUSH PRIVILEGES;
"

# 3. 下载 WordPress
echo "[3/7] 下载 WordPress..."
cd /var/www
wget -q https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
chown -R www-data:www-data $WP_DIR

# 4. 配置 wp-config.php
echo "[4/7] 配置 WordPress..."
cd $WP_DIR
cp wp-config-sample.php wp-config.php

# 生成密钥
SALTS=$(curl -s https://api.wordpress.org/secret-key/1.1/salt/)

cat > wp-config.php << EOF
<?php
define('DB_NAME', '$DB_NAME');
define('DB_USER', '$DB_USER');
define('DB_PASSWORD', '$DB_PASS');
define('DB_HOST', 'localhost');
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', 'utf8mb4_unicode_ci');

$SALTS

\$table_prefix = 'wp_';
define('WP_DEBUG', false);
define('WP_MEMORY_LIMIT', '256M');
define('DISALLOW_FILE_EDIT', true);
define('WP_AUTO_UPDATE_CORE', 'minor');
define('FS_METHOD', 'direct');

if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', __DIR__ . '/' );
}
require_once ABSPATH . 'wp-settings.php';
EOF

# 5. 配置 Nginx
echo "[5/7] 配置 Nginx..."
cat > /etc/nginx/sites-available/wordpress << EOF
server {
    listen 80;
    server_name $DOMAIN www.$DOMAIN;
    root $WP_DIR;
    index index.php;

    client_max_body_size 64M;

    location / {
        try_files \$uri \$uri/ /index.php?\$args;
    }

    location ~ \.php\$ {
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_read_timeout 300;
    }

    location ~* /\.ht { deny all; }
    location = /wp-config.php { deny all; }
    location = /xmlrpc.php { deny all; }

    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg)\$ {
        expires 30d;
        access_log off;
    }
}
EOF

ln -sf /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

# 6. 安装 WordPress
echo "[6/7] 安装 WordPress..."
cd $WP_DIR
wp core install \
    --url="http://$DOMAIN" \
    --title="$DOMAIN" \
    --admin_user="$ADMIN_USER" \
    --admin_password="$ADMIN_PASS" \
    --admin_email="$ADMIN_EMAIL" \
    --locale="zh_CN" \
    --skip-email \
    --allow-root

# 7. 基本配置
echo "[7/7] 基本配置..."
wp option update permalink_structure '/%postname%/' --allow-root
wp rewrite flush --allow-root
wp plugin install akismet --activate --allow-root
wp plugin install wordpress-seo --activate --allow-root
wp theme install generatepress --activate --allow-root

echo ""
echo "=== 部署完成 ==="
echo "站点地址: http://$DOMAIN"
echo "后台地址: http://$DOMAIN/wp-admin"
echo "管理员:   $ADMIN_USER"
echo "密码:     $ADMIN_PASS"
echo "数据库:   $DB_NAME"
echo "DB 用户:  $DB_USER"
echo "DB 密码:  $DB_PASS"
echo ""
echo "请立即登录后台并修改密码!"
echo "下一步:配置 SSL(sudo certbot --nginx -d $DOMAIN)"

20.2 自定义短代码插件

<?php
/**
 * Plugin Name: My Shortcodes
 * Description: 自定义短代码集合
 * Version: 1.0.0
 * Author: Your Name
 * Text Domain: my-shortcodes
 */

if (!defined('ABSPATH')) exit;

// 按钮短代码 [my_button url="#" text="点击这里" color="blue" size="large"]
function my_button_shortcode($atts) {
    $atts = shortcode_atts(array(
        'url'   => '#',
        'text'  => 'Click Here',
        'color' => 'blue',
        'size'  => 'medium',
        'target' => '_self',
    ), $atts, 'my_button');

    return sprintf(
        '<a href="%s" class="my-btn my-btn-%s my-btn-%s" target="%s">%s</a>',
        esc_url($atts['url']),
        esc_attr($atts['color']),
        esc_attr($atts['size']),
        esc_attr($atts['target']),
        esc_html($atts['text'])
    );
}
add_shortcode('my_button', 'my_button_shortcode');

// 信息框短代码 [my_alert type="info" title="提示"]内容[/my_alert]
function my_alert_shortcode($atts, $content = null) {
    $atts = shortcode_atts(array(
        'type'  => 'info',
        'title' => '',
    ), $atts, 'my_alert');

    $types = array('info', 'success', 'warning', 'error');
    $type = in_array($atts['type'], $types) ? $atts['type'] : 'info';

    $html = '<div class="my-alert my-alert-' . esc_attr($type) . '">';
    if (!empty($atts['title'])) {
        $html .= '<strong>' . esc_html($atts['title']) . '</strong>';
    }
    $html .= '<p>' . wp_kses_post(do_shortcode($content)) . '</p>';
    $html .= '</div>';

    return $html;
}
add_shortcode('my_alert', 'my_alert_shortcode');

// 文章列表短代码 [my_posts category="news" count="5" layout="grid"]
function my_posts_shortcode($atts) {
    $atts = shortcode_atts(array(
        'category' => '',
        'count'    => 5,
        'layout'   => 'list',
    ), $atts, 'my_posts');

    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => intval($atts['count']),
        'orderby'        => 'date',
        'order'          => 'DESC',
    );

    if (!empty($atts['category'])) {
        $args['category_name'] = sanitize_text_field($atts['category']);
    }

    $query = new WP_Query($args);
    $html = '<div class="my-posts my-posts-' . esc_attr($atts['layout']) . '">';

    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            $html .= '<div class="my-post-item">';
            $html .= '<h3><a href="' . get_permalink() . '">' . get_the_title() . '</a></h3>';
            $html .= '<p>' . get_the_excerpt() . '</p>';
            $html .= '<span class="date">' . get_the_date() . '</span>';
            $html .= '</div>';
        }
    } else {
        $html .= '<p>暂无文章</p>';
    }

    $html .= '</div>';
    wp_reset_postdata();

    return $html;
}
add_shortcode('my_posts', 'my_posts_shortcode');

// 加载短代码样式
function my_shortcodes_styles() {
    wp_enqueue_style('my-shortcodes', plugin_dir_url(__FILE__) . 'assets/css/shortcodes.css', array(), '1.0.0');
}
add_action('wp_enqueue_scripts', 'my_shortcodes_styles');

20.3 自定义文章类型插件

<?php
/**
 * Plugin Name: My Custom Post Types
 * Description: 注册自定义文章类型和分类法
 * Version: 1.0.0
 */

if (!defined('ABSPATH')) exit;

// 注册自定义文章类型
function my_register_post_types() {

    // 作品集(Portfolio)
    register_post_type('portfolio', array(
        'labels' => array(
            'name'               => '作品集',
            'singular_name'      => '作品',
            'add_new'            => '添加作品',
            'add_new_item'       => '添加新作品',
            'edit_item'          => '编辑作品',
            'new_item'           => '新作品',
            'view_item'          => '查看作品',
            'search_items'       => '搜索作品',
            'not_found'          => '未找到作品',
            'not_found_in_trash' => '回收站中无作品',
        ),
        'public'          => true,
        'has_archive'     => true,
        'rewrite'         => array('slug' => 'portfolio'),
        'menu_icon'       => 'dashicons-portfolio',
        'supports'        => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields', 'comments'),
        'show_in_rest'    => true,
        'capability_type' => 'post',
    ));

    // 产品(Product)
    register_post_type('product', array(
        'labels' => array(
            'name'          => '产品',
            'singular_name' => '产品',
            'add_new'       => '添加产品',
            'edit_item'     => '编辑产品',
        ),
        'public'       => true,
        'has_archive'  => true,
        'rewrite'      => array('slug' => 'product'),
        'menu_icon'    => 'dashicons-cart',
        'supports'     => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
        'show_in_rest' => true,
    ));
}
add_action('init', 'my_register_post_types');

// 注册自定义分类法
function my_register_taxonomies() {

    // 作品分类
    register_taxonomy('portfolio_category', 'portfolio', array(
        'labels' => array(
            'name'          => '作品分类',
            'singular_name' => '作品分类',
            'add_new_item'  => '添加作品分类',
        ),
        'hierarchical'      => true,
        'rewrite'           => array('slug' => 'portfolio-category'),
        'show_admin_column' => true,
        'show_in_rest'      => true,
    ));

    // 产品标签
    register_taxonomy('product_tag', 'product', array(
        'labels' => array(
            'name'          => '产品标签',
            'singular_name' => '产品标签',
        ),
        'hierarchical'      => false,
        'rewrite'           => array('slug' => 'product-tag'),
        'show_admin_column' => true,
        'show_in_rest'      => true,
    ));
}
add_action('init', 'my_register_taxonomies');

// 注册自定义元数据
function my_register_meta() {
    register_post_meta('portfolio', 'project_url', array(
        'show_in_rest'  => true,
        'single'        => true,
        'type'          => 'string',
        'auth_callback' => function() { return current_user_can('edit_posts'); },
    ));

    register_post_meta('portfolio', 'client_name', array(
        'show_in_rest'  => true,
        'single'        => true,
        'type'          => 'string',
        'auth_callback' => function() { return current_user_can('edit_posts'); },
    ));

    register_post_meta('product', 'price', array(
        'show_in_rest'  => true,
        'single'        => true,
        'type'          => 'string',
        'auth_callback' => function() { return current_user_can('edit_posts'); },
    ));

    register_post_meta('product', 'sku', array(
        'show_in_rest'  => true,
        'single'        => true,
        'type'          => 'string',
        'auth_callback' => function() { return current_user_can('edit_posts'); },
    ));
}
add_action('init', 'my_register_meta');

附录 A:常用函数速查

函数 说明
get_header() 加载 header.php
get_footer() 加载 footer.php
get_sidebar() 加载 sidebar.php
get_template_part('content') 加载 template-parts/content.php
wp_head() 在 中输出
wp_footer() 在 前输出
wp_enqueue_style() 加载 CSS
wp_enqueue_script() 加载 JS
wp_nav_menu() 输出导航菜单
dynamic_sidebar() 输出侧边栏
is_active_sidebar() 判断侧边栏是否有小工具
register_nav_menus() 注册导航菜单位置
register_sidebar() 注册侧边栏
add_theme_support() 添加主题支持
add_image_size() 添加自定义图片尺寸
the_post_thumbnail() 输出特色图片
get_the_date() 获取发布日期
get_permalink() 获取文章链接
home_url('/') 获取首页 URL
admin_url('/') 获取后台 URL
get_option() 获取选项值
update_option() 更新选项值
get_post_meta() 获取自定义字段
update_post_meta() 更新自定义字段
wp_redirect() 302 跳转
wp_safe_redirect() 安全跳转
esc_html() HTML 转义
esc_attr() 属性转义
esc_url() URL 转义
sanitize_text_field() 清理文本
sanitize_email() 清理邮箱
current_user_can() 检查用户权限
wp_create_nonce() 创建安全令牌
wp_verify_nonce() 验证安全令牌

附录 B:推荐学习资源

书籍

书名 作者 方向
《Professional WordPress》 Brad Williams WordPress 开发
《WordPress 插件开发》 Brad Williams 插件开发
《WordPress 主题开发》 Tessa Blakeley Silver 主题开发
《WordPress 入门到精通》 国内多位作者 中文入门

在线资源

资源 网址 说明
WordPress 官方文档 https://developer.wordpress.org 开发者文档
WordPress Codex https://codex.wordpress.org 经典文档
WP Tavern https://wptavern.com WordPress 新闻
WPBeginner https://www.wpbeginner.com 新手教程
Smashing Magazine https://www.smashingmagazine.com 设计与开发
WordPress TV https://wordpress.tv 视频教程
GitHub WordPress https://github.com/WordPress 官方源码
GeneratePress https://generatepress.com 主题参考
Elementor https://elementor.com 页面构建器

总结: WordPress 从入门到精通的核心路径是:先掌握后台管理 → 学会使用主题和插件 → 深入主题开发 → 学习插件开发 → 理解钩子系统 → 掌握 REST API → 优化性能和安全。WordPress 的生态系统极其丰富,无论是零代码建站还是深度开发,都能满足需求。持续学习官方文档、关注社区动态、多做项目实践,你将快速成为 WordPress 高手。

转载请注明出处