2026年7月27日

2026年7月27日

WordPressプラグイン開発の基礎【ヘッダー・フック・有効化処理】

はじめに

WordPressプラグインは、コアファイルを変更せずにサイトの機能を拡張できる強力な仕組みです。プラグイン開発の基礎を理解することで、既製品では対応できない独自の機能を安全に実装できます。本記事では、プラグインファイルの作成から有効化処理・フックの登録まで、実践的な手順を解説します。

症状・原因

  • 既存プラグインでは要件を満たせず、独自機能の実装が必要になった
  • テーマのfunctions.phpが肥大化し、プラグインとして分離したい
  • WordPressのアップデートやテーマ変更に影響されない形でカスタマイズしたい

解決手順

ステップ1:プラグインヘッダーコメントを記述する

<?php
/**
 * Plugin Name: My Custom Plugin
 * Plugin URI:  https://example.com/my-custom-plugin
 * Description: サイト独自の機能を追加するカスタムプラグイン
 * Version:     1.0.0
 * Author:      Your Name
 * Author URI:  https://example.com
 * License:     GPL-2.0-or-later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: my-custom-plugin
 * Domain Path: /languages
 */

// このファイルが直接アクセスされた場合に処理を停止するセキュリティチェック
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

ステップ2:プラグイン定数とセキュリティチェックを設定する

<?php
// セキュリティ: WordPressを経由しない直接アクセスを防止
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// プラグイン定数を定義(パスとURLの管理を一元化)
define( 'MCP_VERSION',     '1.0.0' );
define( 'MCP_PLUGIN_DIR',  plugin_dir_path( __FILE__ ) );
define( 'MCP_PLUGIN_URL',  plugin_dir_url( __FILE__ ) );
define( 'MCP_PLUGIN_BASE', plugin_basename( __FILE__ ) );

// plugin_dir_path() → 末尾スラッシュ付きの絶対パスを返す
// plugin_dir_url()  → 末尾スラッシュ付きのURLを返す
// plugin_basename() → 「フォルダ名/ファイル名.php」形式を返す

ステップ3:有効化・無効化フックを登録する

<?php
// プラグイン有効化時に実行される処理を登録
register_activation_hook( __FILE__, 'mcp_activate' );

// プラグイン無効化時に実行される処理を登録
register_deactivation_hook( __FILE__, 'mcp_deactivate' );

/**
 * 有効化時:データベーステーブルの作成やオプションの初期化
 */
function mcp_activate() {
    // デフォルト設定を保存(すでに存在する場合は上書きしない)
    add_option( 'mcp_settings', array(
        'enable_feature' => true,
        'cache_duration' => 3600,
    ) );

    // カスタムテーブルの作成例
    global $wpdb;
    $table_name = $wpdb->prefix . 'mcp_logs';
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE IF NOT EXISTS {$table_name} (
        id bigint(20) NOT NULL AUTO_INCREMENT,
        message text NOT NULL,
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id)
    ) {$charset_collate};";

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta( $sql ); // テーブルが存在しなければ作成、存在すれば差分のみ適用

    // パーマリンクをフラッシュ(カスタム投稿タイプ追加時などに必要)
    flush_rewrite_rules();
}

/**
 * 無効化時:一時データのクリーンアップ(オプションは削除しない)
 */
function mcp_deactivate() {
    // 一時的なキャッシュデータを削除
    delete_transient( 'mcp_cache' );

    // パーマリンクをリセット
    flush_rewrite_rules();
}

ステップ4:add_action・add_filterでフックを登録する

<?php
// アクションフック:WordPressの処理に独自の処理を「追加」する
add_action( 'wp_enqueue_scripts', 'mcp_enqueue_assets' );
add_action( 'init',               'mcp_register_post_type' );
add_action( 'save_post',          'mcp_save_post_data', 10, 3 );
// 第3引数:優先度(デフォルト10、数値が小さいほど先に実行)
// 第4引数:コールバック関数が受け取る引数の数

// フィルターフック:WordPressのデータを「変更」して返す
add_filter( 'the_content',        'mcp_filter_content' );
add_filter( 'wp_title',           'mcp_filter_title', 10, 2 );

/**
 * フロントエンド用スタイル・スクリプトの読み込み
 */
function mcp_enqueue_assets() {
    // CSSの読み込み
    wp_enqueue_style(
        'mcp-style',                        // ハンドル名(一意の識別子)
        MCP_PLUGIN_URL . 'assets/style.css', // CSSファイルのURL
        array(),                             // 依存するスタイルのハンドル名
        MCP_VERSION                          // バージョン(キャッシュバスティング用)
    );

    // JavaScriptの読み込み
    wp_enqueue_script(
        'mcp-script',
        MCP_PLUGIN_URL . 'assets/script.js',
        array( 'jquery' ),   // jQueryに依存
        MCP_VERSION,
        true                 // フッターに読み込む(trueが推奨)
    );

    // JavaScriptにPHP変数を渡す
    wp_localize_script( 'mcp-script', 'mcpData', array(
        'ajaxUrl' => admin_url( 'admin-ajax.php' ),
        'nonce'   => wp_create_nonce( 'mcp_nonce' ),
    ) );
}

/**
 * コンテンツフィルターの例
 */
function mcp_filter_content( $content ) {
    // 投稿の本文のみ処理(フィード等を除く)
    if ( ! is_singular() || ! in_the_loop() ) {
        return $content;
    }

    // コンテンツの末尾に追加情報を挿入
    $content .= '<div class="mcp-notice">この記事はカスタムプラグインで処理されました。</div>';
    return $content;
}

ステップ5:plugin_basename()とアセット読み込みを最適化する

<?php
/**
 * plugin_basename() の活用例:プラグイン管理リンクの追加
 */
add_filter( 'plugin_action_links_' . MCP_PLUGIN_BASE, 'mcp_add_settings_link' );

function mcp_add_settings_link( $links ) {
    // プラグイン一覧画面に「設定」リンクを追加
    $settings_link = '<a href="' . admin_url( 'options-general.php?page=mcp-settings' ) . '">'
        . __( '設定', 'my-custom-plugin' ) . '</a>';
    array_unshift( $links, $settings_link ); // リンクを先頭に追加
    return $links;
}

/**
 * 管理画面のみでスクリプトを読み込む(不要なページでの読み込みを防止)
 */
add_action( 'admin_enqueue_scripts', 'mcp_enqueue_admin_assets' );

function mcp_enqueue_admin_assets( $hook ) {
    // 特定の管理画面ページでのみ読み込む
    if ( 'settings_page_mcp-settings' !== $hook ) {
        return;
    }

    wp_enqueue_style(
        'mcp-admin-style',
        MCP_PLUGIN_URL . 'assets/admin.css',
        array(),
        MCP_VERSION
    );
}

/**
 * プラグインのアンインストール処理(uninstall.phpで定義)
 * register_uninstall_hook() で登録する方法もある
 */
// uninstall.php 内に記述:
// if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) exit;
// delete_option( 'mcp_settings' );
// $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}mcp_logs" );

注意事項

  • 直接アクセス防止: すべてのPHPファイルの先頭にif ( ! defined( 'ABSPATH' ) ) { exit; }を記述してください
  • 関数名の衝突: プラグイン固有のプレフィックス(例:mcp_)を関数名・定数名・クラス名に必ず付けてください
  • dbDelta()の利用: データベーステーブル作成には直接CREATE TABLEではなくdbDelta()を使用し、アップグレード時の安全性を確保してください
  • アンインストール処理: register_deactivation_hookではなくuninstall.phpまたはregister_uninstall_hookでデータ削除を行ってください

まとめ

WordPressプラグイン開発の基礎は、ヘッダーコメント・セキュリティチェック・有効化フック・add_action/add_filterの4つを押さえることで確立できます。これらの仕組みを理解することで、安全で保守しやすいプラグインを作成できます。関連記事:WordPressでショートコードを作成する方法

お気軽にご相談ください

お見積りへ お問い合わせへ