ブログ

  • OLMo 3:推論の根拠を訓練データまで遡れる「ガラス箱」LLMとは何か

    ChatGPTやClaudeなどのLLMは「なぜその回答をしたのか」が分かりません。Allen Institute for AI(AI2)が公開したOLMo 3は、推論の過程を訓練データまで遡って追跡できる「ガラス箱(glass-box)」モデルです。AI透明性の新たな一歩として、日本でも注目すべきプロジェクトです。

    OLMo 3とは

    AI2が公開したOLMo 3は、7Bと32Bパラメータのオープンソース推論モデルです。最大の特徴は完全な透明性です。

    • 訓練データ:Dolma 3(約9.3兆トークン)が完全公開
    • 訓練コード:全て公開
    • ポストトレーニングレシピ:RLHFやファインチューニングの手法も公開
    • モデルの重み:オープンウェイト

    つまり、モデルの入力から出力まで、全てのプロセスを検証できます。

    OlmoTrace:回答の根拠を追跡

    OLMo 3の最も革新的な機能がOlmoTraceです。モデルの回答に対して、以下を追跡できます。

    1. 推論の中間ステップ(思考チェーン)を可視化
    2. 各ステップがどの訓練データに基づいているかを特定
    3. 訓練データの原文を参照可能

    例えば、モデルが「東京の人口は約1400万人」と回答した場合、その数字がDolma 3のどのドキュメントから学習されたかを遡って確認できます。これはハルシネーション(幻覚)の原因特定にも直結します。

    OLMo 3-Think:32Bスケール最強のオープン推論モデル

    OLMo 3-Think(32B)は、32Bパラメータスケールにおける完全オープンソースの推論モデルとして最高性能を達成しています。「Think」の名前が示すように、段階的な推論(Chain-of-Thought)を行い、複雑な問題を分解して解く能力を持ちます。

    なぜ「ガラス箱」が重要なのか

    現在のLLMの大きな課題はブラックボックス性です。

    • 規制対応:EU AI Actをはじめ、AIの透明性を求める規制が世界的に強化されている
    • 信頼性:医療・法律・金融など、根拠が必要な分野でのAI活用には透明性が不可欠
    • 研究:モデルの挙動を理解し改善するためには、内部の可視化が必要
    • 著作権:生成AIの出力が訓練データの著作物に基づいているかを検証可能に

    OLMo 3のアプローチは、これら全ての課題に対する回答です。

    試してみるには

    OLMo 3はGitHub上で完全に公開されています。Hugging Faceからモデルをダウンロードし、ローカルで実行できます。32Bモデルは量子化版であれば16GB程度のGPUメモリで動作します。

    OlmoTraceのデモもAI2のサイトで公開されており、ブラウザから試すことも可能です。「このAIはなぜこう答えたのか?」を自分の目で確かめられる体験は、LLMの理解を一段深めてくれるはずです。

    まとめ

    OLMo 3は「最も高性能なモデル」ではありません。しかし「最も透明なモデル」です。AIが社会インフラになりつつある今、「なぜその答えなのか」を追跡できることの価値は計り知れません。商用LLMがブラックボックスのままである以上、OLMo 3のようなプロジェクトの存在はAI業界全体にとって重要です。

  • Meta×AMD 1000億ドル契約とバッテリー不要IoT:海外インフラ・ハードウェアの激動

    2026年2月最終週、テックインフラの世界で歴史的な動きがありました。MetaとAMDの1000億ドル規模のチップ契約と、バッテリー不要IoTの業界標準化を目指すAmbient IoT Allianceの発足です。日本ではあまり報道されていませんが、いずれも今後のテック業界の方向を決定づける重要なニュースです。

    Meta × AMD:史上最大のAIチップ契約

    2月24日、MetaがAMDと最大1000億ドル(約15兆円)の複数年チップ契約を発表しました。AI史上最大の単一契約です。

    契約の詳細

    • ハードウェア:AMD Instinct MI450ベースのカスタムGPU + 第6世代EPYC CPU
    • 規模:最大6ギガワットのAMD GPUキャパシティを展開
    • 出荷開始:2026年下半期
    • 株式ワラント:AMDがMetaに対し、最大1億6000万株(発行済み株式の約10%)を1株あたり0.01ドルで発行するワラントを付与。マイルストーン達成に応じて権利確定

    なぜ重要か

    注目すべきは3つのポイントです。

    第一に、Nvidiaの独占が崩れ始めていること。MetaはNvidiaにも数百万個のGPUを発注していますが、AMDに1000億ドルを投じることで戦略的に分散化を図っています。

    第二に、株式ワラントという前例のないスキーム。ハードウェア契約に株式報酬を組み合わせるのは異例で、AMDの株価(とMetaの交渉力)に大きなインパクトを持ちます。

    第三に、AIインフラ投資の規模感。Alphabet、Amazon、Meta、Microsoftの4社で2026年のAIインフラ投資は合計約6500億ドルに達する見通しです。2025年の約4100億ドルから58%増です。

    Ambient IoT Alliance:バッテリー不要IoTの標準化

    2月23日、Ambient IoT Allianceが設立されました。バッテリー不要のIoTデバイスの標準化を推進する業界団体です。

    参加企業

    設立メンバーはAtmosic、Infineon、Intel、PepsiCo、Qualcomm、VusionGroup、Wiliot。半導体大手からPepsiCoのような消費財企業まで参加しているのが特徴です。

    エナジーハーベスティングIoTとは

    環境中のエネルギー(無線電波、光、振動、温度差など)を収集して動作するIoTデバイスです。バッテリーが不要なため、以下のような用途が想定されています。

    • サプライチェーン:商品の物流トラッキング(バッテリー交換不要)
    • 小売:電子棚札、在庫管理センサー
    • 環境モニタリング:農業、建物の構造監視
    • 医療:使い捨てセンサーパッチ

    PepsiCoの参加は、大手消費財企業がサプライチェーンの可視化にバッテリーレスIoTを本気で検討していることを示しています。ESP32のような汎用IoTチップとは異なるレイヤーですが、IoT業界全体の進化を加速させる動きです。

    まとめ

    ハードウェアとインフラの世界では、AI投資の爆発的な拡大と、IoTの新しいパラダイム(バッテリーレス)が同時進行しています。Nvidiaの独占崩壊とバッテリー不要IoTの標準化は、今後数年のテック業界を大きく変える可能性があります。日本でも注視すべきトレンドです。

  • GitHub Agentic WorkflowsとCursor並列エージェント:AI開発ツールの2026年2月最前線

    2026年2月、AI開発ツールの世界で2つの大きな動きがありました。GitHubが「Agentic Workflows」をテクニカルプレビューで公開し、CursorがAIエージェントの並列VM実行に対応。どちらも「AIアシスタント」から「AIエージェント」への転換を象徴する出来事です。

    GitHub Agentic Workflows:CI/CDをMarkdownで書く

    2月13日、GitHubが「Agentic Workflows」をテクニカルプレビューとして公開しました。最大の特徴は、CI/CDの自動化をYAMLではなくMarkdownで記述できることです。

    仕組み

    • .github/workflows/にMarkdownファイルを配置
    • gh aw CLIコマンドでMarkdownからGitHub Actionsに変換
    • 複数のAIエンジンに対応:Copilot CLI、Claude Code、OpenAI Codex
    • デフォルトは読み取り専用権限。PRの自動マージは不可
    • MITライセンスで完全オープンソース

    例えば「PRが作成されたらコードレビューして、テストが通ったらステージング環境にデプロイして」という指示を自然言語で書けば、AIエージェントがActionsのワークフローとして実行します。

    注目ポイント

    特に注目すべきはマルチエンジン対応です。Copilot CLIだけでなく、Claude CodeやOpenAI Codexも選択可能。ベンダーロックインを避けるGitHubの姿勢が見えます。セキュリティ面でもデフォルトでread-only、PRの自動マージ禁止と、慎重な設計です。

    Cursor:AIエージェントが並列VMで動く時代

    2月24日、AIコードエディタのCursorが大型アップデートを発表しました。AIエージェントが専用の仮想マシン(VM)上で並列実行できるようになりました。

    何が変わったか

    • 並列実行:複数のAIエージェントがそれぞれ独立したVM上で動作。ローカルPCのリソースを消費しない
    • 自己テスト:エージェントが自分で変更をテストし、ビデオ/スクリーンショットで結果を記録
    • プラグインシステム:Amplitude、AWS、Figma、Stripeなどとの統合
    • クロスプラットフォームサンドボックス:開発者の中断を40%削減
    • CursorのPRの約35%がVM上のエージェントによって生成

    パラダイムシフト

    これは「1ファイルのコード補完」から「10-20の並列エージェントが同時にタスクをこなす」への転換です。1つのエージェントにバグ修正を、別のエージェントにテスト追加を、さらに別のエージェントにドキュメント更新を任せる——そんなワークフローが現実になっています。

    AI開発ツールのトレンド

    これら2つの動きから見えるトレンドは明確です。

    1. 「アシスタント」から「エージェント」へ:補完ではなく、タスク全体を自律的に実行
    2. サンドボックスとセキュリティ:エージェントの権限管理が必須要件に
    3. マルチエンジン:特定のAIモデルに依存しない設計
    4. 並列処理:複数エージェントの同時実行が前提のアーキテクチャ

    2026年は「AIがコードを書く」から「AIチームがプロジェクトを回す」へと進化する年になりそうです。GitHub Agentic Workflowsはオープンソースなので、ぜひ試してみてください。

  • メモ帳がハッキングの入口に?Windows NotepadのRCE脆弱性とCopilotプロンプトインジェクションの衝撃

    2026年2月のMicrosoft Patch Tuesdayで、セキュリティ業界を騒がせる脆弱性が2つ明らかになりました。1つはWindows Notepad(メモ帳)のリモートコード実行(RCE)、もう1つはGitHub Copilotへのプロンプトインジェクション攻撃です。どちらも「信頼されてきたツール」が攻撃経路になるという点で、開発者なら知っておくべきニュースです。

    Windows Notepadにリモートコード実行(CVE-2026-20841)

    Windowsのメモ帳に新しく追加されたMarkdownレンダリング機能が、深刻な脆弱性の原因となりました。CVSSスコアは8.8(High)で、すでにGitHubにPoCエクスプロイトが公開されています。

    攻撃の仕組み

    攻撃者が細工した.mdファイルをメモ帳で開くと、Markdownレンダリング時に悪意のあるリンクが生成されます。ユーザーがそのリンクをクリックすると、メモ帳が未検証のプロトコルを起動し、リモートのファイルを実行してしまいます。

    つまり、「.mdファイルを開いてリンクをクリックしただけ」でマルウェアが実行される可能性があるということです。

    なぜ重要か

    メモ帳はWindowsで最も基本的な、最も信頼されてきたアプリケーションです。「メモ帳が危険」という概念自体が今までなかった。これはシンプルなツールに機能を追加する際のセキュリティリスクを如実に示す教訓です。2月のPatch Tuesdayで修正済みですが、Windows Updateを適用していない環境は注意が必要です。

    GitHub Copilotにプロンプトインジェクション脆弱性

    同じ2月のパッチで、GitHub Copilotに関する複数のCVEも修正されました。中でもCVE-2026-21516(CVSS 8.8)は、JetBrains版Copilotにおいてプロンプトインジェクションにより任意コード実行が可能というものです。

    攻撃シナリオ

    攻撃者がリポジトリのコードベースに悪意のあるプロンプトを埋め込みます(コメントやドキュメント内など)。開発者がそのリポジトリでCopilotのAIエージェント機能を使うと、エージェントが悪意のあるプロンプトを処理し、意図しないコードの実行やファイル操作を行ってしまいます。

    VS Code版(CVE-2026-21256)でも同様の問題が発見されています。

    AI時代の新しい脅威カテゴリ

    これは「プロンプトインジェクションが実際の攻撃ベクトルとなった」最初の大規模事例と言えます。AIコーディングアシスタントが「毒入りリポジトリ」から任意コードを実行するという脅威は、従来のセキュリティモデルでは想定されていませんでした。

    今後、AIエージェントの権限管理やサンドボックス設計がより重要になることは間違いありません。OSS リポジトリをクローンしてAIに分析させる際は、信頼性の確認が不可欠です。

    対策まとめ

    • Windows Updateを早急に適用する(2月のPatch Tuesday)
    • GitHub Copilotを最新版にアップデートする(VS Code、JetBrains両方)
    • 不審な.mdファイルをメモ帳で開かない
    • AIエージェントに未知のリポジトリを処理させる際は慎重に
    • AIツールの権限設定を最小限にする(read-onlyをデフォルトに)

    「信頼されたツール」が攻撃の入口になる時代。セキュリティの常識がアップデートされていることを、改めて認識させられるニュースでした。

  • Rust × ESP32開発が本格化:esp-hal 1.0のインパクトと始め方

    2025年10月、ESP32向けRust HAL「esp-hal」がバージョン1.0.0に到達しました。これはマイコンベンダーが公式にサポートする初の安定版Rust HALであり、組込みRust界にとって画期的な出来事です。この記事では、esp-hal 1.0の意義と、ESP32でRust開発を始める方法を解説します。

    esp-hal 1.0.0とは

    esp-halはEspressifが公式に開発・メンテナンスしている、ESP32ファミリー向けのRustハードウェア抽象化レイヤー(HAL)です。2025年2月にベータ版、10月に正式リリースされました。

    1.0で安定化された機能:

    • HAL初期化(esp_hal::init)と設定
    • GPIO、UART、SPI、I2Cドライバ
    • 時間モジュール(Instant、Duration、Rate)
    • async/blockingの両方のドライバモード
    • Embassyなどの非同期ランタイムとの互換性

    その他の機能はunstableフィーチャーフラグの下に配置され、段階的に安定化される予定です。次の大きな安定化ターゲットはWi-Fi/Bluetooth/ESP-NOWスタック「esp-radio」です。

    2つの開発アプローチ

    ESP32でRustを使う方法は2つあります。

    1. no_std + esp-hal(ベアメタル)

    OSを使わず、ハードウェアを直接制御するアプローチです。バイナリサイズが小さく、起動が速く、リアルタイム性が必要な場面に適しています。esp-hal 1.0はこのパスの安定版です。

    2. std + esp-idf-hal(IDF上で動作)

    ESP-IDFの上にRust標準ライブラリを載せるアプローチです。スレッド、ネットワーキング、ファイルシステムなど標準ライブラリの機能がフルに使えます。バイナリは大きくなりますが、機能の網羅性は高いです。

    LLVM Xtensaアップストリーム化

    ESP32・ESP32-S2・ESP32-S3が採用するXtensaアーキテクチャのLLVMサポートが、本家LLVMへのアップストリーム化が進んでいます。基本ISAの大部分はすでにLLVM本体に取り込まれており、将来的にはEspressifのカスタムLLVMフォークなしで、標準のRustツールチェーンからXtensaターゲットにコンパイルできるようになります。

    なお、RISC-VベースのESP32-C系/H系チップはすでに標準ツールチェーンでコンパイル可能です。

    始め方

    ESP32でRust開発を始める手順は以下のとおりです。

    1. RustインストールrustupでRustをインストール
    2. espupインストールcargo install espupでESP32用ツールチェーンマネージャを導入
    3. ツールチェーン構築espup installでXtensa対応ツールチェーンを自動セットアップ
    4. プロジェクト作成cargo generate esp-rs/esp-halテンプレートからプロジェクトを生成
    5. ビルド&フラッシュcargo runで実機にフラッシュして実行

    まとめ

    esp-hal 1.0.0のリリースにより、ESP32でのRust開発は「実験的」から「プロダクション対応」へと段階が上がりました。メモリ安全性とゼロコスト抽象化というRustの利点を、IoTデバイス開発で活かせる時代が来ています。C/C++に慣れた組込みエンジニアも、ぜひRust on ESP32を試してみてください。

  • ESP32-S3でTinyML入門:エッジAI推論を実装する方法

    クラウドに頼らず、マイコン上で直接AI推論を行う「TinyML」が注目を集めています。ESP32-S3はベクトル命令拡張を備え、TinyMLに最適なチップの一つです。この記事では、ESP32-S3でのエッジAI開発について、ツールチェーンからモデルデプロイまで解説します。

    なぜESP32-S3なのか

    ESP32-S3はデュアルコアXtensa LX7(最大240MHz)に加え、ベクトル命令拡張を搭載しています。これにより畳み込みニューラルネットワーク(CNN)の演算が高速化されます。ESP-NNライブラリがこれらの命令を最適に活用し、推論電力は約130〜157mW、レイテンシはモデルサイズに応じて7ms〜536msです。

    実用的な性能として、小型CNNなら約20FPS、中規模モデルでも約1FPSで推論可能です。顔検出、動体検知、音声コマンド認識などのユースケースに十分な性能です。

    ESP-DL:Espressif公式ディープラーニングライブラリ

    Espressifが提供するESP-DLは、ESP32向けの公式ディープラーニングフレームワークです。2025年に大幅なアップデートが行われました。

    ESP-DL v3.2(2025年10月)の主な特徴:

    • 独自のモデルフォーマット「.espdl」(FlatBuffersベースで高速なゼロコピー読み込み)
    • 8bit/16bit量子化サポート
    • ESP32-S3/P4向けのアセンブリ最適化カーネル(PIE命令活用)
    • Conv、Gemm、Add、Mulなどの主要演算をハードウェアアクセラレーション

    ESPDet-Pico:リアルタイム物体検出

    2025年4月にリリースされたESPDet-PicoはUltralytics YOLOv11ベースの軽量物体検出モデルです。歩行者検出、顔検出、COCO(YOLO11n)、猫・犬・手の検出など、事前学習済みモデルが提供されており、ESP32-S3上でリアルタイム推論が可能です。

    開発フロー

    ESP32でTinyMLを始める基本的な流れは以下のとおりです。

    1. モデル学習:PC上でPyTorch/TensorFlowでモデルを学習
    2. 量子化:esp-ppqツールで8bit/16bitに量子化し、.espdlフォーマットに変換
    3. デプロイ:ESP-DLライブラリを使ってESP32上でモデルをロード・推論
    4. 最適化:ESP-NN/PIE命令による自動最適化が適用される

    より手軽に始めたい場合はEdge Impulseがおすすめです。Webブラウザ上でデータ収集からモデル学習、ESP32へのデプロイまで一貫して行えます。深いML知識がなくても物体検出や音声認識モデルを構築できます。

    ESP32-S3 + カメラの活用例

    ESP32-S3はカメラインターフェースを備えているため、映像系のAIアプリケーションに強みがあります。DFRobotの「ESP32-S3 AI Camera」(8MB PSRAM、16MBフラッシュ)は、顔認識・物体検出・音声対話をエッジで実行できる開発ボードとして2025年に発売されました。

    代表的なユースケース:

    • Ringの代替となるローカル動作のドアベルカメラ
    • ペット検知・見守りカメラ
    • 製造ラインでの外観検査
    • 来客カウンターや人流分析

    まとめ

    ESP32-S3はTinyMLの実用的なプラットフォームとして成熟しました。ESP-DL v3.2とESPDet-Picoにより、YOLOベースの物体検出まで手の届く範囲になっています。数百円のマイコンでAI推論ができる時代を、ぜひ体験してみてください。

  • ESP32の最新動向まとめ(2025-2026):新チップ・Wi-Fi 6・AI対応まで完全解説

    IoT開発者にとって定番のESP32ファミリーですが、2025〜2026年にかけて大きな進化を遂げています。新チップの量産開始、Wi-Fi 6対応、AI推論機能の強化など、注目すべきアップデートが目白押しです。この記事では、ESP32エコシステムの最新動向を網羅的にまとめます。

    新チップラインナップの拡充

    Espressifは従来のESP32シリーズに加え、用途特化型の新チップを続々とリリースしています。

    ESP32-P4:高性能HMI向けSoC

    ESP32-P4はEspressif史上最もパワフルなチップです。デュアルコアRISC-V(最大400MHz)を搭載し、MIPI-CSI/DSIによる1080pカメラ入力・ディスプレイ出力、ハードウェアH.264エンコーダ(1080p@30fps)、55本のGPIOを備えています。

    注目点はWi-Fi/Bluetoothを内蔵しないこと。無線通信はESP32-C6などのコンパニオンチップと組み合わせる設計です。WaveshareやGUITIONからP4+C6を統合した開発ボード(約14ドル〜)が発売されています。

    ESP32-C5:業界初デュアルバンドWi-Fi 6対応MCU

    2025年5月に量産開始されたESP32-C5は、RISC-Vベースで2.4GHz + 5GHzのデュアルバンドWi-Fi 6(802.11ax)に対応した業界初のMCUです。従来のESP32はすべて2.4GHzのみだったため、5GHz帯が使えるのは大きな進化です。さらにBluetooth 5やIEEE 802.15.4(Zigbee/Thread)にも対応しています。

    CES 2026で発表:ESP32-E22とESP32-H21

    ESP32-E22はWi-Fi 6E(2.4/5/6GHz トライバンド)に対応し、2×2 MIMOで最大2.4Gbpsのデータレートを実現。デュアルコア500MHz RISC-Vプロセッサを搭載し、無線コプロセッサとして動作します。

    ESP32-H21は超低消費電力BLE MCUで、96MHz RISC-V、320KB RAM、BLE + IEEE 802.15.4対応。ウェアラブルやバッテリー駆動IoTノード向けです。

    開発フレームワークの進化

    ESP-IDF 6.0(2026年2月リリース)

    ESP-IDFのメジャーアップデートであるv6.0が2026年2月13日にリリースされました。主な変更点はMbedTLS v4シリーズへのアップグレードとPSA Crypto APIへの移行です。暗号化APIの使い方に破壊的変更があるため、既存プロジェクトの移行には注意が必要です。

    Arduino ESP32 Core 3.x

    Arduino ESP32 Core 3.0はESP-IDF 5.1ベースに刷新され、ESP32-C6やESP32-H2のサポートが追加されました。8つの周辺機器APIが更新され、ネイティブI2Cオーディオライブラリ、Ethernet SPIサポート(W5500、DM9051等)も追加されています。2.x系からの移行には破壊的変更があるため注意が必要です。

    セキュリティ:CVE-2025-27840「バックドア」騒動

    2025年3月、ESP32に29個の文書化されていないBluetooth HCIコマンドが見つかり「バックドア」として話題になりました。しかしEspressifは、これらはデバッグ用コマンドであり物理アクセスなしにはリモートで悪用できないと説明。ESP-IDF v5.5でこれらのコマンドをデフォルト無効化する修正が行われました。

    Matter/Thread対応の成熟

    スマートホーム標準プロトコル「Matter」への対応が着実に進んでいます。ESP32ファミリーはMatter 1.0認証を取得済みで、Thread Border RouterソリューションもThread V1.3認証を取得しています。ESPHome 2025.6.0ではOpenThreadサポートが追加され、ESP32-C6/H2をThreadエンドポイントとしてHome Assistantに直接接続できるようになりました。

    まとめ

    ESP32ファミリーは単なるWi-Fiマイコンから、Wi-Fi 6/6E、Thread/Matter、AI推論、1080p映像処理まで対応する総合IoTプラットフォームへと進化しています。用途に応じて最適なチップを選べるラインナップの充実が最大の魅力です。次回はESP32でのAI/TinyMLについて詳しく解説します。

  • WordPress プラグイン開発入門:OOP設計でメンテナブルなプラグインを作る

    WordPressプラグインの開発は、functions.phpにコードを追加する延長線上にありますが、本格的なプラグインはOOP(オブジェクト指向)で設計すべきです。この記事では、保守性が高く拡張しやすいプラグインの作り方を解説します。

    プラグインのディレクトリ構成

    my-awesome-plugin/
    ├── my-awesome-plugin.php    # メインファイル(エントリポイント)
    ├── includes/
    │   ├── class-plugin.php     # プラグインのメインクラス
    │   ├── class-admin.php      # 管理画面の処理
    │   ├── class-api.php        # REST APIエンドポイント
    │   └── class-db.php         # データベース操作
    ├── admin/
    │   ├── views/               # 管理画面テンプレート
    │   ├── css/
    │   └── js/
    ├── public/
    │   ├── css/
    │   └── js/
    ├── languages/               # 翻訳ファイル
    └── readme.txt               # WordPress.org用

    メインファイル

    <?php
    /**
     * Plugin Name: My Awesome Plugin
     * Description: プラグインの説明
     * Version: 1.0.0
     * Author: Your Name
     * Text Domain: my-awesome-plugin
     */
    
    if (!defined("ABSPATH")) exit;
    
    define("MAP_VERSION", "1.0.0");
    define("MAP_PLUGIN_DIR", plugin_dir_path(__FILE__));
    define("MAP_PLUGIN_URL", plugin_dir_url(__FILE__));
    
    require_once MAP_PLUGIN_DIR . "includes/class-plugin.php";
    
    // プラグイン初期化
    function map_init() {
        return MyAwesomePluginPlugin::get_instance();
    }
    add_action("plugins_loaded", "map_init");
    
    // アクティベーション・ディアクティベーション
    register_activation_hook(__FILE__, ["MyAwesomePluginPlugin", "activate"]);
    register_deactivation_hook(__FILE__, ["MyAwesomePluginPlugin", "deactivate"]);

    プラグインのメインクラス(シングルトン)

    <?php
    namespace MyAwesomePlugin;
    
    class Plugin {
        private static $instance = null;
    
        public static function get_instance() {
            if (self::$instance === null) {
                self::$instance = new self();
            }
            return self::$instance;
        }
    
        private function __construct() {
            $this->load_dependencies();
            $this->init_hooks();
        }
    
        private function load_dependencies() {
            require_once MAP_PLUGIN_DIR . "includes/class-admin.php";
            require_once MAP_PLUGIN_DIR . "includes/class-api.php";
            require_once MAP_PLUGIN_DIR . "includes/class-db.php";
        }
    
        private function init_hooks() {
            // 管理画面
            if (is_admin()) {
                new Admin();
            }
            // REST API
            add_action("rest_api_init", [new Api(), "register_routes"]);
            // フロントエンド
            add_action("wp_enqueue_scripts", [$this, "enqueue_public_assets"]);
        }
    
        public function enqueue_public_assets() {
            wp_enqueue_style(
                "map-public",
                MAP_PLUGIN_URL . "public/css/style.css",
                [],
                MAP_VERSION
            );
            wp_enqueue_script(
                "map-public",
                MAP_PLUGIN_URL . "public/js/main.js",
                [],
                MAP_VERSION,
                true
            );
            // JSにデータを渡す
            wp_localize_script("map-public", "mapConfig", [
                "ajaxUrl" => admin_url("admin-ajax.php"),
                "apiUrl" => rest_url("my-plugin/v1/"),
                "nonce" => wp_create_nonce("wp_rest"),
            ]);
        }
    
        public static function activate() {
            Db::create_tables();
            flush_rewrite_rules();
        }
    
        public static function deactivate() {
            flush_rewrite_rules();
        }
    }

    管理画面クラス

    <?php
    namespace MyAwesomePlugin;
    
    class Admin {
        public function __construct() {
            add_action("admin_menu", [$this, "add_menu"]);
            add_action("admin_init", [$this, "register_settings"]);
        }
    
        public function add_menu() {
            add_options_page(
                "My Plugin設定",
                "My Plugin",
                "manage_options",
                "my-awesome-plugin",
                [$this, "render_settings_page"]
            );
        }
    
        public function register_settings() {
            register_setting("map_settings", "map_api_key");
            register_setting("map_settings", "map_enabled");
        }
    
        public function render_settings_page() {
            include MAP_PLUGIN_DIR . "admin/views/settings.php";
        }
    }

    データベースクラス

    <?php
    namespace MyAwesomePlugin;
    
    class Db {
        public static function create_tables() {
            global $wpdb;
            $table = $wpdb->prefix . "map_logs";
            $charset = $wpdb->get_charset_collate();
    
            $sql = "CREATE TABLE IF NOT EXISTS $table (
                id bigint(20) NOT NULL AUTO_INCREMENT,
                user_id bigint(20) DEFAULT NULL,
                action varchar(50) NOT NULL,
                data longtext,
                created_at datetime DEFAULT CURRENT_TIMESTAMP,
                PRIMARY KEY (id),
                KEY user_id (user_id),
                KEY created_at (created_at)
            ) $charset;";
    
            require_once ABSPATH . "wp-admin/includes/upgrade.php";
            dbDelta($sql);
        }
    
        public static function insert_log($action, $data = null) {
            global $wpdb;
            return $wpdb->insert(
                $wpdb->prefix . "map_logs",
                [
                    "user_id" => get_current_user_id(),
                    "action" => $action,
                    "data" => is_array($data) ? json_encode($data) : $data,
                ],
                ["%d", "%s", "%s"]
            );
        }
    }

    セキュリティのベストプラクティス

    • ABSPATH チェック: 全PHPファイルの先頭で if (!defined("ABSPATH")) exit; を記述
    • Nonceの検証: フォーム送信やAjaxリクエストでは必ずnonce検証を行う
    • 権限チェック: current_user_can() で適切な権限を確認
    • サニタイズ: 入力値は sanitize_text_field()、出力は esc_html() で処理
    • SQLインジェクション対策: $wpdb->prepare() を使用

    まとめ

    OOP設計でプラグインを作ることで、コードの見通しが良くなり、チーム開発やメンテナンスが格段に楽になります。最初は少し面倒に感じるかもしれませんが、一度フレームワークを作ってしまえば、新しいプラグインでも使い回せます。WordPress公式ディレクトリへの公開を目指す場合も、この設計であればレビューを通過しやすいでしょう。

  • WordPress REST APIでヘッドレスCMS構築:Next.jsフロントエンドと連携する実践テクニック

    WordPressをヘッドレスCMSとして使い、フロントエンドをNext.jsで構築するアーキテクチャが注目されています。コンテンツ管理はWordPressの使いやすい管理画面で、表示はモダンなReactアプリで、という両方の良いところを取る手法です。

    WordPress REST APIの基本

    WordPress 4.7以降、REST APIが標準搭載されています。/wp-json/wp/v2/ 以下のエンドポイントで投稿・ページ・カテゴリなどのデータをJSON形式で取得できます。

    # 投稿一覧を取得
    curl https://your-site.com/wp-json/wp/v2/posts
    
    # 特定の投稿を取得
    curl https://your-site.com/wp-json/wp/v2/posts/123
    
    # カテゴリ一覧
    curl https://your-site.com/wp-json/wp/v2/categories
    
    # 検索
    curl "https://your-site.com/wp-json/wp/v2/posts?search=React"
    
    # ページネーション
    curl "https://your-site.com/wp-json/wp/v2/posts?per_page=10&page=2"

    Next.jsプロジェクトのセットアップ

    npx create-next-app@latest wp-frontend --typescript --app
    cd wp-frontend

    WordPress APIクライアント

    // lib/wordpress.ts
    const API_URL = process.env.WORDPRESS_API_URL || "https://your-site.com/wp-json/wp/v2";
    
    export interface WPPost {
      id: number;
      slug: string;
      title: { rendered: string };
      content: { rendered: string };
      excerpt: { rendered: string };
      date: string;
      categories: number[];
      _embedded?: {
        "wp:featuredmedia"?: Array<{ source_url: string }>;
      };
    }
    
    export async function getPosts(page = 1, perPage = 10): Promise<WPPost[]> {
      const res = await fetch(
        `${API_URL}/posts?_embed&per_page=${perPage}&page=${page}`,
        { next: { revalidate: 3600 } } // ISR: 1時間キャッシュ
      );
      if (!res.ok) throw new Error("Failed to fetch posts");
      return res.json();
    }
    
    export async function getPostBySlug(slug: string): Promise<WPPost | null> {
      const res = await fetch(
        `${API_URL}/posts?_embed&slug=${slug}`,
        { next: { revalidate: 3600 } }
      );
      const posts = await res.json();
      return posts[0] || null;
    }
    
    export async function getCategories() {
      const res = await fetch(`${API_URL}/categories`);
      return res.json();
    }

    投稿一覧ページ

    // app/page.tsx
    import { getPosts } from "@/lib/wordpress";
    import Link from "next/link";
    
    export default async function Home() {
      const posts = await getPosts();
    
      return (
        <main>
          <h1>ブログ</h1>
          {posts.map((post) => (
            <article key={post.id}>
              <Link href={`/posts/${post.slug}`}>
                <h2 dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
              </Link>
              <div dangerouslySetInnerHTML={{ __html: post.excerpt.rendered }} />
              <time>{new Date(post.date).toLocaleDateString("ja-JP")}</time>
            </article>
          ))}
        </main>
      );
    }

    投稿詳細ページ

    // app/posts/[slug]/page.tsx
    import { getPostBySlug, getPosts } from "@/lib/wordpress";
    import { notFound } from "next/navigation";
    
    export async function generateStaticParams() {
      const posts = await getPosts(1, 100);
      return posts.map((post) => ({ slug: post.slug }));
    }
    
    export default async function PostPage({ params }: { params: { slug: string } }) {
      const post = await getPostBySlug(params.slug);
      if (!post) notFound();
    
      return (
        <article>
          <h1 dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
          <time>{new Date(post.date).toLocaleDateString("ja-JP")}</time>
          <div dangerouslySetInnerHTML={{ __html: post.content.rendered }} />
        </article>
      );
    }

    カスタムエンドポイントの追加

    functions.phpでカスタムREST APIエンドポイントを追加できます。人気記事ランキングや関連記事など、標準APIにない機能を実装する場合に使います。

    // functions.php
    add_action("rest_api_init", function() {
        register_rest_route("custom/v1", "/popular", [
            "methods" => "GET",
            "callback" => function() {
                $posts = get_posts([
                    "meta_key" => "post_views",
                    "orderby" => "meta_value_num",
                    "order" => "DESC",
                    "numberposts" => 5,
                ]);
                return array_map(function($p) {
                    return [
                        "id" => $p->ID,
                        "title" => $p->post_title,
                        "slug" => $p->post_name,
                        "views" => get_post_meta($p->ID, "post_views", true),
                    ];
                }, $posts);
            },
            "permission_callback" => "__return_true",
        ]);
    });

    CORS設定

    ヘッドレス構成ではフロントエンドとWordPressが別ドメインになるため、CORS設定が必要です。

    // functions.php
    add_action("rest_api_init", function() {
        remove_filter("rest_pre_serve_request", "rest_send_cors_headers");
        add_filter("rest_pre_serve_request", function($value) {
            header("Access-Control-Allow-Origin: https://your-frontend.com");
            header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
            header("Access-Control-Allow-Headers: Content-Type, Authorization");
            return $value;
        });
    });

    まとめ

    WordPressのREST APIとNext.jsを組み合わせることで、編集者にはWordPressの使いやすいUIを、ユーザーにはReactベースの高速な表示体験を提供できます。ISRを使えばビルド不要で最新コンテンツが反映される、最強のブログ基盤が構築できます。

  • WordPress 6.x ブロックエディタの進化まとめ:サイトエディタ・パターン・スタイルブック完全ガイド

    WordPress 6.x系では、ブロックエディタ(Gutenberg)が大幅に進化しました。サイトエディタの安定化、パターンシステムの刷新、スタイルブックの導入など、サイト構築のワークフローが根本から変わっています。この記事では、WordPress 6.0〜6.7で追加された主要機能を実践的に解説します。

    サイトエディタ(Full Site Editing)の成熟

    WordPress 6.2でサイトエディタがベータから正式版に昇格しました。ヘッダー、フッター、サイドバーを含むサイト全体をブロックエディタで編集できます。

    サイトエディタでは「テンプレート」と「テンプレートパーツ」を直接編集できます。PHPテンプレートファイルを触らずに、ビジュアルエディタ上でレイアウトを組み替えられるのは革命的です。

    テンプレートの種類

    • ページテンプレート: 固定ページ・投稿ごとに異なるレイアウトを適用
    • アーカイブテンプレート: カテゴリ・タグ一覧ページのレイアウト
    • 検索結果テンプレート: 検索結果ページの表示形式
    • 404テンプレート: ページが見つからない場合の表示

    パターンシステムの刷新

    WordPress 6.3で「再利用ブロック」が「パターン」に統合されました。パターンには2種類あります。

    • 同期パターン(旧:再利用ブロック): 一箇所を編集すると全ての使用箇所に反映される
    • 非同期パターン: テンプレートとして挿入。挿入後は独立して編集可能

    テーマ開発者は、patternsディレクトリにPHPファイルを配置するだけでカスタムパターンを登録できます。

    // patterns/hero-section.php
    <?php
    /**
     * Title: ヒーローセクション
     * Slug: mytheme/hero-section
     * Categories: featured
     */
    ?>
    <!-- wp:cover {"dimRatio":50} -->
    <div class="wp-block-cover">
      <div class="wp-block-cover__inner-container">
        <!-- wp:heading {"textAlign":"center","level":1} -->
        <h1 class="has-text-align-center">サイトタイトル</h1>
        <!-- /wp:heading -->
        <!-- wp:paragraph {"align":"center"} -->
        <p class="has-text-align-center">サブタイトルテキスト</p>
        <!-- /wp:paragraph -->
      </div>
    </div>
    <!-- /wp:cover -->

    スタイルブック

    WordPress 6.2で導入されたスタイルブックは、サイト内の全ブロックの見た目を一覧で確認・編集できる機能です。「外観」→「エディター」→「スタイル」からアクセスできます。

    見出し、段落、ボタン、テーブルなど全てのブロックタイプのスタイルを、実際のプレビューを見ながらカスタマイズできます。CSSを一行も書かずに、サイト全体のデザインシステムを構築できるのは非常に強力です。

    theme.jsonの進化

    theme.jsonはブロックテーマの心臓部です。バージョン2(WordPress 6.1〜)では、設定項目が大幅に増えました。

    {
      "$schema": "https://schemas.wp.org/trunk/theme.json",
      "version": 3,
      "settings": {
        "color": {
          "palette": [
            { "slug": "primary", "color": "#1a73e8", "name": "プライマリ" },
            { "slug": "secondary", "color": "#333", "name": "セカンダリ" }
          ],
          "gradients": [],
          "custom": false
        },
        "typography": {
          "fontFamilies": [
            {
              "fontFamily": "-apple-system, BlinkMacSystemFont, sans-serif",
              "slug": "system",
              "name": "システムフォント"
            }
          ],
          "fontSizes": [
            { "slug": "small", "size": "14px", "name": "小" },
            { "slug": "medium", "size": "16px", "name": "中" },
            { "slug": "large", "size": "24px", "name": "大" }
          ]
        },
        "spacing": {
          "units": ["px", "rem", "%"]
        },
        "layout": {
          "contentSize": "800px",
          "wideSize": "1200px"
        }
      },
      "styles": {
        "blocks": {
          "core/heading": {
            "typography": { "fontWeight": "700" }
          }
        }
      }
    }

    WordPress 6.5〜6.7の注目機能

    • フォントライブラリ(6.5): Google Fontsやローカルフォントをアップロードして管理画面から適用
    • ブロックバインディングAPI(6.5): ブロックの属性をカスタムフィールドや外部データに動的にバインド
    • データビュー(6.6): 投稿・ページ一覧がグリッド表示に対応、フィルタ・ソート機能が強化
    • セクションスタイル(6.7): グループブロックにスタイルバリエーションを適用して、セクション単位でデザインを切り替え

    クラシックテーマからの移行

    既存のクラシックテーマ(PHPテンプレートベース)からブロックテーマへの移行は段階的に行えます。まずは「テーマサポート」を追加してブロックエディタの機能を有効にし、徐々にテンプレートをブロックベースに置き換えていくアプローチが現実的です。

    まとめ

    WordPress 6.x系のブロックエディタは、もはや単なる記事エディタではなく、サイト全体を構築するフルサイトエディティングツールへと進化しました。theme.jsonとパターンを活用すれば、コードを最小限に抑えつつ、高品質なテーマを開発できます。

IP: 取得中...
216.73.216.31216.73.216.31