自分だけのクイズ作成 - Quipha公開中

【WordPress】投稿記事のブロックをPHPで一括更新

Wordpress
スポンサーリンク

はじめに

複数の投稿記事に対して、一括で変更したい!っていうことありませんか?
今回は、WordPressの投稿記事を、PHPで一括変更するやり方を解説します。

WordPressの記事の投稿画面は、ブロックエディター Gutenberg(グーテンベルク)が採用されています。

本文を修正しようとしても、ブロックエディターで編集された本文は、特殊なHTMLタグが追加されており、その仕様を守って編集する必要があります。

本記事は、functions.phpの修正を含みます。修正前にバックアップを行いましょう。
修正については、自己責任でお願いします。

経緯

なぜこの記事をまとめたかというと、私はWordPressのデータを移行したことがあります。

その時は、WordPressのインポート・エクスポートツールを使用したのですが、何故か中途半端に移行されてしまいました😥

具体的には、別なドメインのWordPressに移行したのですが、一部の画像のURLが古いドメインを参照したままとなっていました。全部ではなく一部の画像のURLだけ・・

その原因は分かりませんが、大量の記事と画像があり、一個一個、画像を探して修正するのは相当時間がかかります。

そこで、PHPで全記事の画像ブロックのURLを、一括で変更する処理を実装しました。

ブロック更新

基本的には別記事で解説した、ブロック解析の続きになります。

実際の投稿内容を表示してみましょう。

$post_idはご自身のWordPressに存在する記事IDを指定してください。

        // 記事を取得
        $post_id = 2479;  // TODO: 適宜変更してください

        // 記事の詳細を取得
        $page = get_post($post_id);
        echo nl2br(esc_html($page->post_content));

ブロックエディタで編集した内容は、以下のようにHTMLタグで保存されています。

MySQLのテーブルにもこの状態で格納されています。

この文字列を直接編集して更新してもよいのですが、<!– wp:heading –>などのブロックエディタが認識するタグを誤って変更してしまうと、編集時に正しくブロックが認識されなくなりますので注意が必要です。

このブロックには、想定されていないか無効なコンテンツが含まれています。

ブロックのリカバリーを施行

ブロックを編集するには、「parse_blocks」を使用してまずは解析を行います。(配列に変換)

        // ブロックを解析
        $blocks = parse_blocks($page->post_content);

タイトル一覧を取得してみましょう。

        foreach ($blocks as $key => $value) {
            // 見出しブロックを取得
            if ($value['blockName'] == 'core/heading') {
                echo htmlspecialchars($value['innerHTML']);
            }
        }

記事の中にある見出しの一覧を取得できました。

それではブロックを編集してみます。
サンプルとして、各タイトルの先頭に「編集テスト」という文字列を追加してみましょう。

        // 記事を取得
        $post_id = 2479;  // TODO: 適宜変更してください
        $page = get_post($post_id);

        // ブロックを解析
        $blocks = parse_blocks($page->post_content);
        foreach ($blocks as $key => $value) {
            // 見出しブロックを取得
            if ($value['blockName'] == 'core/heading') {
                // innerContentキーに対して、文字列を挿入
                $blocks[$key]['innerContent'][0] = substr_replace($blocks[$key]['innerContent'][0], '「編集テスト」', 5, 0);
            }
        }

        // 編集結果を出力
        echo "<pre>";
        echo htmlspecialchars(print_r($blocks, true));
        echo "</pre>";

innerContentキーを更新するのがポイントです。
以下のようにh2タグのタイトルの先頭に文字列を追加しました。

Array
(
    [0] => Array
        (
            [blockName] => core/heading
            [attrs] => Array()
            [innerBlocks] => Array()
            [innerHTML] => <h2>はじめに</h2>
            [innerContent] => Array(
                    [0] => <h2>「編集テスト」はじめに</h2>
                )
        )
...

これだけですと、PHPの配列を変更しただけになります。
この配列をブロック文字列に戻すには、「serialize_blocks」を使用します。

        $to_content = serialize_blocks($blocks);
        echo nl2br(esc_html($to_content));

これでブロックエディタで編集したコードに戻すことが出来ます。

<!-- wp:heading -->
<h2>「編集テスト」はじめに</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>今回は、固定ページの子ページ一覧を表示するカスタマイズを行います。<br>ウィジェットで使用できるようにしてみました。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>例えばコーポレートサイトや、マニュアルサイトでも便利に使えると思います。<br>このように、サイドバーに固定ページの子ページの一覧を表示するようにしてみます。</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>「編集テスト」試してみよう</h2>
<!-- /wp:heading -->

parse_blocksでブロックを配列に変換し、配列の値を変更後、serialize_blocksで投稿本文へ戻すことによって、安全に投稿本文を編集することが出来ます。

最後に、投稿本文を更新するには、以下のコードで出来ます。

        $my_post = array(
            'ID'           => $post_id,
            'post_content' => $to_content,
        );
        wp_update_post($my_post);

上記のコードを実行すると、本文が書き換わりますのでご注意ください。

応用例

一括でブロック更新

コードを実行すると、全ての記事の本文が書き換わりますのでご注意ください。

試しに、全記事のタイトルを変更してみましょう。
あくまで実用性のないサンプルですが、応用すれば記事を一括で書き換えたい場合にとても便利です。

        // 記事の一覧を取得
        $pages = get_posts(
            array(
                'post_type' => ['post'],
                'orderby' => 'post__in',
                'posts_per_page' => 200,
            )
        );

        foreach ($pages as $index => $page) {
            // 記事を取得
            $page = get_post($page->ID);

            // ブロックを解析
            $blocks = parse_blocks($page->post_content);
            foreach ($blocks as $key => $value) {
                // 見出しブロックを取得
                if ($value['blockName'] == 'core/heading') {
                    // innerContentキーに対して、文字列を挿入
                    $blocks[$key]['innerContent'][0] = substr_replace($blocks[$key]['innerContent'][0], '「編集テスト」', 5, 0);
                }
            }
            
            // ブロックへ変換
            $to_content = serialize_blocks($blocks);

            // 記事を更新
            $my_post = array(
                'ID'           => $page->ID,
                'post_content' => $to_content,
            );
            // TODO: あえてコメントにしています。試す場合はコメントを外してください。
            //wp_update_post($my_post);
        }

実行してみると、全ての記事の全ての見出しを一括で変更できました。
(「編集テスト」という文字列を追加しました)

さいごに

投稿記事を、手軽に一括で変更することが出来ると便利ですよね!
参考にして是非活用してみてください。

コメント

タイトルとURLをコピーしました