雛箱

メモ 257

わーい画像部屋のRSSがなんとかなったので更新履歴に自動で反映されるようになったよー!


しばらくphpと戦ってたので以下メモです。


まず画像部屋のfunctions.phpに
add_action('init', function() {
    add_feed('media-gallery', function() {
        load_template(get_stylesheet_directory() . '/feed-media-gallery.php');
    });
});

と書きまして、通常フィードとは別のフィードを出力するようにしました。
名前は何でも良いんですけど、今回は記事や固定ページではなく画像をアップロードしたことを通知するフィードを作りたかったのでmedia-galleryにしました。
これでhttps://ワードプレス/feed/media-gallery/というアドレスにアクセスすればRSSを読み込む挙動になりました。まだ中身何にもないですけど。

で、functions.phpと同じ場所にfeed-media-gallery.phpを作成します。
中身は空でもアップロードすればワードプレス側で弄れるので大丈夫だと思います。

結論から言うと、そこに以下の記載をしています。
header('Content-Type: application/rss+xml; charset=UTF-8');

// XML ヘッダ
echo '<?xml version="1.0" encoding="UTF-8"?>';
echo '<rss version="2.0"><channel>';
echo '<title>Media Gallery Feed</title>';
echo '<link>' . home_url('/') . '</link>';
echo '<description>Media Gallery RSS</description>';

// 親カテゴリマップ
$parent_map = [
    'knyacki' => 'ニャッキ',
    'rtr'     => 'ドット絵化',
    'jpeg'    => 'Jpeg圧縮',
];

// 画像添付投稿を取得
$attachments = get_posts([
    'post_type' => 'attachment',
    'post_mime_type' => 'image',
    'numberposts' => 50,
    'orderby' => 'date',
    'order' => 'DESC',
]);

if ($attachments) {
    $grouped = [];
    $processed_ids = []; // 重複防止

    // 120分以内のまとめ処理
    foreach ($attachments as $post) {
        $id = $post->ID;
        $time = strtotime($post->post_date);

        $found = false;
        foreach ($grouped as &$g) {
            if (abs($g['time'] - $time) <= 7200) { // 120分以内
                $g['ids'][] = $id;
                $found = true;
                break;
            }
        }
        if (!$found) {
            $grouped[] = ['time' => $time, 'ids' => [$id]];
        }
    }

    // <item> 出力
    foreach ($grouped as $g) {
        $rep_id = $g['ids'][0];

        // 重複チェック
        if (isset($processed_ids[$rep_id])) continue;
        $processed_ids[$rep_id] = true;

        $date = get_the_date('Y.m.d', $rep_id);
        $terms = wp_get_post_terms($rep_id, 'category');

        $cat_name = '未分類';
        $link = home_url('/');

        // カテゴリ URL 作成
        foreach ($terms as $term) {
            $ancestors = get_ancestors($term->term_id, 'category');
            if ($ancestors) {
                $top = get_term(end($ancestors), 'category');

                // photoカテゴリは孫カテゴリまで取得
                if ($top && $top->slug === 'photo' && count($ancestors) >= 2) {
                    $child = get_term($ancestors[count($ancestors) - 2], 'category');
                    $grandchild = $term;
                    $cat_name = $grandchild->name;
                    $link = home_url('/') . "photo/{$child->slug}/{$grandchild->slug}/";
                    break;
                } elseif ($top && isset($parent_map[$top->slug])) {
                    $cat_name = $parent_map[$top->slug];
                    $link = home_url('/') . "{$top->slug}/";
                    break;
                }
            } elseif (isset($parent_map[$term->slug])) {
                $cat_name = $parent_map[$term->slug];
                $link = home_url('/') . "{$term->slug}/";
                break;
            }
        }

        // 追加画像数
        $extra_count = max(0, count($g['ids']) - 1);
        $extra_text = $extra_count > 0 ? "(他{$extra_count}枚)" : '';

        echo '<item>';
        echo '<title><![CDATA[' . $date . ' - ' . $cat_name . ' - #' . $rep_id . $extra_text . ']]></title>';
        echo '<link>' . esc_url($link) . '</link>';
        echo '<guid>media-gallery?id=' . $rep_id . '</guid>';
        echo '<pubDate>' . get_the_date('r', $rep_id) . '</pubDate>';
        echo '<source url="' . esc_url($link) . '">' . $cat_name . '</source>';
        echo '</item>';
    }
}

echo '</channel></rss>';

先に書いたように、記事や固定ページではなく画像をアップロードしたこと…メディアライブラリに追加があったことを感知するようにしました。

まあざっくりしたことは(自分が忘れるので)php内にコメントアウトで書いてあるのですが、

親カテゴリマップというのはRSSでカテゴリスラッグがそのまま出て来ても分かりにくいため名前を分かりやすく変換するやつですね。
この辺り表示名付けてるのでそっちを利用すればイチイチ指定しなくてもなんとかなりそうですが、数が少なくて面倒でもないのでとりあえずこうしてあります。

重複防止と120分以内のまとめ処理は画像をまとめてアップした際に更新履歴が埋まらないようにする為です。
そんなに更新に時間かからないとかもっと即座に更新反映させたいとかなら30分とかもっと短くても良さそうですね。
自分の場合は画像溜め込むことがあるのと即時反映に拘ってないので120分にしました。こんなに長くなくても良い気はしますが。

あとギャラリー化するにあたって画像にカテゴリ付けをしているので、その親カテゴリーで分類、特定のカテゴリ(photo)に関しては孫まで掘って孫で判断するようにしています。
カテゴリ付けに関してはプラグインを利用しています。『WordPress メディアライブラリ カテゴリ付け』辺りの単語で検索すると色々出て来るので良さそうなの入れると良いと思います。もしかしたら今回のPHPだと相性悪くて反応しないのあるかもですけど。
とりあえず私が使っているのはCategories Images です。

あ、それとパーマリンクを/親カテゴリ/(子カテゴリ/孫カテゴリ/)としているのでリンクも更新した画像に直接飛ぶのではなく、カテゴリ別画像一覧ページに飛ぶ感じで作ってますね。

で、画像部屋のRSSはこんな感じなんですが、読み取って更新履歴として表示させる方がブログタイトルを読み込む仕様にしてあるので、このままだと2026/01/20 - Media Gallery Feed - 2026/01/10 - yell vogue - #1139(他5枚)
みたいになってしまうので、
出力の方のfunctions.phpに
        if ( strpos( $item->get_feed()->subscribe_url(), 'gallery/feed/media-gallery' ) !== false ) {
            echo esc_html( $title );
        } else {
            echo esc_html( $date ) . ' - ';
            echo esc_html( $feed_title ) . ' - ';
            echo esc_html( $title );
        }

という記載をしてあります。

なんでわざわざfeed-media-gallery.phpの方で記事タイトル扱いで日付を表示させて、出力の方のfunctions.phpで$dateを表示させない形にしているかというと投稿日付の表示が怪しくなったからです。
多分ちゃんと出来るひとならfeed-media-gallery.phpの方でecho esc_html( $date )抜いて出力の方のfunctions.phpでecho esc_html( $feed_title )だけ抜く形になるんじゃないかな…。
まあとりあえずこの形で問題なく動くのでこうしています
畳む


#WordPress

  メモ  編集