WordPress幻灯片功能的完整代码实现

WordPress幻灯片功能的完整代码实现。它创建了一个自定义帖子类型“幻灯片”,左侧大图轮播,右侧小图垂直滚动,所有图片数量、推荐和置顶状态均在后台可设。

<?php
/**
 * Plugin Name: 高级幻灯片功能
 * Description: 左侧大图轮播 + 右侧小图垂直滚动,支持后台管理图片、推荐和置顶
 * Version: 1.0
 * Author: Your Name
 */

// 安全起见,防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

class AdvancedSlider {

    public function __construct() {
        add_action('init', array($this, 'register_slider_post_type'));
        add_action('add_meta_boxes', array($this, 'add_slider_meta_boxes'));
        add_action('save_post', array($this, 'save_slider_meta'));
        add_shortcode('advanced_slider', array($this, 'render_slider_shortcode'));
        add_action('wp_enqueue_scripts', array($this, 'enqueue_slider_assets'));
        
        // 添加图片上传相关钩子
        add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
    }

    // 注册自定义文章类型
    public function register_slider_post_type() {
        $labels = array(
            'name'               => '幻灯片',
            'singular_name'      => '幻灯片项目',
            'menu_name'          => '高级幻灯片',
            'add_new'            => '添加新幻灯片',
            'add_new_item'       => '添加新幻灯片项目',
            'edit_item'          => '编辑幻灯片项目',
            'new_item'           => '新幻灯片项目',
            'view_item'          => '查看幻灯片项目',
            'search_items'       => '搜索幻灯片',
            'not_found'          => '未找到幻灯片',
            'not_found_in_trash' => '回收站中没有幻灯片',
        );

        $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'),
        );

        register_post_type('slider_item', $args);
    }

    // 添加元数据框
    public function add_slider_meta_boxes() {
        add_meta_box(
            'slider_settings',
            '幻灯片设置',
            array($this, 'render_slider_meta_box'),
            'slider_item',
            'normal',
            'high'
        );
    }

    // 渲染元数据框
    public function render_slider_meta_box($post) {
        wp_nonce_field('slider_meta_box', 'slider_meta_box_nonce');

        $image_url = get_post_meta($post->ID, '_slider_image_url', true);
        $link_url = get_post_meta($post->ID, '_slider_link_url', true);
        $is_sticky = get_post_meta($post->ID, '_slider_sticky', true);
        $is_featured = get_post_meta($post->ID, '_slider_featured', true);
        $slide_text = get_post_meta($post->ID, '_slider_text', true);
        $slide_order = get_post_meta($post->ID, '_slider_order', true);
        ?>
        <style>
            .slider-meta-field {
                margin-bottom: 15px;
            }
            .slider-meta-field label {
                display: inline-block;
                width: 120px;
                font-weight: bold;
                vertical-align: top;
            }
            .slider-meta-field input[type="text"],
            .slider-meta-field textarea {
                width: 70%;
            }
            .slider-image-preview {
                margin-left: 125px;
                margin-top: 5px;
            }
            .slider-image-preview img {
                max-width: 200px;
                max-height: 150px;
                border: 1px solid #ddd;
                padding: 2px;
            }
        </style>
        <div class="slider-meta-field">
            <label>图片URL:</label>
            <input type="text" name="slider_image_url" id="slider_image_url" value="<?php echo esc_url($image_url); ?>" style="width: 60%;" />
            <button type="button" class="button upload_image_button">上传图片</button>
            <div class="slider-image-preview">
                <?php if ($image_url) : ?>
                    <img src="<?php echo esc_url($image_url); ?>" alt="预览图片" />
                <?php endif; ?>
            </div>
        </div>

        <div class="slider-meta-field">
            <label>链接URL (可选):</label>
            <input type="text" name="slider_link_url" value="<?php echo esc_url($link_url); ?>" style="width: 70%;" />
            <p class="description">点击幻灯片时跳转的链接</p>
        </div>

        <div class="slider-meta-field">
            <label>文字说明 (可选):</label>
            <textarea name="slider_text" rows="3" style="width: 70%;"><?php echo esc_textarea($slide_text); ?></textarea>
        </div>

        <div class="slider-meta-field">
            <label>排序权重:</label>
            <input type="number" name="slider_order" value="<?php echo intval($slide_order); ?>" style="width: 100px;" />
            <p class="description">数值越小越靠前,用于自定义顺序</p>
        </div>

        <div class="slider-meta-field">
            <label>置顶:</label>
            <input type="checkbox" name="slider_sticky" value="1" <?php checked($is_sticky, '1'); ?> />
            <span>置顶的幻灯片会显示在右侧小图区域的最前面</span>
        </div>

        <div class="slider-meta-field">
            <label>推荐:</label>
            <input type="checkbox" name="slider_featured" value="1" <?php checked($is_featured, '1'); ?> />
            <span>推荐的幻灯片会在左侧大图中优先显示</span>
        </div>
        <?php
    }

    // 保存元数据
    public function save_slider_meta($post_id) {
        if (!isset($_POST['slider_meta_box_nonce']) || !wp_verify_nonce($_POST['slider_meta_box_nonce'], 'slider_meta_box')) {
            return;
        }

        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }

        if (!current_user_can('edit_post', $post_id)) {
            return;
        }

        if (isset($_POST['slider_image_url'])) {
            update_post_meta($post_id, '_slider_image_url', esc_url_raw($_POST['slider_image_url']));
        }

        if (isset($_POST['slider_link_url'])) {
            update_post_meta($post_id, '_slider_link_url', esc_url_raw($_POST['slider_link_url']));
        }

        if (isset($_POST['slider_text'])) {
            update_post_meta($post_id, '_slider_text', sanitize_textarea_field($_POST['slider_text']));
        }

        if (isset($_POST['slider_order'])) {
            update_post_meta($post_id, '_slider_order', intval($_POST['slider_order']));
        }

        $sticky = isset($_POST['slider_sticky']) ? '1' : '0';
        update_post_meta($post_id, '_slider_sticky', $sticky);

        $featured = isset($_POST['slider_featured']) ? '1' : '0';
        update_post_meta($post_id, '_slider_featured', $featured);
    }

    // 后台加载媒体上传器
    public function admin_enqueue_scripts($hook) {
        global $post_type;
        if ('slider_item' === $post_type) {
            wp_enqueue_media();
            wp_add_inline_script('media-upload', '
                jQuery(document).ready(function($) {
                    $(".upload_image_button").click(function(e) {
                        e.preventDefault();
                        var button = $(this);
                        var customUploader = wp.media({
                            title: "选择图片",
                            button: {
                                text: "使用此图片"
                            },
                            multiple: false
                        }).on("select", function() {
                            var attachment = customUploader.state().get("selection").first().toJSON();
                            button.siblings("#slider_image_url").val(attachment.url);
                            button.siblings(".slider-image-preview").html("<img src=\"" + attachment.url + "\" style=\"max-width:200px;\" />");
                        }).open();
                    });
                });
            ');
        }
    }

    // 加载前端样式和脚本
    public function enqueue_slider_assets() {
        if (has_shortcode(get_post()->post_content, 'advanced_slider')) {
            wp_enqueue_style('advanced-slider-style', plugin_dir_url(__FILE__) . 'assets/slider-style.css', array(), '1.0');
            wp_enqueue_script('advanced-slider-script', plugin_dir_url(__FILE__) . 'assets/slider-script.js', array('jquery'), '1.0', true);
            wp_localize_script('advanced-slider-script', 'sliderAjax', array(
                'ajaxurl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce('slider_nonce')
            ));
        }
    }

    // 获取幻灯片数据
    private function get_slider_items() {
        // 获取左侧大图(推荐)
        $featured_args = array(
            'post_type' => 'slider_item',
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => '_slider_featured',
                    'value' => '1',
                    'compare' => '='
                )
            ),
            'meta_key' => '_slider_order',
            'orderby' => array(
                'meta_value_num' => 'ASC',
                'date' => 'DESC'
            ),
            'order' => 'ASC'
        );
        
        // 获取置顶和普通右侧小图
        $right_args = array(
            'post_type' => 'slider_item',
            'posts_per_page' => -1,
            'meta_query' => array(
                'relation' => 'OR',
                array(
                    'key' => '_slider_sticky',
                    'value' => '1',
                    'compare' => '='
                ),
                array(
                    'key' => '_slider_sticky',
                    'value' => '0',
                    'compare' => '='
                )
            ),
            'meta_key' => '_slider_order',
            'orderby' => array(
                'meta_value_num' => 'ASC',
                'date' => 'DESC'
            ),
            'order' => 'ASC'
        );
        
        $featured_items = get_posts($featured_args);
        $all_items = get_posts($right_args);
        
        // 如果没有推荐项,则从所有项中取
        if (empty($featured_items)) {
            $featured_args['meta_query'] = null;
            $featured_items = get_posts($featured_args);
        }
        
        // 处理右侧项:置顶优先
        $sticky_items = array();
        $normal_items = array();
        foreach ($all_items as $item) {
            $is_sticky = get_post_meta($item->ID, '_slider_sticky', true);
            if ($is_sticky == '1') {
                $sticky_items[] = $item;
            } else {
                $normal_items[] = $item;
            }
        }
        $right_items = array_merge($sticky_items, $normal_items);
        
        return array(
            'left_items' => $featured_items,
            'right_items' => $right_items
        );
    }

    // 渲染短代码
    public function render_slider_shortcode($atts) {
        $atts = shortcode_atts(array(
            'left_count' => 5,      // 左侧大图数量
            'right_count' => 10,     // 右侧小图显示数量
        ), $atts);
        
        $items = $this->get_slider_items();
        $left_items = array_slice($items['left_items'], 0, intval($atts['left_count']));
        $right_items = array_slice($items['right_items'], 0, intval($atts['right_count']));
        
        ob_start();
        ?>
        <div class="advanced-slider-container">
            <div class="slider-left">
                <div class="main-slider">
                    <?php if (!empty($left_items)) : ?>
                        <?php foreach ($left_items as $index => $item) : 
                            $image_url = get_post_meta($item->ID, '_slider_image_url', true);
                            $link_url = get_post_meta($item->ID, '_slider_link_url', true);
                            $text = get_post_meta($item->ID, '_slider_text', true);
                            ?>
                            <div class="slide-item <?php echo $index === 0 ? 'active' : ''; ?>" data-index="<?php echo $index; ?>">
                                <?php if ($link_url) : ?>
                                    <a href="<?php echo esc_url($link_url); ?>">
                                        <img src="<?php echo esc_url($image_url); ?>" alt="<?php echo esc_attr($item->post_title); ?>">
                                        <?php if ($text) : ?>
                                            <div class="slide-caption"><?php echo esc_html($text); ?></div>
                                        <?php endif; ?>
                                    </a>
                                <?php else : ?>
                                    <img src="<?php echo esc_url($image_url); ?>" alt="<?php echo esc_attr($item->post_title); ?>">
                                    <?php if ($text) : ?>
                                        <div class="slide-caption"><?php echo esc_html($text); ?></div>
                                    <?php endif; ?>
                                <?php endif; ?>
                            </div>
                        <?php endforeach; ?>
                        
                        <div class="slider-nav">
                            <span class="prev-slide">&#10094;</span>
                            <span class="next-slide">&#10095;</span>
                        </div>
                        <div class="slider-dots">
                            <?php foreach ($left_items as $index => $item) : ?>
                                <span class="dot <?php echo $index === 0 ? 'active' : ''; ?>" data-index="<?php echo $index; ?>"></span>
                            <?php endforeach; ?>
                        </div>
                    <?php else : ?>
                        <p>暂无幻灯片内容,请在后台添加。</p>
                    <?php endif; ?>
                </div>
            </div>
            
            <div class="slider-right">
                <div class="thumb-scroll-container">
                    <div class="thumb-list">
                        <?php foreach ($right_items as $item) : 
                            $image_url = get_post_meta($item->ID, '_slider_image_url', true);
                            $title = $item->post_title;
                            $is_sticky = get_post_meta($item->ID, '_slider_sticky', true);
                            ?>
                            <div class="thumb-item <?php echo $is_sticky ? 'sticky' : ''; ?>" data-id="<?php echo $item->ID; ?>">
                                <img src="<?php echo esc_url($image_url); ?>" alt="<?php echo esc_attr($title); ?>">
                                <div class="thumb-title"><?php echo esc_html($title); ?></div>
                                <?php if ($is_sticky) : ?>
                                    <span class="sticky-badge">置顶</span>
                                <?php endif; ?>
                            </div>
                        <?php endforeach; ?>
                    </div>
                </div>
            </div>
        </div>
        <?php
        return ob_get_clean();
    }
}

// 初始化插件
new AdvancedSlider();

// 创建assets目录和CSS/JS文件
function advanced_slider_create_assets() {
    $upload_dir = plugin_dir_path(__FILE__);
    $assets_dir = $upload_dir . 'assets/';
    
    if (!file_exists($assets_dir)) {
        mkdir($assets_dir, 0755, true);
    }
    
    // CSS文件
    $css_content = <<<CSS
.advanced-slider-container {
    display: flex;
    gap: 20px;
    max-width: 1200px;
    margin: 0 auto;
    position: relative;
    font-family: Arial, sans-serif;
}

.slider-left {
    flex: 2;
    position: relative;
}

.main-slider {
    position: relative;
    overflow: hidden;
    border-radius: 8px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.slide-item {
    display: none;
    position: relative;
}

.slide-item.active {
    display: block;
    animation: fadeIn 0.5s ease-in-out;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.slide-item img {
    width: 100%;
    height: 400px;
    object-fit: cover;
    display: block;
}

.slide-caption {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(0,0,0,0.7);
    color: white;
    padding: 10px;
    text-align: center;
}

.slider-nav {
    position: absolute;
    top: 50%;
    width: 100%;
    transform: translateY(-50%);
    display: flex;
    justify-content: space-between;
    padding: 0 10px;
    box-sizing: border-box;
}

.prev-slide, .next-slide {
    cursor: pointer;
    background: rgba(0,0,0,0.5);
    color: white;
    padding: 10px 15px;
    border-radius: 50%;
    font-size: 18px;
    transition: 0.3s;
}

.prev-slide:hover, .next-slide:hover {
    background: rgba(0,0,0,0.8);
}

.slider-dots {
    text-align: center;
    padding: 10px 0;
    position: absolute;
    bottom: 10px;
    left: 0;
    right: 0;
}

.dot {
    cursor: pointer;
    height: 12px;
    width: 12px;
    margin: 0 5px;
    background-color: #bbb;
    border-radius: 50%;
    display: inline-block;
    transition: background-color 0.3s;
}

.dot.active, .dot:hover {
    background-color: #717171;
}

.slider-right {
    flex: 1;
}

.thumb-scroll-container {
    height: 400px;
    overflow-y: auto;
    border-radius: 8px;
    background: #f5f5f5;
    padding: 10px;
}

.thumb-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.thumb-item {
    position: relative;
    background: white;
    border-radius: 6px;
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.2s, box-shadow 0.2s;
    box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

.thumb-item:hover {
    transform: translateX(-5px);
    box-shadow: 0 3px 10px rgba(0,0,0,0.2);
}

.thumb-item.sticky {
    border-left: 4px solid #ff9800;
}

.thumb-item img {
    width: 100%;
    height: 80px;
    object-fit: cover;
    display: block;
}

.thumb-title {
    padding: 8px;
    font-size: 14px;
    background: white;
    text-align: center;
    font-weight: bold;
    color: #333;
}

.sticky-badge {
    position: absolute;
    top: 5px;
    right: 5px;
    background: #ff9800;
    color: white;
    padding: 2px 6px;
    border-radius: 3px;
    font-size: 10px;
    font-weight: bold;
}

/* 滚动条样式 */
.thumb-scroll-container::-webkit-scrollbar {
    width: 8px;
}

.thumb-scroll-container::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 10px;
}

.thumb-scroll-container::-webkit-scrollbar-thumb {
    background: #888;
    border-radius: 10px;
}

.thumb-scroll-container::-webkit-scrollbar-thumb:hover {
    background: #555;
}

/* 响应式 */
@media (max-width: 768px) {
    .advanced-slider-container {
        flex-direction: column;
    }
    .slide-item img {
        height: 250px;
    }
    .thumb-scroll-container {
        height: 300px;
    }
}
CSS;
    
    file_put_contents($assets_dir . 'slider-style.css', $css_content);
    
    // JS文件
    $js_content = <<<JS
jQuery(document).ready(function($) {
    var currentIndex = 0;
    var slideItems = $('.slide-item');
    var totalSlides = slideItems.length;
    var autoPlayInterval;
    
    function showSlide(index) {
        if (index < 0) index = totalSlides - 1;
        if (index >= totalSlides) index = 0;
        
        slideItems.removeClass('active');
        $(slideItems[index]).addClass('active');
        $('.dot').removeClass('active');
        $('.dot[data-index="' + index + '"]').addClass('active');
        currentIndex = index;
    }
    
    function nextSlide() {
        showSlide(currentIndex + 1);
    }
    
    function prevSlide() {
        showSlide(currentIndex - 1);
    }
    
    function startAutoPlay() {
        if (autoPlayInterval) clearInterval(autoPlayInterval);
        autoPlayInterval = setInterval(nextSlide, 5000);
    }
    
    function stopAutoPlay() {
        if (autoPlayInterval) {
            clearInterval(autoPlayInterval);
            autoPlayInterval = null;
        }
    }
    
    if (totalSlides > 0) {
        $('.next-slide').on('click', function() {
            nextSlide();
            stopAutoPlay();
            startAutoPlay();
        });
        
        $('.prev-slide').on('click', function() {
            prevSlide();
            stopAutoPlay();
            startAutoPlay();
        });
        
        $('.dot').on('click', function() {
            var index = $(this).data('index');
            showSlide(index);
            stopAutoPlay();
            startAutoPlay();
        });
        
        // 右侧缩略图点击事件 - 切换到对应的大图
        $('.thumb-item').on('click', function() {
            var thumbId = $(this).data('id');
            // 查找左侧大图中对应的幻灯片(根据图片URL或标题匹配)
            var thumbImg = $(this).find('img').attr('src');
            var foundIndex = -1;
            
            slideItems.each(function(index) {
                var slideImg = $(this).find('img').attr('src');
                if (slideImg === thumbImg) {
                    foundIndex = index;
                    return false;
                }
            });
            
            if (foundIndex !== -1) {
                showSlide(foundIndex);
                stopAutoPlay();
                startAutoPlay();
            }
        });
        
        // 鼠标悬停时暂停自动播放
        $('.main-slider').hover(function() {
            stopAutoPlay();
        }, function() {
            startAutoPlay();
        });
        
        // 启动自动播放
        startAutoPlay();
    }
});
JS;
    
    file_put_contents($assets_dir . 'slider-script.js', $js_content);
}

register_activation_hook(__FILE__, 'advanced_slider_create_assets');

安装步骤

1. 创建插件文件

将上面的完整代码保存为一个PHP文件,例如 advanced-slider.php,然后放到:

/wp-content/plugins/advanced-slider/advanced-slider.php

2. 激活插件

进入 WordPress 后台 → 插件 → 找到”高级幻灯片功能” → 点击激活

插件激活时会自动在插件目录下创建 assets 文件夹和所需的CSS/JS文件

使用方法

第一步:添加幻灯片内容

进入后台 → 高级幻灯片 → 添加新幻灯片

每个幻灯片需要填写:

  • 标题:幻灯片的名称(用于右侧小图显示)
  • 图片URL:点击”上传图片”按钮选择图片
  • 链接URL(可选):点击大图时跳转的链接
  • 文字说明(可选):显示在大图底部的文字
  • 排序权重:数值越小越靠前
  • 置顶:勾选后会在右侧小图区域置顶显示(带橙色标记)
  • 推荐:勾选后会显示在左侧大图轮播区

第二步:在页面中显示幻灯片

在任意页面或文章的编辑器中,添加短代码:

[advanced_slider]

第三步:可选参数调整数量

[advanced_slider left_count="3" right_count="6]

参数说明:

  • left_count:左侧大图显示数量(默认5)
  • right_count:右侧小图显示数量(默认10)

功能说明

区域功能
左侧大图自动轮播(5秒切换),支持点击箭头或圆点切换,鼠标悬停时暂停
右侧小图垂直滚动列表,点击小图可切换到对应大图
置顶功能右侧小图中置顶项显示橙色边框和”置顶”标签
推荐功能推荐项优先显示在左侧大图区

常见问题

Q:右侧小图滚动速度能调吗?
A:滚动速度由CSS控制,可以修改 assets/slider-style.css 中的滚动条样式。

Q:可以修改自动轮播间隔吗?
A:在 assets/slider-script.js 中找到 5000(毫秒),改成您想要的值即可。

Q:图片尺寸建议?
A:左侧大图建议 800×400px,右侧小图建议 300×80px(会自动裁剪适应)。