star back image
people4
電飾 電飾
moon
astronaut

【WordPress】AI最適化 LLMO構造化データ出力プラグインを作る

BLOG AISEOWEBログWordPressプラグイン
読了約:20分

以前にAI検索をフレンドリーにするllms.txtの育成プラグインを作成しました。

それでAI対応も終わったと思っていたところ。有名SEO診断サイトにかけると。。
「LLMOの構造化データがないです」と、低評価されました。

まったLLMOとか言う新しい言葉を(-ω-;)

LLMOって何ですかね。

必要なんでしょうか。さっぱりわかりません。

AIに聞きました。

LLMsとは違うもの

・やること
LLMs → llms.txt をサーバールートに出力(テキスト)
LLMO → HTMLの <head> に JSON-LD を挿入

・意味合い
llms.txt → 「AIに対するサイトの外向け説明」
JSON-LD(BlogPosting) → 「ページ単位での意味づけ」

という感じで、お互いを補完し合う関係になるとのこと。

<head></head>内に、JSON-LDという構造化データを仕込むようです。

LLMsと競合はしませんが、JSON-LDって知ってましたか?

Blog記事にページ単位で実装するならやはり。

ですよね。毎回やるのはめんどくさい。。自動がいいです。

【AI】一緒にプラグインを作ろう

JSON-LDを記事に自動で出せるWordpressプラグインを作りたいとAIに伝えました。

すると。。〆(゚ε゚AI). サササ

generic-structured-data/
└── generic-structured-data.php

パーミッションはWordPressのプラグインとして動作するために必要な権限は:

ディレクトリ: 755 (drwxr-xr-x)
ファイル: 644 (-rw-r--r--)

WordPressがインストールされているフォルダを探してください。

アップ場所:
wp_パス/wp-content/plugins/

/generic-structured-data/をFTPでアップしましょう。

/wp-content/plugins/ディレクトリにUPすると、プラグインをダウンロードしたのと同じことになります。

有効化のあとは、任意のブログ記事を開いて、
「ページのソースを表示」で <script type="application/ld+json"> が出ていればOKです。

ブラウザーのChromeでコード(ソースコードやHTML/CSS/JS)を表示するには、右クリックして「ページのソースを表示」するか、ショートカットキー(Ctrl+U / Cmd+Option+U)を使うのが最も簡単です。より詳細に調べたい場合は、右クリックから「検証」(F12キーも可)で開発者ツールを開くと、コードを編集・デバッグしながらリアルタイムで確認できます。

プラグインのソースコードを見ていきましょう。

【共有】プラグインのソースコード

ファイルは1つです。有効化にするだけ動作し、管理画面もありません。
コードをコピペして、保存&有効化すれば動きます。

要件は以下です。

  • 投稿ページに JSON-LD を自動出力
  • サイト名・著者名・アイコンなど WordPress の動的情報を最大限活用

シンプルですね。

generic-structured-data.php

<?php
/**
 * Plugin Name: Generic Structured Data for Blog Posts
 * Plugin URI: https://neo.astrowave.jp/
 * Description: シンプルな BlogPosting の構造化データ(JSON-LD)を、投稿ページに自動追加する超汎用プラグインです。
 * Version: 1.0.0
 * Author: サイガモ
 * Author URI: https://neo.astrowave.jp/
 * License: GPL v2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: generic-structured-data
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * BlogPosting の JSON-LD を出力
 */
function gsd_output_blogposting_schema() {
    // 個別投稿ページ(post など)以外では出さない
    if ( ! is_single() ) {
        return;
    }

    global $post;
    if ( ! $post instanceof WP_Post ) {
        return;
    }

    $post_id = $post->ID;

    // 基本情報
    $headline  = get_the_title( $post_id );
    $permalink = get_permalink( $post_id );

    // 抜粋(なければ本文から自動生成)
    if ( has_excerpt( $post_id ) ) {
        $description = get_the_excerpt( $post_id );
    } else {
        $content     = wp_strip_all_tags( $post->post_content );
        $description = wp_trim_words( $content, 40, '…' ); // 約40語
    }

    // アイキャッチ画像
    $image_url = get_the_post_thumbnail_url( $post_id, 'full' );

    // カテゴリー(先頭1件を articleSection に)
    $article_section = '';
    $categories      = get_the_category( $post_id );
    if ( ! empty( $categories ) && ! is_wp_error( $categories ) ) {
        $article_section = $categories[0]->name;
    }

    // タグ → keywords
    $keywords = '';
    $tags     = get_the_tags( $post_id );
    if ( $tags && ! is_wp_error( $tags ) ) {
        $tag_names = wp_list_pluck( $tags, 'name' );
        $keywords  = implode( ', ', $tag_names );
    }

    // 著者情報
    $author_id   = $post->post_author;
    $author_name = get_the_author_meta( 'display_name', $author_id );
    $author_url  = get_author_posts_url( $author_id );

    // サイト情報(publisher)
    $site_name = get_bloginfo( 'name' );
    $site_icon = get_site_icon_url(); // 設定されていない場合は空文字

    $schema = array(
        '@context'        => 'https://schema.org',
        '@type'           => 'BlogPosting',
        'mainEntityOfPage'=> array(
            '@type' => 'WebPage',
            '@id'   => $permalink,
        ),
        'headline'        => $headline,
        'description'     => $description,
        'inLanguage'      => 'ja',
        'datePublished'   => get_the_date( DATE_W3C, $post_id ),
        'dateModified'    => get_the_modified_date( DATE_W3C, $post_id ),

        'author'          => array(
            '@type' => 'Person',
            'name'  => $author_name,
            'url'   => $author_url,
        ),

        'publisher'       => array(
            '@type' => 'Organization',
            'name'  => $site_name,
        ),
    );

    // サイトアイコンがあればロゴとして追加
    if ( $site_icon ) {
        $schema['publisher']['logo'] = array(
            '@type' => 'ImageObject',
            'url'   => $site_icon,
        );
    }

    // カテゴリ
    if ( $article_section ) {
        $schema['articleSection'] = $article_section;
    }

    // アイキャッチ
    if ( $image_url ) {
        $schema['image'] = array(
            '@type' => 'ImageObject',
            'url'   => $image_url,
        );
    }

    // キーワード
    if ( $keywords ) {
        $schema['keywords'] = $keywords;
    }

    echo "\n" . '<script type="application/ld+json">' . "\n";
    echo wp_json_encode( $schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT );
    echo "\n" . '</script>' . "\n";
}
add_action( 'wp_head', 'gsd_output_blogposting_schema' );

「ページのソースを表示」で <script type="application/ld+json"> が出力されているか確認しましょう。

ドキドキ❤️

【補足】出力フィールドの内容

実際に出力されたもののサンプルは以下の記事ページです。

サンプルページ
https://neo.astrowave.jp/blog/17958/

構造化データ

<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": "https://neo.astrowave.jp/blog/19361/"
    },
    "headline": "【WordPress】AI最適化 LLMs.txtプラグインを作る",
    "description": "AI検索をフレンドリーにするllms.txtの育成プラグインの記事を書いていまし…",
    "inLanguage": "ja",
    "datePublished": "2025-05-07T18:48:18+09:00",
    "dateModified": "2025-12-04T14:02:56+09:00",
    "author": {
        "@type": "Person",
        "name": "サイガモ",
        "url": "https://neo.astrowave.jp/author/akira/"
    },
    "publisher": {
        "@type": "Organization",
        "name": "astrowave",
        "logo": {
            "@type": "ImageObject",
            "url": "https://neo.astrowave.jp/wp-content/uploads/2022/04/cropped-siteicon.png"
        }
    },
    "articleSection": "BLOG",
    "image": {
        "@type": "ImageObject",
        "url": "https://neo.astrowave.jp/wp-content/uploads/2025/05/llms_plugin_main.jpg"
    },
    "keywords": "PHP, SEO, WEBログ, WordPress, プラグイン"
}
</script>

↑上はプラグインで出力された JSON-LDコードです。
内容的には以下のような感じです。

"headline"
→ 記事タイトルが正確に反映されている

"description"
→ 抜粋が自動で入っている

"inLanguage"
→ ja(日本語用)OK

"datePublished / dateModified"
→ WordPressの投稿日時・更新日時を W3C 形式で取得

"author"
→ 動的に著者名 & 著者ページ URL が取得

"publisher"
→ WordPress のサイト名を自動取得している
→ サイトアイコンも自動検出

"articleSection"
→ カテゴリー名「BLOG」が動的反映
(WordPress の get_the_category が働いている証拠)

"image"
→ アイキャッチ画像を自動でフルサイズ取得
(BlogPostingの要素)

"keywords"
→ タグがカンマ区切りで自動反映(完璧)

このサンプル実装では、キレイに出力されておりました。

これでもう完璧とAIさんも言っています。

以上になります。

【AI】イラストを描いてもらった

今回の記事のキャッチ画像で使わせてもらいます「Google ImageFX」で作成した画像です。誰でもgoogleアカウントでログインして使えます。

この記事にピッタリなイラストのための考えたリクエストは、「VRゴーグルを付けた男性の顔右下に配置。男性はすごく笑っている。男性頭上はVRで見ている内容が背景。背景はピンクの髪のメイドさんが両手を広げてハグしてくれそうな雰囲気。AIと服に刺繍。point of viewで実写的に。」です。

またメイドさんですか。。

AIフレンドリー感を表現しました。

星間旅路のメロディ

「宇宙の静けさに包まれながら、漂流する過去の音楽を捜し求め、銀河の奥底でその旋律に耳を傾ける。」

「この電波はどこの星からきたのだろうか。」

どこかで聞いたことがあるような。

ニャンだこれは?