纯代码WordPress高级幻灯片功能

纯代码WordPress高级幻灯片功能的完整实现。它不依赖任何插件,通过自定义文章类型、特色图像和短码,在后台创建幻灯片组,并在前台生成带缩略图导航的响应式轮播。

<?php
/**
 * Plugin Name: 高级幻灯片功能 (纯代码)
 * Description: 通过自定义文章类型实现幻灯片组管理,支持分组、缩略图导航、响应式布局。无插件依赖。
 * Version:     1.0.0
 * Author:      Code Craftsman
 * Text Domain: advanced-slider
 */

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

class Advanced_WP_Slider {

    private static $instance = null;

    // 幻灯片文章类型的名称
    const SLIDER_CPT = 'awp_slide';
    // 幻灯片分组分类法
    const SLIDER_GROUP_TAX = 'slider_group';

    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        $this->init_hooks();
    }

    private function init_hooks() {
        // 注册自定义文章类型和分类法
        add_action('init', array($this, 'register_slide_post_type'));
        add_action('init', array($this, 'register_slider_group_taxonomy'));

        // 添加自定义元数据框 (图片链接、描述、按钮文字等)
        add_action('add_meta_boxes', array($this, 'add_slide_meta_boxes'));
        add_action('save_post_' . self::SLIDER_CPT, array($this, 'save_slide_meta'));

        // 修改“特色图像”提示,鼓励用户上传幻灯片图片
        add_filter('admin_post_thumbnail_html', array($this, 'custom_thumbnail_html'), 10, 2);

        // 在列表页添加幻灯片组列
        add_filter('manage_' . self::SLIDER_CPT . '_posts_columns', array($this, 'add_slider_group_column'));
        add_action('manage_' . self::SLIDER_CPT . '_posts_custom_column', array($this, 'show_slider_group_column'), 10, 2);

        // 注册短码 [awp_slider group="组别名"]
        add_shortcode('awp_slider', array($this, 'render_slider_shortcode'));

        // 前端资源:CSS/JS (仅在需要时加载)
        add_action('wp_enqueue_scripts', array($this, 'register_slider_assets'));
    }

    // 1. 注册自定义文章类型:幻灯片
    public function register_slide_post_type() {
        $labels = array(
            'name'               => __('幻灯片', 'advanced-slider'),
            'singular_name'      => __('幻灯片项', 'advanced-slider'),
            'add_new'            => __('添加新幻灯片', 'advanced-slider'),
            'add_new_item'       => __('新建幻灯片项', 'advanced-slider'),
            'edit_item'          => __('编辑幻灯片', 'advanced-slider'),
            'new_item'           => __('新幻灯片', 'advanced-slider'),
            'view_item'          => __('查看幻灯片', 'advanced-slider'),
            'search_items'       => __('搜索幻灯片', 'advanced-slider'),
            'not_found'          => __('未找到幻灯片', 'advanced-slider'),
            'not_found_in_trash' => __('回收站中没有幻灯片', 'advanced-slider'),
        );
        $args = array(
            'labels'              => $labels,
            'public'              => false,
            'publicly_queryable'  => false,
            'show_ui'             => true,
            'show_in_menu'        => true,
            'query_var'           => false,
            'rewrite'             => false,
            'capability_type'     => 'post',
            'has_archive'         => false,
            'hierarchical'        => false,
            'menu_position'       => 20,
            'menu_icon'           => 'dashicons-images-alt2',
            'supports'            => array('title', 'thumbnail', 'page-attributes'),
        );
        register_post_type(self::SLIDER_CPT, $args);
    }

    // 2. 注册分类法:幻灯片组 (用于区分不同位置的轮播)
    public function register_slider_group_taxonomy() {
        $labels = array(
            'name'              => __('幻灯片组', 'advanced-slider'),
            'singular_name'     => __('组', 'advanced-slider'),
            'search_items'      => __('搜索组', 'advanced-slider'),
            'all_items'         => __('所有组', 'advanced-slider'),
            'parent_item'       => __('父级组', 'advanced-slider'),
            'parent_item_colon' => __('父级组:', 'advanced-slider'),
            'edit_item'         => __('编辑组', 'advanced-slider'),
            'update_item'       => __('更新组', 'advanced-slider'),
            'add_new_item'      => __('新增组', 'advanced-slider'),
            'new_item_name'     => __('新组名称', 'advanced-slider'),
            'menu_name'         => __('分组', 'advanced-slider'),
        );
        $args = array(
            'hierarchical'      => true,
            'labels'            => $labels,
            'show_ui'           => true,
            'show_admin_column' => true,
            'query_var'         => false,
            'rewrite'           => false,
        );
        register_taxonomy(self::SLIDER_GROUP_TAX, self::SLIDER_CPT, $args);
    }

    // 3. 添加幻灯片专用元数据框:链接URL,描述文本,按钮文字
    public function add_slide_meta_boxes() {
        add_meta_box(
            'awp_slide_details',
            __('幻灯片详细信息', 'advanced-slider'),
            array($this, 'render_slide_meta_box'),
            self::SLIDER_CPT,
            'normal',
            'high'
        );
    }

    public function render_slide_meta_box($post) {
        wp_nonce_field('awp_slide_meta_nonce', 'awp_slide_meta_nonce');
        $slide_url = get_post_meta($post->ID, '_awp_slide_url', true);
        $slide_desc = get_post_meta($post->ID, '_awp_slide_description', true);
        $slide_btn_text = get_post_meta($post->ID, '_awp_slide_button_text', true);
        ?>
        <p>
            <label for="awp_slide_url"><?php _e('链接地址 (URL)', 'advanced-slider'); ?>:</label><br/>
            <input type="url" name="awp_slide_url" id="awp_slide_url" value="<?php echo esc_url($slide_url); ?>" style="width: 100%;" placeholder="https://..."/>
        </p>
        <p>
            <label for="awp_slide_description"><?php _e('幻灯片描述 (可选,显示在图片上)', 'advanced-slider'); ?>:</label><br/>
            <textarea name="awp_slide_description" id="awp_slide_description" rows="3" style="width: 100%;"><?php echo esc_textarea($slide_desc); ?></textarea>
        </p>
        <p>
            <label for="awp_slide_button_text"><?php _e('按钮文字 (可选,与链接配合)', 'advanced-slider'); ?>:</label><br/>
            <input type="text" name="awp_slide_button_text" id="awp_slide_button_text" value="<?php echo esc_attr($slide_btn_text); ?>" style="width: 50%;" placeholder="了解更多"/>
        </p>
        <p class="description"><?php _e('提示:主图片使用“特色图像”设置。建议图片尺寸: 1920x800 或比例 2.4:1', 'advanced-slider'); ?></p>
        <?php
    }

    public function save_slide_meta($post_id) {
        if (!isset($_POST['awp_slide_meta_nonce']) || !wp_verify_nonce($_POST['awp_slide_meta_nonce'], 'awp_slide_meta_nonce')) {
            return;
        }
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }
        if (!current_user_can('edit_post', $post_id)) {
            return;
        }
        if (isset($_POST['awp_slide_url'])) {
            update_post_meta($post_id, '_awp_slide_url', esc_url_raw($_POST['awp_slide_url']));
        }
        if (isset($_POST['awp_slide_description'])) {
            update_post_meta($post_id, '_awp_slide_description', sanitize_textarea_field($_POST['awp_slide_description']));
        }
        if (isset($_POST['awp_slide_button_text'])) {
            update_post_meta($post_id, '_awp_slide_button_text', sanitize_text_field($_POST['awp_slide_button_text']));
        }
    }

    // 强化特色图像提示
    public function custom_thumbnail_html($content, $post_id) {
        if (get_post_type($post_id) === self::SLIDER_CPT) {
            $content .= '<p><strong>' . __('幻灯片主图像:用于轮播展示。', 'advanced-slider') . '</strong></p>';
        }
        return $content;
    }

    // 在列表页快速查看所属组
    public function add_slider_group_column($columns) {
        $columns['slider_group'] = __('幻灯片组', 'advanced-slider');
        return $columns;
    }

    public function show_slider_group_column($column, $post_id) {
        if ($column === 'slider_group') {
            $terms = get_the_terms($post_id, self::SLIDER_GROUP_TAX);
            if (!empty($terms) && !is_wp_error($terms)) {
                $out = array();
                foreach ($terms as $term) {
                    $out[] = sprintf('<a href="%s">%s</a>',
                        esc_url(add_query_arg(array('slider_group' => $term->slug), admin_url('edit.php?post_type=' . self::SLIDER_CPT))),
                        esc_html($term->name)
                    );
                }
                echo implode(', ', $out);
            } else {
                echo '—';
            }
        }
    }

    // 注册前端脚本样式 (按需在短码中延迟加载)
    public function register_slider_assets() {
        wp_register_style('awp-slider-style', false, array(), '1.0.0');
        wp_add_inline_style('awp-slider-style', $this->get_slider_css());
        
        wp_register_script('awp-slider-script', false, array(), '1.0.0', true);
        wp_add_inline_script('awp-slider-script', $this->get_slider_js());
    }

    // 获取前端 CSS (纯代码嵌入)
    private function get_slider_css() {
        return '
        .awp-slider-container {
            position: relative;
            width: 100%;
            overflow: hidden;
            margin-bottom: 2rem;
            background: #f5f5f5;
        }
        .awp-slider-wrapper {
            position: relative;
            width: 100%;
        }
        .awp-slider-slides {
            display: flex;
            transition: transform 0.5s ease-in-out;
            margin: 0;
            padding: 0;
            list-style: none;
        }
        .awp-slider-slide {
            flex: 0 0 100%;
            position: relative;
        }
        .awp-slider-slide img {
            width: 100%;
            height: auto;
            display: block;
            object-fit: cover;
            max-height: 600px;
        }
        .awp-slider-caption {
            position: absolute;
            bottom: 20%;
            left: 10%;
            right: 10%;
            background: rgba(0,0,0,0.6);
            color: #fff;
            padding: 20px 30px;
            border-radius: 8px;
            text-align: center;
            max-width: 80%;
            margin: 0 auto;
            box-sizing: border-box;
        }
        .awp-slider-caption h3 {
            margin: 0 0 10px;
            font-size: 2rem;
            color: #fff;
        }
        .awp-slider-caption p {
            margin: 0 0 15px;
            font-size: 1rem;
        }
        .awp-slider-btn {
            display: inline-block;
            background: #007cba;
            color: #fff;
            padding: 10px 25px;
            text-decoration: none;
            border-radius: 4px;
            transition: background 0.3s;
        }
        .awp-slider-btn:hover {
            background: #005a87;
            color: #fff;
        }
        .awp-slider-nav {
            position: absolute;
            bottom: 20px;
            left: 0;
            right: 0;
            text-align: center;
            z-index: 10;
        }
        .awp-slider-dot {
            display: inline-block;
            width: 12px;
            height: 12px;
            background: rgba(255,255,255,0.5);
            border-radius: 50%;
            margin: 0 5px;
            cursor: pointer;
            transition: background 0.3s;
        }
        .awp-slider-dot.active {
            background: #007cba;
        }
        .awp-slider-arrow {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            background: rgba(0,0,0,0.5);
            color: white;
            padding: 12px 18px;
            cursor: pointer;
            font-size: 24px;
            font-weight: bold;
            z-index: 10;
            user-select: none;
            border-radius: 50%;
            width: 48px;
            text-align: center;
            line-height: 1;
        }
        .awp-slider-arrow.prev { left: 20px; }
        .awp-slider-arrow.next { right: 20px; }
        .awp-slider-arrow:hover {
            background: rgba(0,0,0,0.8);
        }
        @media (max-width: 768px) {
            .awp-slider-caption { bottom: 10%; padding: 12px 20px; }
            .awp-slider-caption h3 { font-size: 1.2rem; }
            .awp-slider-arrow { padding: 6px 12px; font-size: 18px; width: 36px; }
        }
        ';
    }

    // 获取前端 JS (纯代码)
    private function get_slider_js() {
        return '
        (function() {
            var sliders = document.querySelectorAll(".awp-slider-container");
            sliders.forEach(function(container) {
                var slidesContainer = container.querySelector(".awp-slider-slides");
                var slides = container.querySelectorAll(".awp-slider-slide");
                var prevBtn = container.querySelector(".awp-slider-arrow.prev");
                var nextBtn = container.querySelector(".awp-slider-arrow.next");
                var dotsContainer = container.querySelector(".awp-slider-nav");
                var total = slides.length;
                if (total === 0) return;
                var currentIndex = 0;
                var autoplayInterval = null;
                var autoplayDelay = parseInt(container.dataset.autoplay) || 5000;
                
                function updateSlider() {
                    if (slidesContainer) {
                        slidesContainer.style.transform = "translateX(-" + (currentIndex * 100) + "%)";
                    }
                    if (dotsContainer) {
                        var dots = dotsContainer.querySelectorAll(".awp-slider-dot");
                        dots.forEach(function(dot, idx) {
                            if (idx === currentIndex) dot.classList.add("active");
                            else dot.classList.remove("active");
                        });
                    }
                }
                
                function goToSlide(index) {
                    if (index < 0) index = total - 1;
                    if (index >= total) index = 0;
                    currentIndex = index;
                    updateSlider();
                    resetAutoplay();
                }
                
                function nextSlide() { goToSlide(currentIndex + 1); }
                function prevSlide() { goToSlide(currentIndex - 1); }
                
                function resetAutoplay() {
                    if (autoplayInterval) clearInterval(autoplayInterval);
                    if (autoplayDelay > 0 && total > 1) {
                        autoplayInterval = setInterval(nextSlide, autoplayDelay);
                    }
                }
                
                if (prevBtn) prevBtn.addEventListener("click", function(e) { e.preventDefault(); prevSlide(); });
                if (nextBtn) nextBtn.addEventListener("click", function(e) { e.preventDefault(); nextSlide(); });
                
                if (dotsContainer && total > 1) {
                    var dotHtml = "";
                    for (var i = 0; i < total; i++) {
                        dotHtml += "<span class=\"awp-slider-dot\" data-index=\"" + i + "\"></span>";
                    }
                    dotsContainer.innerHTML = dotHtml;
                    var dots = dotsContainer.querySelectorAll(".awp-slider-dot");
                    dots.forEach(function(dot) {
                        dot.addEventListener("click", function() {
                            var idx = parseInt(this.dataset.index);
                            goToSlide(idx);
                        });
                    });
                }
                
                // 启动自动播放
                if (total > 1 && autoplayDelay > 0) {
                    resetAutoplay();
                }
                // 鼠标悬停暂停
                container.addEventListener("mouseenter", function() {
                    if (autoplayInterval) clearInterval(autoplayInterval);
                });
                container.addEventListener("mouseleave", function() {
                    if (total > 1 && autoplayDelay > 0) resetAutoplay();
                });
                updateSlider();
            });
        })();
        ';
    }

    // 短码渲染主逻辑
    public function render_slider_shortcode($atts) {
        $atts = shortcode_atts(array(
            'group' => '',
            'autoplay' => '5000',   // 毫秒,0表示关闭自动播放
            'show_caption' => '1',
            'show_nav' => '1',
        ), $atts, 'awp_slider');

        if (empty($atts['group'])) {
            return '<p style="color:red;">' . __('错误:请指定幻灯片组名,例如 [awp_slider group="homepage"]', 'advanced-slider') . '</p>';
        }

        // 查询幻灯片,按 menu_order 排序 (支持拖拽顺序)
        $slides = get_posts(array(
            'post_type'      => self::SLIDER_CPT,
            'posts_per_page' => -1,
            'orderby'        => 'menu_order',
            'order'          => 'ASC',
            'tax_query'      => array(
                array(
                    'taxonomy' => self::SLIDER_GROUP_TAX,
                    'field'    => 'slug',
                    'terms'    => sanitize_title($atts['group']),
                )
            )
        ));

        if (empty($slides)) {
            return '<p>' . sprintf(__('幻灯片组 “%s” 暂无内容,请添加幻灯片并分配组。', 'advanced-slider'), esc_html($atts['group'])) . '</p>';
        }

        // 确保前端资源已输出
        wp_enqueue_style('awp-slider-style');
        wp_enqueue_script('awp-slider-script');

        ob_start();
        $container_id = 'awp-slider-' . md5($atts['group'] . rand());
        $autoplay_val = intval($atts['autoplay']) > 0 ? intval($atts['autoplay']) : 0;
        ?>
        <div id="<?php echo esc_attr($container_id); ?>" class="awp-slider-container" data-autoplay="<?php echo $autoplay_val; ?>">
            <div class="awp-slider-wrapper">
                <ul class="awp-slider-slides">
                    <?php foreach ($slides as $slide) : 
                        $thumb_id = get_post_thumbnail_id($slide->ID);
                        $img_url = $thumb_id ? wp_get_attachment_image_url($thumb_id, 'large') : '';
                        if (empty($img_url)) {
                            $img_url = 'https://via.placeholder.com/1920x800?text=No+Image';
                        }
                        $slide_url = get_post_meta($slide->ID, '_awp_slide_url', true);
                        $desc = get_post_meta($slide->ID, '_awp_slide_description', true);
                        $btn_text = get_post_meta($slide->ID, '_awp_slide_button_text', true);
                        $title = esc_html($slide->post_title);
                    ?>
                    <li class="awp-slider-slide">
                        <?php if ($slide_url) : ?><a href="<?php echo esc_url($slide_url); ?>" title="<?php echo $title; ?>"><?php endif; ?>
                            <img src="<?php echo esc_url($img_url); ?>" alt="<?php echo $title; ?>">
                        <?php if ($slide_url) : ?></a><?php endif; ?>
                        
                        <?php if ($atts['show_caption'] == '1' && ($desc || $btn_text)) : ?>
                        <div class="awp-slider-caption">
                            <h3><?php echo $title; ?></h3>
                            <?php if ($desc) : ?><p><?php echo nl2br(esc_html($desc)); ?></p><?php endif; ?>
                            <?php if ($btn_text && $slide_url) : ?>
                                <a href="<?php echo esc_url($slide_url); ?>" class="awp-slider-btn"><?php echo esc_html($btn_text); ?></a>
                            <?php endif; ?>
                        </div>
                        <?php endif; ?>
                    </li>
                    <?php endforeach; ?>
                </ul>
                <?php if ($atts['show_nav'] == '1' && count($slides) > 1) : ?>
                <div class="awp-slider-arrow prev">&#10094;</div>
                <div class="awp-slider-arrow next">&#10095;</div>
                <div class="awp-slider-nav"></div>
                <?php endif; ?>
            </div>
        </div>
        <?php
        return ob_get_clean();
    }
}

// 初始化插件
Advanced_WP_Slider::get_instance();

幻灯片功能使用指南

创建并管理您的幻灯片组,然后在任何页面通过短码调用。

第一步:创建幻灯片组和内容

  1. 在WordPress后台,您会看到新增的“幻灯片”菜单。先点击“分组”创建一个新组,例如命名为 homepage
  2. 点击“添加新幻灯片”,为每张幻灯片填写标题、上传特色图像(主图),并可选填链接地址、描述文字和按钮文字。在右侧“分组”中勾选您刚创建的组。
  3. 通过“页面属性”中的“顺序”字段,可以拖拽或数字设定幻灯片的显示顺序。

第二步:在前台显示幻灯片

  • 使用短码 [awp_slider group="homepage"] 即可在文章、页面或主题模板中调用该组幻灯片。
  • 支持的自定义参数示例:
    • [awp_slider group="homepage" autoplay="3000" show_caption="1" show_nav="1"]
      • autoplay:自动切换间隔(毫秒),设为 0 可关闭自动播放。
      • show_caption:显示或隐藏描述与按钮(1 显示,0 隐藏)。
      • show_nav:显示或隐藏箭头与点导航。