投稿者: ryuji

  • 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はオープンソースなので、ぜひ試してみてください。

  • 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について詳しく解説します。

  • 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推論ができる時代を、ぜひ体験してみてください。

  • 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とパターンを活用すれば、コードを最小限に抑えつつ、高品質なテーマを開発できます。

  • Docker ComposeでNode.js + PostgreSQL環境を5分で構築する

    開発環境の構築は地味に時間がかかる作業です。Docker Composeを使えば、Node.jsアプリケーションとPostgreSQLデータベースを含む開発環境を、たった1コマンドで立ち上げることができます。

    前提条件

    • Docker Desktop がインストール済み
    • docker compose コマンドが使える状態

    プロジェクト構成

    my-app/
    ├── docker-compose.yml
    ├── Dockerfile
    ├── package.json
    ├── src/
    │   └── index.js
    └── .env

    docker-compose.yml

    version: "3.8"
    services:
      app:
        build: .
        ports:
          - "3000:3000"
        environment:
          - DATABASE_URL=postgresql://myuser:mypass@db:5432/mydb
          - NODE_ENV=development
        volumes:
          - ./src:/app/src
        depends_on:
          db:
            condition: service_healthy
    
      db:
        image: postgres:16-alpine
        environment:
          POSTGRES_USER: myuser
          POSTGRES_PASSWORD: mypass
          POSTGRES_DB: mydb
        ports:
          - "5432:5432"
        volumes:
          - pgdata:/var/lib/postgresql/data
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U myuser -d mydb"]
          interval: 5s
          timeout: 5s
          retries: 5
    
    volumes:
      pgdata:

    Dockerfile

    FROM node:20-alpine
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci
    COPY src/ ./src/
    EXPOSE 3000
    CMD ["node", "src/index.js"]

    Node.jsアプリケーション

    // src/index.js
    const { Pool } = require("pg");
    const http = require("http");
    
    const pool = new Pool({
      connectionString: process.env.DATABASE_URL,
    });
    
    const server = http.createServer(async (req, res) => {
      try {
        const result = await pool.query("SELECT NOW() as current_time");
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({
          message: "Hello from Docker!",
          db_time: result.rows[0].current_time,
        }));
      } catch (err) {
        res.writeHead(500);
        res.end(JSON.stringify({ error: err.message }));
      }
    });
    
    server.listen(3000, () => {
      console.log("Server running on port 3000");
    });

    起動と確認

    # ビルド&起動
    docker compose up -d
    
    # ログ確認
    docker compose logs -f app
    
    # 動作確認
    curl http://localhost:3000

    開発時のTips

    • volumesでsrcディレクトリをマウントしておけば、ファイル変更が即座に反映されます(nodemonと組み合わせると便利)
    • healthcheckを設定しておくと、DBが起動する前にアプリが接続しようとするエラーを防げます
    • PostgreSQLのデータはnamed volumeに保存されるので、コンテナを再作成してもデータは消えません

    まとめ

    Docker Composeを使えば、チームメンバー全員が同じ環境で開発できます。新メンバーのオンボーディングも「git cloneしてdocker compose up」だけで完了。環境差異によるトラブルから解放されます。

  • PythonのFastAPIで爆速REST API開発:非同期処理とバリデーション

    FastAPIはPython製のWebフレームワークで、型ヒントを活用した自動バリデーション、自動ドキュメント生成、非同期処理対応が特徴です。Flask比で200%以上のパフォーマンス向上が見込めます。

    FastAPIの特徴

    • Python型ヒントによる自動バリデーション
    • OpenAPI(Swagger)ドキュメント自動生成
    • async/await対応の非同期処理
    • Pydanticモデルによるデータシリアライゼーション
    • StarletteベースのASGIフレームワーク

    インストールと最初のAPI

    pip install "fastapi[standard]"
    # main.py
    from fastapi import FastAPI, HTTPException
    from pydantic import BaseModel, Field
    from typing import Optional
    import uvicorn
    
    app = FastAPI(title="商品管理API", version="1.0.0")
    
    class Product(BaseModel):
        name: str = Field(..., min_length=1, max_length=100)
        price: int = Field(..., gt=0, description="価格(円)")
        description: Optional[str] = None
        in_stock: bool = True
    
    # インメモリDB
    products: dict[int, Product] = {}
    next_id = 1
    
    @app.post("/products", status_code=201)
    async def create_product(product: Product):
        global next_id
        product_id = next_id
        products[product_id] = product
        next_id += 1
        return {"id": product_id, **product.model_dump()}
    
    @app.get("/products/{product_id}")
    async def get_product(product_id: int):
        if product_id not in products:
            raise HTTPException(status_code=404, detail="商品が見つかりません")
        return {"id": product_id, **products[product_id].model_dump()}
    
    @app.get("/products")
    async def list_products(
        min_price: Optional[int] = None,
        max_price: Optional[int] = None,
        in_stock: Optional[bool] = None,
    ):
        result = []
        for pid, p in products.items():
            if min_price and p.price  max_price:
                continue
            if in_stock is not None and p.in_stock != in_stock:
                continue
            result.append({"id": pid, **p.model_dump()})
        return result
    
    if __name__ == "__main__":
        uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

    自動ドキュメント

    FastAPIは起動するだけで以下のドキュメントが自動生成されます。

    • Swagger UI: http://localhost:8000/docs – インタラクティブなAPI操作画面
    • ReDoc: http://localhost:8000/redoc – 読みやすいドキュメント形式

    非同期処理

    FastAPIはasync/awaitをネイティブサポートしています。DB操作やHTTPリクエストなどのI/O処理を非同期で実行できます。

    import httpx
    
    @app.get("/external-data")
    async def get_external_data():
        async with httpx.AsyncClient() as client:
            response = await client.get("https://api.example.com/data")
            return response.json()

    まとめ

    FastAPIは、型安全性・パフォーマンス・開発体験の全てにおいて優れたフレームワークです。AI APIのバックエンド、マイクロサービス、プロトタイプ開発など幅広い場面で活躍します。

IP: 取得中...
216.73.217.150216.73.217.150