You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WordPress多社交平台内容聚合短代码排序失效求助

WordPress社交聚合短代码修复方案

核心问题定位

你的代码无法正常运行的主要原因是函数调用名称不匹配,同时存在排序逻辑、兼容性和安全性的细节问题:

  • 在social_wall_shortcode中,你调用了不存在的my_instagram_feed_shortcode和display_twitch_videos函数,实际应该是你定义好的fetch_instagram_posts和fetch_twitch_videos
  • 默认排序是按日期升序(最早内容在前),不符合“最新内容优先”的常规需求
  • Instagram使用file_get_contents兼容性较差,WordPress环境推荐用官方的wp_remote_get
  • Twitch嵌入代码中的parent=*存在安全风险,应该指定实际站点域名

修复后的完整代码

<?php
/*
Plugin Name:  Social media crawler
Description:  聚合Twitch、YouTube、Instagram内容并按日期排序
Version:      1.0
Author:       
License:      GPL2
License URI:  https://www.gnu.org/licenses/gpl-2.0.html
Domain Path:  /languages
*/

function fetch_youtube_videos($atts) {
    $atts = shortcode_atts(array(
        'channel_id' => '***',
        'max_results' => 5,
        'date' => '2010-01-01',
    ), $atts);

    $api_key = '***';
    $publishedAfter = $atts['date'] . 'T00:00:00Z';
    $api_url = add_query_arg(array(
        'part' => 'snippet',
        'channelId' => $atts['channel_id'],
        'maxResults' => $atts['max_results'],
        'publishedAfter' => $publishedAfter,
        'order' => 'date',
        'type' => 'video',
        'key' => $api_key
    ), 'https://www.googleapis.com/youtube/v3/search');

    $response = wp_remote_get($api_url);
    if (is_wp_error($response)) {
        return [];
    }

    $body = wp_remote_retrieve_body($response);
    $data = json_decode($body);
    if (!isset($data->items)) {
        return [];
    }

    $posts = [];
    foreach ($data->items as $item) {
        $title = $item->snippet->title;
        $video_id = $item->id->videoId;
        $video_url = 'https://www.youtube.com/watch?v=' . $video_id;
        $embed_url = 'https://www.youtube.com/embed/' . $video_id;
        $publishedAt = $item->snippet->publishedAt;

        $html = '<div class="youtube-video">' .
            '<iframe width="560" height="315" src="' . esc_url($embed_url) . '" title="' . esc_attr($title) . '" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>' .
            '<p><a href="' . esc_url($video_url) . '" target="_blank">' . esc_html($title) . '</a></p>' .
            '</div>';

        $posts[] = [
            'date' => $publishedAt,
            'html' => $html
        ];
    }
    return $posts;
}

function fetch_instagram_posts($atts) {
    $atts = shortcode_atts([
        'limit' => 10,
    ], $atts);

    $fields = "id,caption,media_type,media_url,permalink,thumbnail_url,timestamp,username";
    $token = "*";
    $limit = $atts['limit'];

    $api_url = add_query_arg(array(
        'fields' => $fields,
        'access_token' => $token,
        'limit' => $limit
    ), 'https://graph.instagram.com/me/media');

    $response = wp_remote_get($api_url);
    if (is_wp_error($response)) {
        return [];
    }

    $body = wp_remote_retrieve_body($response);
    $contents = json_decode($body, true);
    if (!isset($contents["data"]) || empty($contents["data"])) {
        return [];
    }

    $posts = [];
    foreach ($contents["data"] as $post) {
        $username = isset($post["username"]) ? $post["username"] : "";
        $caption = isset($post["caption"]) ? $post["caption"] : "";
        $media_url = isset($post["media_url"]) ? $post["media_url"] : "";
        $permalink = isset($post["permalink"]) ? $post["permalink"] : "";
        $media_type = isset($post["media_type"]) ? $post["media_type"] : "";
        $timestamp = isset($post["timestamp"]) ? $post["timestamp"] : "";

        $html = "<div class='ig_post_container'><div>";
        if ($media_type == "VIDEO") {
            $html .= "<video controls style='width:100%; display: block !important;'><source src='" . esc_url($media_url) . "' type='video/mp4'>Your browser does not support the video tag.</video>";
        } else {
            $html .= "<img src='" . esc_url($media_url) . "' alt='" . esc_attr($caption) . "' />";
        }
        $html .= "</div><div class='ig_post_details'><div><strong>@" . esc_html($username) . "</strong> " . esc_html($caption) . "</div><div class='ig_view_link'><a href='" . esc_url($permalink) . "' target='_blank'>View on Instagram</a></div></div></div>";

        $posts[] = [
            'date' => $timestamp,
            'html' => $html
        ];
    }
    return $posts;
}

function fetch_twitch_videos($atts) {
    $atts = shortcode_atts([
        'date' => '1970-01-01',
    ], $atts);

    $clientID = '*';
    $clientSecret = '*';
    $tokenUrl = 'https://id.twitch.tv/oauth2/token';

    $params = [
        'client_id' => $clientID,
        'client_secret' => $clientSecret,
        'grant_type' => 'client_credentials',
    ];

    $response = wp_remote_post($tokenUrl, array(
        'body' => $params
    ));
    if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
        return [];
    }

    $tokenData = json_decode(wp_remote_retrieve_body($response), true);
    if (!isset($tokenData['access_token'])) {
        return [];
    }

    $accessToken = $tokenData['access_token'];
    $broadcasterUserId = '*';
    $site_domain = wp_parse_url(get_site_url(), PHP_URL_HOST);

    $videoClipsUrl = add_query_arg(array(
        'broadcaster_id' => $broadcasterUserId
    ), 'https://api.twitch.tv/helix/clips');

    $headers = [
        'Authorization: Bearer ' . $accessToken,
        'Client-Id: ' . $clientID,
    ];

    $response = wp_remote_get($videoClipsUrl, array(
        'headers' => $headers
    ));
    if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
        return [];
    }

    $videoClipsData = json_decode(wp_remote_retrieve_body($response), true);
    if (!isset($videoClipsData['data']) || empty($videoClipsData['data'])) {
        return [];
    }

    $posts = array_map(function ($clip) use ($site_domain) {
        $clipDate = $clip['created_at'];
        $embed_url = add_query_arg('parent', $site_domain, $clip['embed_url']);
        $html = '<iframe src="' . esc_url($embed_url) . '" frameborder="0" allowfullscreen="true" scrolling="no" height="378" width="620"></iframe>';
        return [
            'date' => $clipDate,
            'html' => $html,
        ];
    }, $videoClipsData['data']);

    $minDateTimestamp = strtotime($atts['date']);
    $filteredPosts = array_filter($posts, function ($post) use ($minDateTimestamp) {
        return strtotime($post['date']) >= $minDateTimestamp;
    });

    return array_values($filteredPosts);
}

function social_wall_shortcode($atts) {
    ob_start();

    // 修正函数调用名称
    $youtubePosts = fetch_youtube_videos($atts);
    $instagramPosts = fetch_instagram_posts($atts);
    $twitchPosts = fetch_twitch_videos($atts);

    $allPosts = array_merge($youtubePosts, $instagramPosts, $twitchPosts);

    // 改为降序排序,最新内容在前
    usort($allPosts, function($a, $b) {
        return strtotime($b['date']) <=> strtotime($a['date']);
    });

    echo '<div class="social-wall-container">';
    if (empty($allPosts)) {
        echo '<p>暂无社交内容展示</p>';
    } else {
        foreach ($allPosts as $post) {
            echo $post['html'];
        }
    }
    echo '</div>';

    $content = ob_get_clean();
    return $content;
}

add_shortcode('social_wall', 'social_wall_shortcode');

关键修复点说明

  1. 函数名称修正:将social_wall_shortcode中的错误函数调用替换为正确的fetch_instagram_posts和fetch_twitch_videos
  2. 排序逻辑调整:把排序规则从升序改为降序,确保最新内容优先显示
  3. 兼容性优化:Instagram和Twitch的API调用改用WordPress原生的wp_remote_get/wp_remote_post,替代file_get_contents和curl,避免主机环境限制
  4. 安全增强:Twitch嵌入链接的parent参数设置为当前站点域名,替代通配符*
  5. 错误提示补充:当没有任何内容时,显示友好提示
  6. 转义完善:给所有用户生成的内容添加esc_url/esc_html/esc_attr,防止XSS风险
  7. URL构建优化:使用add_query_arg构建API链接,避免手动拼接字符串导致的错误

内容的提问来源于stack exchange,提问作者Mats S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 09:12:02