【PHP】WP用のページカウンタプラグイン

PHP

WordPress開発者リソースを見ていたらプラグインが作れそうだったので、ページ毎のカウンタを表示させるプラグインを作成しました。

実装した機能

●記事内にカウンタを表示
 カウンタの数字部分は、PNGファイルを表示
 同じユーザが画面を更新してもインクリメントされない

●カウンタのメニューを実装
 メニュー内で画像ファイルの表示サイズを変更可能
 画像ファイルのフォルダを指定

プラグインの作り方(ざっくり)

WordPress自体がPHPで動作していますので、プラグイン用のフォルダにプログラムを置けば認識されます。
あとは、プラグインを有効にすると使えるイメージです。
PHPエラーを出力すると、WordPressが全部停止しますので、業務で使用している方はテスト環境で作成することをお勧めします。

ざっくりとした流れ
①プラグインの認識
 plugins フォルダに、phpファイルを配置するだけでプラグインと認識される
②プラグインの有効化
 GUIだけでできます
③プラグインが使える

プラグインを認識させる

次の場所にフォルダを作成し、PHPファイルを配置してください

フォルダ構成
 url/wordpress/wp-content/plugins/
               ├ □ すでに入っているプラグイン
├ □ test_plugin
    ├ test.php         

PHPファイル

<?php
/*
Plugin Name: プラグインテスト
Plugin URI: https://tansunohazama.sakura.ne.jp/
Description: プラグインテスト
Version: 0.1
Author: ****
Author URI: https://tansunohazama.sakura.ne.jp/
*/

// 直接呼出しの禁止
if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}
?>

WordPressを起動し、メニューからプラグインを選択すると、

コメント内のプラグイン名等が表示される仕組みになっているようです。
有効化にチェックを入れるだけで、このプラグインが有効になります。

 if ( ! defined( ‘ABSPATH’ ) ) {
と書かれているのは、PHPファイルを直接呼び出された際にプログラムを実行させないためのものです。
直接実行されることによって思いもよらない誤作動や、情報漏洩に繋がりますので、必ず記載してください。
 このプラグインには何も機能がないので、有効化しても何も起きません。

ページカウンタプラグイン

プログラムは次の通りです。

フォルダ構成

/wp-content/plugins/tansu-counter
 ├ □ images
 │ └ [0~9].png 数字の画像ファイル
 ├ □ counters
├ □ includes
 │ ├ counter-functions.php
 │ ├ display-functions.php
 │ └ admin-settings.php
└ plugin-counter.php

plugin-counter.php

<?php
/*
Plugin Name: たんすのカウンター
Plugin URI: https://tansunohazama.sakura.ne.jp/
Description: ページ内カウンターを実装します
Version: 0.1
Author: kirabbit
Author URI: https://tansunohazama.sakura.ne.jp/
*/

// 直接呼出しの禁止
if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

// プラグインのディレクトリパス
define('PAGE_COUNTER_DIR', plugin_dir_path(__FILE__));
define('PAGE_COUNTER_URL', plugin_dir_url(__FILE__));

// インクルードファイル
require_once PAGE_COUNTER_DIR . 'includes/admin-settings.php';
require_once PAGE_COUNTER_DIR . 'includes/counter-functions.php';
require_once PAGE_COUNTER_DIR . 'includes/display-functions.php';

// hook 必要なディレクトリを作成
function create_counter_directory() {
    // カウンタの計算ファイル置き場
    $counter_dir = PAGE_COUNTER_DIR . 'counters/';
    if (!file_exists($counter_dir)) {
        mkdir($counter_dir, 0755, true);
    }
	
    //カウンタ用の画像置き場
    $images_dir = PAGE_COUNTER_DIR . 'images/';
    if (!file_exists($images_dir)) {
        mkdir($images_dir, 0755, true);
    }
}

//アクティベート時に実行される
register_activation_hook(__FILE__, 'create_counter_directory');
?>

counter-functions.php

<?php
if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * カウンタの更新機能
 * インクリメントロジック部
 */
function update_page_counter() {
    if (is_singular()) {
        $post_id = get_the_ID();
        $counter_file = PAGE_COUNTER_DIR . 'counters/' . $post_id . '.txt';

        // クライアントのIPアドレスを取得
        #$client_ip = $_SERVER['REMOTE_ADDR']; // -- 最終訪問者のIPアドレス漏洩対策
		$client_ip = hash('sha256', $_SERVER['REMOTE_ADDR'] . "sio2g");

        if (!file_exists($counter_file)) {
            // ファイルが存在しない場合はカウントを0、IPを現在のIPで初期化
            file_put_contents($counter_file, "1\t$client_ip");
        } else {
            // ファイルからカウント数と最後のIPアドレスを読み取る
            list($count, $last_ip) = explode("\t", file_get_contents($counter_file));

            // 同じIPアドレスからの訪問でない場合のみカウントを増加
            if ($client_ip !== trim($last_ip)) {
                $count++;
                file_put_contents($counter_file, "$count\t$client_ip");
            }
        }
    }
}
add_action('wp', 'update_page_counter');

display-functions.php

<?php
if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * カウンタ表示
 * 表示用HTML生成部(PNG)
 */
function display_page_counter_with_png() {
    if (is_singular()) {
        $post_id = get_the_ID();
        $counter_file = PAGE_COUNTER_DIR . 'counters/' . $post_id . '.txt';

        // 管理画面から取得した画像フォルダパスとサイズ設定を取得
        $image_path = get_option('page_counter_image_path', PAGE_COUNTER_URL . 'images/');
        $image_size = get_option('page_counter_image_size', 100);

        if (file_exists($counter_file)) {
            // ファイルからカウント数を取得
            list($count) = explode("\t", file_get_contents($counter_file));

            // カウント数を6桁のゼロパディングにする
            $counter = str_pad($count, 6, '0', STR_PAD_LEFT);
            $counter_digits = str_split($counter);
            $output = '<div style="display: inline-block;">';

            foreach ($counter_digits as $digit) {
                $png_url = $image_path . $digit . '.png';
                $output .= '<img src="' . esc_url($png_url) . '" alt="' . esc_attr($digit) . '" style="width: ' . intval($image_size) . 'px; height: auto; vertical-align: middle;">';
            }

            $output .= '</div>';
            return $output;
        } else {
            return '初めての訪問者です。';
        }
    }
}
add_shortcode('page_counter', 'display_page_counter_with_png');

/**
 * カウンタ表示
 * メニュー画面用 サンプルカウンタ
 */
function page_counter_sample_display() {
    $image_path = get_option('page_counter_image_path', PAGE_COUNTER_URL . 'images/');
    $image_size = get_option('page_counter_image_size', 100);

    // サンプル表示用の数字を作成(例: "000123")
    $sample_number = '000123';
    $sample_digits = str_split($sample_number);
    $output = '<div style="display: inline-block;">';

    foreach ($sample_digits as $digit) {
        $png_url = $image_path . $digit . '.png';
        $output .= '<img src="' . esc_url($png_url) . '" alt="' . esc_attr($digit) . '" style="width: ' . intval($image_size) . 'px; height: auto; vertical-align: middle;">';
    }

    $output .= '</div>';
    return $output;
}

admin-settings.php

<?php

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

/**
 * メニューにカウンタ設定メニューを追加する
 * 
 */
function page_counter_settings_menu() {
    add_options_page(
        'タンスのカウンタ設定',
        'タンスのカウンタ設定',
        'manage_options',
        'page-counter-settings',
        'page_counter_settings_page'
    );
}
add_action('admin_menu', 'page_counter_settings_menu');

/**
 * カウンタ設定ページの作成
 * 
 */
function page_counter_settings_page() {
    ?>
    <div class="wrap">
        <h1>タンスのカウンタ設定</h1>
        <form method="post" action="options.php">
            <?php settings_fields('page_counter_settings_group'); ?>
            <?php do_settings_sections('page-counter-settings'); ?>
            <?php submit_button(); ?>
        </form>
        ※[0.png] ~[9.png]を画像フォルダパスに配置してください。<br>
        <hr>
        <h2>サンプルカウンタ</h2>
        <div>
            <?php echo page_counter_sample_display(); ?>
        </div>
        <h2>使用方法</h2>
         カウンタを入れたい場所に、ショートコードを使って<br>
            [page_counter]<br>
        と入力してください。<br>
         閲覧したユーザが変わるたびにカウントされます。<br>
    </div>
    <?php
}

// カウンタ設定オプションを登録
function page_counter_settings_init() {
    register_setting('page_counter_settings_group', 'page_counter_image_path');
    register_setting('page_counter_settings_group', 'page_counter_image_size');

    add_settings_section(
        'page_counter_settings_section',
        'カウンタ画像設定',
        null,
        'page-counter-settings'
    );

    add_settings_field(
        'page_counter_image_path',
        '画像フォルダパス',
        'page_counter_image_path_callback',
        'page-counter-settings',
        'page_counter_settings_section'
    );

    add_settings_field(
        'page_counter_image_size',
        '画像一枚毎のサイズ(px)',
        'page_counter_image_size_callback',
        'page-counter-settings',
        'page_counter_settings_section'
    );
}
add_action('admin_init', 'page_counter_settings_init');

function page_counter_image_path_callback() {
    $image_path = get_option('page_counter_image_path', PAGE_COUNTER_URL . 'images/');
    echo '<input type="text" name="page_counter_image_path" value="' . esc_attr($image_path) . '" size="50">';
}

function page_counter_image_size_callback() {
    $image_size = get_option('page_counter_image_size', 100);
    echo '<input type="number" name="page_counter_image_size" value="' . esc_attr($image_size) . '" min="10" max="500">';
}

 HPを書いていて今更ながらに思ったのですが、こういう時にGITでソースを公開するといいのですね。
 

実行画面

管理者ページ

画像のサイズ変更と、サンプルカウンタを表示しました

●使い方

記事作成画面上に
   ショートコードで

000020

と入力すると、ページカウンタが表示されるようになります。

ページ全体のカウンタを作ってもよかったのですが、全体のカウンタだとショートコードで毎回入力する必要がないので、ページカウンタとしました。
 このページを見た人の人数が知りたいときに使えます。
 簡易のカウンターですので特別な機能はありませんが、PHPが書ける人なら色々な仕組みを導入できそうです。

最後に

 WordPress作った人すごいですね。
 これだけ拡張性があるエンジンを作った開発者様には尊敬と経緯の意を示したいです。

参考にしたサイト、ソース

 WordPress 開発者リソース https://developer.wordpress.org/plugins/plugin-basics
 他のプラグインのソースを片っ端から見て参考にさせていただきましたw