【スポンサーリンク】

[WordPress] 自作プラグインに投稿文字数を計測するスクリプトを追加した【dbDelta】

[WordPress] 自作プラグインに投稿文字数を計測するスクリプトを追加した【dbDelta】

自作 WordPressプラグインに、一日の投稿文字数をカウントする機能を追加しました。

大まかな処理の流れは
  • プラグインの有効化時に投稿文字数カウント用のデータベースを作成する
  • プラグイン表示時に、累計の投稿文字数を追加する
    (ただし、同じ日付のデータがあれば更新する)
  • 管理メニューでデータベース集計を表形式で表示する
[WordPress] 自作プラグインに投稿文字数を計測するスクリプトを追加した【dbDelta】

一日の成果を文字数で把握できると、ちょっとモチベーションアップになるかも?

\記事が役に立ったらシェアしてね/
免責事項

なるべく正確な情報になるよう努力していますが、個々のPC/スマホにより状況は異なり、結果の保証はできません。
操作の際には、十分に注意の上、ご自身の判断と責任で行っていただくようお願いいたします。

【スポンサーリンク】

1. データベースの作成(dbDelta)

一番手間取ったのは、データベースを作成する処理です。

WordPressでは、MySQLのテーブルはかんたんに追加できます。

global $chiilabo_db_version;
$chiilabo_db_version = '1.1';

define('CHIILABO_COUNT_TABLE_NAME', $wpdb->prefix . 'chiilabo_daily_count');


function chiilabo_db_install() {
  global $wpdb;
  global $chiilabo_db_version;

  $table_name = CHIILABO_COUNT_TABLE_NAME;

  $charset_collate = $wpdb->get_charset_collate();

  $sql = "CREATE TABLE $table_name (
    id mediumint(9) NOT NULL AUTO_INCREMENT,
    date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
    count mediumint(9) NOT NULL,
    diff mediumint(9) NOT NULL,
    UNIQUE KEY id (id)
  ) $charset_collate;";

  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
  dbDelta( $sql );

  add_option( 'chiilabo_db_version', $chiilabo_db_version );
}

テーブルを作成するクエリ($sql)を dbDelta() に与えると、うまいこと テーブルを追加・更新してくれます。

(参考)

1-1. プラグイン有効化時にテーブルを作成したい(register_activation_hook)

問題は、テーブル作成のトリガーです。
「プラグインの有効化」で実行させたかったのですが、どうもうまく反応してくれませんでした。
register_activation_hookで指定できるはずなのですが…。

register_activation_hook(__FILE__, 'chiilabo_db_install');

しかたないので、プラグインの管理メニューの表示スクリプトに テスト用の条件分岐を入れて、手動で chiilabo_db_install()関数を呼び出して、テーブルの初期化を操作しました。

2. 日ごとの投稿文字数の集計する(date_default_timezone_set)

投稿文字数は、get_posts()の content から勘定できます。

ただし、すでに同じ日付で記録されていたら、それを更新する必要があります。
まず、日付の区切りを日本時間に合わせます(date_default_timezone_set('Asia/Tokyo');)。

すでに同じ日付で記録されていたら、いったん消すことにしました。

    /* 当日の記録をいったん削除する*/

    global $wpdb;
    
    date_default_timezone_set('Asia/Tokyo');
    $date =  date("Y-m-d H-i-s", strtotime("today"));
    
    $table_name = CHIILABO_COUNT_TABLE_NAME;
    $wpdb->query("DELETE FROM $table_name WHERE date = '$date'");

2-1. 不要な要素を除外する(preg_replace)

次に、全投稿の文字数を数えます。

    /* 全投稿の文字数を数える */
    $posts = get_posts( array(
    'post_type' => 'post',
    'post_status' =>  array( 'publish', 'pending', 'draft', 'future'),
    'orderby' => 'modified', /* date, modified */
    'numberposts' => -1
    ) );
    $count = 0;
    foreach ( $posts as $post ) { 
        $content = $post->post_content;
        
        $content = preg_replace('/<pre[\s\S]*?<\/pre>/','', $content);
        $content = preg_replace('/<blockquote[\s\S]*?<\/blockquote>/','', $content);
        $content = strip_tags($content);
        $content = preg_replace('/\s*/','', $content);
        $char_count = mb_strlen($content);        
        $count += $char_count;
    }

記事内の自分の入力文字数をカウントしたかったので、引用とコードを除くようにしました。

preg_replace() で、不要な部分を正規表現パターンで削除しました。
例えば、このように空白文字をカウントから除外しました。

   $content = preg_replace('/\s*/','', $content);

ただし、正規表現でのマッチで 2つハマりポイントがありました。

2-2. 「/」はそのままパターンに入れられない(エスケープ)

タグを閉じる「</pre>」でつまりました。
実は、「/」が正規表現パターンの「デリミタ」になっているから、そのまま指定できないのです。
「\/」とエスケープすることに気づくのに時間がかかりました。

$result = preg_replace('/<a .*?>(.*?)<\/a>/', "$1", $item);
メタ文字説明
\多目的に使う一般的なエスケープ文字。
「メタ文字」は、もれなくエスケープが必要。
正規表現パターンの中で「デリミタ」と同じ文字が出現するなら、エスケープが必要。
^検索対象(複数行モードでは行)の始まりを言明
$検索対象の終わりあるいは終端の改行文字の前(複数行モードでは行の終わり)を言明
.改行を除くすべての文字にマッチ(デフォルト時)
[文字クラス定義の開始
]文字クラス定義の終了
|選択肢の開始
(サブパターンの開始
)サブパターンの終了
?( の意味を拡張/0 または 1 回マッチ/なるべく少ない回数だけマッチ
*0 回以上の繰り返し
+1 回以上の繰り返し
{最小/最大を指定する量指定子の開始
}最小/最大を指定する量指定子の終了

2-3. 「.」は改行にマッチしない「\s\S」

一つは、複数行の正規表現による置換です。
通常の「.*」でタグの中身にマッチさせたかったのですが、改行が含まれるとマッチしません。そこで、「\s\S」を使いました。

$subject = '
The text you
need to search.
';

// 改行コードを含むべての文字列
if ( preg_match( '/[\s\S]*/', $subject ) )
  echo "Matched";

2-4. 【追記:2023-06-04】正規表現の最短一致・最長一致【*?】

ところが、<pre>タグではうまくマッチしません。
どうも、文字数が少なくカウントされてしまっているのです。

    $content = preg_replace('/<pre[\s\S]*<\/pre>/','', $content);

実は、正規表現では、文字列内にパターンが複数存在するときに、長く取るのか、短く取るのかが重要です1

基本は「最長一致」です。
マッチした全体が一つにカウントされます。

このスクリプトでは、改行を含めたすべての文字にマッチするために[\s\S]*を使っています。しかし、これだと、preタグが複数存在した場合、その間も含めてマッチしてしまいます。[\s\S]*が「<\/pre>」も含んでしまうからです。

そこで最短一致にするには、[\s\S]*?とします。

    $content = preg_replace('/<pre[\s\S]*?<\/pre>/','', $content);

そうすれば、正しくタグに囲まれた部分だけがマッチします。

2-5. (あるいは)HTMLとしてパースする

一応、HTMLとしてパースする方法もあります2

    $doc = new DOMDocument();
    $doc->formatOutput = true;
    $doc->preserveWhiteSpace = false;
    $doc->documentEncoding = 'UTF-8';
    @$doc->loadHTML($html);

    $xpath = new DOMXPath($doc);

foreach ($xpath->query('//div[@class="hoge"]') as $node) {
   $node->parentNode->removeChild($node); 
} 

とりあえず、今回はかんたんな置換で解決しています。

3. 出来上がったコード

出来上がりました。

ちゃんと表示するごとに、サイト全体の文字数が更新されて、前日との差分が表示されます。

出来上がったコード
/** 2023-05-06 データベース追加*/
global $chiilabo_db_version;
$chiilabo_db_version = '1.1';

define('CHIILABO_COUNT_TABLE_NAME', $wpdb->prefix . 'chiilabo_daily_count');


function chiilabo_db_install() {
  global $wpdb;
  global $chiilabo_db_version;

  $table_name = CHIILABO_COUNT_TABLE_NAME;

  $charset_collate = $wpdb->get_charset_collate();

  $sql = "CREATE TABLE $table_name (
    id mediumint(9) NOT NULL AUTO_INCREMENT,
    date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
    count mediumint(9) NOT NULL,
    diff mediumint(9) NOT NULL,
    UNIQUE KEY id (id)
  ) $charset_collate;";

  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
  dbDelta( $sql );

  add_option( 'chiilabo_db_version', $chiilabo_db_version );
}

/** 2023-05-06 なぜかプラグイン有効化時に実行されない*/
register_activation_hook(__FILE__, 'chiilabo_db_install');
function chiilabo_db_initial_data() {
  global $wpdb;

  $table_name = CHIILABO_COUNT_TABLE_NAME;
  
  $wpdb->insert(
    $table_name,
    array(
      'date' => "2023-05-05	00:00:00",
      'count' => "2780000",
    )
  );
}


function delete_db() {
    global $wpdb;
    
    $table_name = CHIILABO_COUNT_TABLE_NAME;
    $wpdb->query("DELETE FROM $table_name");

}
function add_count_to_db() {
    /* 全投稿の文字数を数える */
    $posts = get_posts( array(
    'post_type' => 'post',
    'post_status' =>  array( 'publish', 'pending', 'draft', 'future'),
    'orderby' => 'modified', /* date, modified */
    'numberposts' => -1
    ) );
    $count = 0;
    foreach ( $posts as $post ) { 
        $content = $post->post_content;
        
        $content = preg_replace('/<pre[\s\S]*?<\/pre>/','', $content);
        $content = preg_replace('/<blockquote[\s\S]*?<\/blockquote>/','', $content);
        $content = strip_tags($content);
        $content = preg_replace('/\s*/','', $content);
        $char_count = mb_strlen($content);        
        $count += $char_count;
    }
    
    /* 当日の記録をいったん削除する*/
    global $wpdb;
    
    date_default_timezone_set('Asia/Tokyo');
    $date =  date("Y-m-d H-i-s", strtotime("today"));
    $table_name = CHIILABO_COUNT_TABLE_NAME;
    
    $wpdb->query("DELETE FROM $table_name WHERE date = '$date'");
    
    /* 前日の記録との差分を計算する*/
    $query = "
                SELECT date, count, diff
                FROM $table_name 
                ORDER BY date DESC
            ";  
    $results = $wpdb->get_results("SELECT date, count, diff FROM $table_name ORDER BY date DESC LIMIT 1");
    $diff = $count - $results[0]->count;
    $wpdb->insert(
        $table_name,
        array(
          'date' => $date,
          'count' => $count,
          'diff' => $diff,
        )
      );
    
}
/** 日々の投稿文字数の表示*/
function chiilabo_daily_count_display(){
    chiilabo_daily_count_display_inner(-1);
}
/** 日々の投稿文字数の表示*/
function chiilabo_daily_count_display_inner($num){
    global $wpdb;
    /* データベースのクリア用フラグ 通常はfalse*/
    if (false) {
        chiilabo_db_install();
        delete_db();
        chiilabo_db_initial_data();
    }
    
    add_count_to_db();
    $table_name = CHIILABO_COUNT_TABLE_NAME;
    if ($num>0) {
        $limit = "LIMIT $num";
    }
    $query = "
                SELECT date, count, diff
                FROM $table_name 
                ORDER BY date DESC
                $limit
            ";  

    // Retrieve the access logs
    $results = $wpdb->get_results($query);

    // Initialize the table
    echo '<table class="a">';
    echo '<thead><tr>';
    echo '<th>日付</th>';
    echo '<th>入力文字数</th>';
    echo '</tr></thead>';
    
    // Populate the table
    echo '<tbody>';
    foreach ( $results as $idx => $row) {
        echo '<tr>';
        echo '<td>' . substr($row->date, 0, 10)  . '</td>';
        echo '<td align="right">' . ( $row->diff) . '</td>';
        echo '</tr>';
    }
    
    
    echo '</tbody>';
    echo '</table>';    
}

これらをプラグインPHPに追加することで、機能を追加できました。

<?php
/**
 * Plugin Name: ちいラボ統計
 * Plugin URI: chiilabo.com
 * Author: chiilabo
 * Author URI: chiilabo.com
 * Description: 投稿月ごとの月別ページビュー集計表を表示する。
 * Version: 2.1.0
 * Update: 月別ページビュー
 *   2.0.0: 2023-04-23 グリッドビューを追加
 *   2.0.1: 2023-04-24 グリッドビューに検索バーを追加
 *   2.0.2: 2023-05-05 文字数のカウントからコード・引用を省く
 *   2.0.3: 2023-05-05 グリッドビューに簡易ページを追加した
 *   2.1.0: 2023-05-06 記事の集計データベースを追加した
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}




/** 管理メニューの設定・追加*/
define( 'ACCESSES_TABLE_NAME', $wpdb->prefix . 'cocoon' . '_accesses' );

// Register the admin menu for the plugin
function chiilabo_stats_admin_menu() {
add_menu_page(
'chiilabo-stats' // ページのタイトルタグ<title>に表示されるテキスト
    , 'ちいラボ統計'   // 左メニューとして表示されるテキスト
    , 'edit_posts'       // 必要な権限 manage_options は通常 
    , 'chiilabo-stats'        // 左メニューのスラッグ名 
    , '' // メニューページを表示する際に実行される関数
    , 'dashicons-admin-users'       // メニューのアイコンを指定 https
    , 0                             // メニューが表示される位置のインデックス(0が先頭) 5=投稿,10=メディア,20=固定ページ,25=コメント,60=テーマ,65=プラグイン,70=ユーザー,75=ツール,80=設定
    );
    add_submenu_page(
    'chiilabo-stats',    // 親メニューのスラッグ
    '記事分析',
    '記事分析',
    'edit_posts',
    'chiilabo-stats',
    'posts_stats_display',
    1
    );
    add_submenu_page(
    'chiilabo-stats',    // 親メニューのスラッグ
    '月別集計',
    '月別集計',
    'edit_posts',
    'monthly-pageview-totals',
    'monthly_pageview_totals_display',
    2
    );
    
    add_submenu_page(
    'chiilabo-stats',    // 親メニューのスラッグ
    'グリッド集計',
    'グリッド集計',
    'edit_posts',
    'grid-stats',
    'grid_stats_display',
    3
    );
    add_submenu_page(
    'chiilabo-stats',    // 親メニューのスラッグ
    'グリッド集計all',
    'グリッド集計all',
    'edit_posts',
    'grid-stats-all',
    'grid_stats_display_all',
    4
    );
    add_submenu_page(
    'chiilabo-stats',    // 親メニューのスラッグ
    '日々の投稿文字数',
    '日々の投稿文字数',
    'edit_posts',
    'daily-count',
    'chiilabo_daily_count_display',
    4
    );
}
add_action( 'admin_menu', 'chiilabo_stats_admin_menu' );

// Callback to display the page content
function monthly_pageview_totals_display() {
global $wpdb;

// Use the Transients API to cache the page view data for 12 hours

// Retrieve all the posts and their permalinks
$posts = get_posts( array(
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => -1
) );

$urls = array();
$post_ms = array();
$results = array();
foreach ( $posts as $post ) {
    $url = parse_url( get_permalink( $post ) );
    $urls[$post->ID] = substr( $url['path'], 1 );
    $post_m = substr($urls[$post->ID], 0,7);
    $post_ms[$post_m]=$post_m;
    $results[$post_m]=array();
}


$table_name = ACCESSES_TABLE_NAME;
$query = "
            SELECT post_id, SUM(count) as pv, YEAR(date) as year, MONTH(date) as month, date
            FROM $table_name 
            GROUP BY post_id, year, month
            ORDER BY date DESC  
        ";  

// Retrieve the access logs
$logs = $wpdb->get_results($query);

$months = array();
foreach ( $logs as $log ) {
    $post_m = substr($urls[$log->post_id], 0,7);
    $access_m = $log->year.sprintf('%02d', $log->month);
    
    $pv = $results[$post_m][$access_m];
    if (!$pv) {
        $pv =0;
    }
    $results[$post_m][$access_m] = $pv + $log->pv;
    $months[ $access_m ] = $log->year.'年'.$log->month.'月';
}    

// Initialize the table
echo '<table class="widefat">';
echo '<thead><tr>';
echo '<th width="40%">投稿月</th>';

foreach ( $months as $month ) {
    echo '<th>' . esc_html( $month ) . '</th>';
}
echo '</tr></thead>';

// Populate the table
echo '<tbody>';
foreach ( $results as $m => $row ) {
echo '<tr>';
echo '<td>' . $m  . '</td>';
foreach ( $months as $key => $month ) {
$pv = 0;
foreach ( $row as $mm => $mpv ) {
if ( $mm == $key ) {
    $pv = $mpv;
    break;
}
}
echo '<td align="right">' . ( $pv ? number_format_i18n( $pv ) : '' ) . '</td>';
}
echo '</tr>';
}


echo '</tbody>';
echo '</table>';
}




/**
 * 記事ごとの分析
 * 
 */
function posts_stats_display() {
    global $wpdb;
    
    // Retrieve all the posts and their permalinks
    $posts = get_posts( array(
    'post_type' => 'post',
    'post_status' => 'publish',
    'numberposts' => -1
    ) );
    
    $post_id2obj = array();
    $post_words = array();
    foreach ( $posts as $post ) {
        $post_id2obj[$post->ID] = $post;
        $post_words[$post->ID] = mb_strlen($post->post_content);
    }

    
    $table_name = ACCESSES_TABLE_NAME;
    $query = "
            SELECT post_id, SUM(count) as pv, date
            FROM $table_name 
            GROUP BY post_id
            ORDER BY date DESC  
        ";  
    
    // Retrieve the access logs
    $logs = $wpdb->get_results($query);
    $pvs = array();
    foreach ( $logs as $log ) {
        $days[$log->post_id] = (strtotime("now") - strtotime($log->date)) / 86400;
    }

    // Initialize the table
    echo '<style>.widefat.stats td, .widefat.stats th { padding: 2px 10px !IMPORTANT; } </style>';
    
    echo '<table class="widefat stats">';
    echo '<thead><tr>';
    echo '<th>投稿日</th>';
    echo '<th>文字数</th>';
    echo '<th>PV/日</th>';
    echo '<th>タイトル</th>';
    echo '<th>星</th>';
    echo '</tr></thead>';
    
    // Populate the table
    echo '<tbody>';
    echo '<tr>';
    echo '<td>';
    foreach ( $logs as $log ) {
        $post = $post_id2obj[$log->post_id];
        $pv_ave = ceil($log->pv / ceil($days[$log->post_id]));
        if ($pv_ave > 2) {
            echo '</td>';
            echo '</tr>';
            echo '<tr>';
            echo '<td>';
            echo $log->date;        
            echo '</td>';
            
            echo '<td align="right">';
            echo mb_strlen(strip_tags($post->post_content));
            echo '</td>';
            
            echo '<td align="right">';
            echo $pv_ave;
            echo '</td>';
            
            echo '<td>';
            echo '<a href="'. get_permalink($post) . '">';
            echo mb_substr($post->post_title, 0, 50) .' ... ('. $log->pv .') ';
            echo '</a>';
            echo '</td>';
            echo '<td>';
            echo '<a href="'. get_permalink($post) . '">';
            echo '○';
            echo '</a>';
        } else {
            echo '<a href="'. get_permalink($post) . '">';
            echo '✕';
            echo '</a>';
        }
    } 
    

echo '</tbody>';
echo '</table>';
}

function grid_stats_display() {
     grid_stats_display_inner(360);
}

function grid_stats_display_all() {
     grid_stats_display_inner(-1);
}
/**
 * 
 * 
 */
function grid_stats_display_inner($disp_count = -1) {
    global $wpdb;
    
    // Retrieve all the posts and their permalinks
    $posts = get_posts( array(
    'post_type' => 'post',
    'post_status' =>  array( 'publish', 'pending', 'draft', 'future'),
    'orderby' => 'modified', /* date, modified */
    'numberposts' => -1
    ) );
    if ($disp_count > 0) {
        $posts = array_slice($posts, 0, $disp_count);
    }
    
    $post_id2obj = array();
    $post_words = array();
    foreach ( $posts as $post ) {
        $post_id2obj[$post->ID] = $post;
        $post_words[$post->ID] = mb_strlen($post->post_content);
    }

    
    $table_name = ACCESSES_TABLE_NAME;
    $query = "
            SELECT post_id, SUM(count) as pv, date
            FROM $table_name 
            GROUP BY post_id
        ";  
    
    // Retrieve the access logs
    $logs = $wpdb->get_results($query);
    
    $post_id2log = array();
    $days = array();
    date_default_timezone_set('Asia/Tokyo');
    foreach ( $logs as $log ) {
        $post_id2log[$log->post_id] = $log;
        $days[$log->post_id] = (strtotime("now") - strtotime($log->date)) / 86400;
    }
    

    // Initialize the table
    $row = 9;
    if (wp_is_mobile()) {
        $row = 4;
    }
    
    echo '<style>
    table.widefat.stats{
        width: 100%;
    }
    .widefat.stats td, .widefat.stats th {
        border: 1px solid black;
        padding: 0px 0px !IMPORTANT; 
        width: calc(100%/'.$row.');
    } 
      .container{
        position: relative;
        width:calc(100%/'.$row.');
      }
      .widefat.stats img{
        width: 100%;
        height: 100%;
        object-fit:cover;
        aspect-ratio: 100/100;
        opacity: 0.6;
        }
      .container p{
        position: absolute;
        padding: 5px;
        font-size: 7px;
        margin:0;
      }
      .container .date{
        top: 5px;
        left: 5px;
        
        text-align: center;
        background-color: brown;
        font-weight: bold;
        color: #fff;
      }
      .container .chars {
        background-color: #fff;
        left: 5px;
        bottom: -5px;
        font-weight: 900;
      }
      .container .pv {
        background-color: #fff;
        right: 5px;
        bottom: -5px;
        font-weight: 900;
      }      
      .container .rank {
        position: absolute;
        font-size: 300%;
        font-weight: 900;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
  text-shadow: var(--cocoon-white-color) 3px 0px 0px, var(--cocoon-white-color) 2px 1px 0px, var(--cocoon-white-color) 2px 2px 0px, var(--cocoon-white-color) 2px 3px 0px, var(--cocoon-white-color) 1px 3px 0px, var(--cocoon-white-color) 0px 3px 0px, var(--cocoon-white-color) -1px 3px 0px, var(--cocoon-white-color) -2px 2px 0px, var(--cocoon-white-color) -3px 1px 0px, var(--cocoon-white-color) -3px 0px 0px, var(--cocoon-white-color) -3px -1px 0px, var(--cocoon-white-color) -3px -2px 0px, var(--cocoon-white-color) -2px -2px 0px, var(--cocoon-white-color) -1px -3px 0px, var(--cocoon-white-color) 0px -3px 0px, var(--cocoon-white-color) 1px -3px 0px, var(--cocoon-white-color) 2px -2px 0px, var(--cocoon-white-color) 2px -2px 0px, var(--cocoon-white-color) 3px -1px 0px;        
        }      
      .container.todo_post .rank, .container.todo_post .chars   {
      color: red;
      }

    </style>
    ';
    
$search_box = '<div class="searchbox-wrap"><div class="gcse-searchbox-only"></div></div>

<script async src="https://cse.google.com/cse.js?cx=b8f3ee6d995f66436"></script>
<div class="searchbox-space"></div>
<style>
    .searchbox-space {
        height: 64px;
    }
    .searchbox-wrap {
		position: fixed; /* ヘッダーを固定する */
        top: 32px; /* 上部から配置の基準位置を決める */
        left: 0px;
		padding: 10px;
		background-color: #f0f0f1;
		opacity: 1;
		z-index: 999;
		padding-left: 172px;
		border-bottom: 1px solid #aaa;
		width: 100%;
		height: 64px;
		box-sizing: border-box;
        
    }
	.gcse-searchbox-only {
		display: block;
		background-color: #f0f0f1;
	}
    @media screen and (max-width: 960px){
        .searchbox-wrap {
        padding-left: 48px;
        position: absolute;
        }
	    .gcse-searchbox-only {
    	}
    }
    @media screen and (max-width: 782px){
        .searchbox-wrap {
            top: 48px; /* 上部から配置の基準位置を決める */
    		padding-left: 0px;
    		height: 100px;
        }
        .searchbox-space {
            height: 100px;
        }
    }
    .gcse-searchbox-only {
    	}
    }
    
</style>';    
    echo $search_box;
    
    /* 入力文字数カウントの表示 */
    chiilabo_daily_count_display_inner(2);
    echo '<table class="widefat stats">';

    
    // Populate the table
    echo '<tbody>';
    $count = 0;
    $last_date = "tomorrow";
    foreach ( $posts as $post ) {
        if($count == 0) {
            echo '<tr>';
        }
        $log = $post_id2log[$post->ID];
        $pv_ave = ($log->pv / ceil($days[$post->ID]));
        if (is_nan($pv_ave)) {
            $pv_ave = 0;
        }
        
        $is_todo_post = 0;
        if ($post->post_status == "publish") {
            $categories = get_the_category($post->ID);
            foreach ( $categories as $category) {
                if ($category->term_id == 2458) {
                    $is_todo_post = 1;
                }
            }
            
        } else {
            $is_todo_post = 1;
        }
        if ($is_todo_post == 1) {
            echo '<td class="container todo_post">';
            
        } else {
            echo '<td class="container">';
        }
        echo '<a href="'. get_permalink($post) . '" title="'. mb_substr($post->post_title, 0, 50) .'">';
        $img = get_the_post_thumbnail_url($post->ID, 'thumbnail' );
        echo '<img src="' .$img. '" alt="' . mb_substr($post->post_title, 0, 50)  . '">';
        $date = substr($post->post_modified, 0, 10);
        if (strtotime($date) != false && floor(strtotime($date)/86400) < floor( strtotime($last_date)/86400)) {
            echo '<p class="date">'.$date.'</p>';
            $last_date = $date;        
        }
        $content = $post->post_content;
        
        $content = preg_replace('/<pre[\s\S]*?<\/pre>/','', $content);
        $content = preg_replace('/<blockquote[\s\S]*?<\/blockquote>/','', $content);
        $content = preg_replace('/\[amazon.*\]/','', $content);
        $content = preg_replace('/\3/','', $content);
        
        $content = strip_tags($content);
        $content = preg_replace('/\s*/','', $content);
        $char_count = mb_strlen($content);        
        
        echo '<p class="chars">'.$char_count.'</p>';
        echo '<p class="pv">'. floor($pv_ave).'</p>';
        
        $pv_rank = "";
        if ($pv_ave >= 100) {
            $pv_rank = "飛";
        } else if ($pv_ave >= 40) {
            $pv_rank = "角";
        } else if ($pv_ave >= 15) {
            $pv_rank = "金";
        } else if ($pv_ave >= 12) {
            $pv_rank = "銀";
        } else if ($pv_ave >= 9) {
            $pv_rank = "桂";
        } else if ($pv_ave >= 6) {
            $pv_rank = "香";
        } else if ($pv_ave >= 2.5) {
            $pv_rank = "歩";
        } else {
            $pv_rank = "";
        }
            
        echo '<p class="rank">'.$pv_rank.'</p>';
        echo '</a>';
        
        echo '</td>';
        
        $count = $count+1;
        if ($count == $row) {
            echo '</tr>';
            $count = 0;
        }
    } 
    

echo '</tbody>';
echo '</table>';
}

/** 2023-05-06 データベース追加*/
global $chiilabo_db_version;
$chiilabo_db_version = '1.0';

define('CHIILABO_COUNT_TABLE_NAME', $wpdb->prefix . 'chiilabo_daily_count');


function chiilabo_db_install() {
  global $wpdb;
  global $chiilabo_db_version;

  $table_name = CHIILABO_COUNT_TABLE_NAME;

  $charset_collate = $wpdb->get_charset_collate();

  $sql = "CREATE TABLE $table_name (
    id mediumint(9) NOT NULL AUTO_INCREMENT,
    date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
    count mediumint(9) NOT NULL,
    diff mediumint(9) NOT NULL,
    UNIQUE KEY id (id)
  ) $charset_collate;";

  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
  dbDelta( $sql );

  add_option( 'chiilabo_db_version', $chiilabo_db_version );
}

function chiilabo_db_initial_data() {
  global $wpdb;

  $table_name = CHIILABO_COUNT_TABLE_NAME;
  
  $wpdb->insert(
    $table_name,
    array(
      'date' => "2023-05-05	00:00:00",
      'count' => "2470000",
    )
  );
}

/** 2023-05-06 なぜかプラグイン有効化時に実行されない*/
register_activation_hook(__FILE__, 'chiilabo_db_install');

function delete_db() {
    global $wpdb;
    
    $table_name = CHIILABO_COUNT_TABLE_NAME;
    $wpdb->query("DELETE FROM $table_name");

}
function add_count_to_db() {
    $posts = get_posts( array(
    'post_type' => 'post',
    'post_status' =>  array( 'publish', 'pending', 'draft', 'future'),
    'orderby' => 'modified', /* date, modified */
    'numberposts' => -1
    ) );
    $count = 0;
    foreach ( $posts as $post ) { 
        $content = $post->post_content;
        
        $content = preg_replace('/<pre[\s\S]*<\/pre>/','', $content);
        $content = preg_replace('/<blockquote[\s\S]*<\/blockquote>/','', $content);
        $content = preg_replace('/\[amazon.*\]/','', $content);
        $content = preg_replace('/\4/','', $content);
        $content = strip_tags($content);
        $content = preg_replace('/\s*/','', $content);
        $char_count = mb_strlen($content);        
        $count += $char_count;
    }
    
    global $wpdb;
    
    $table_name = CHIILABO_COUNT_TABLE_NAME;
    date_default_timezone_set('Asia/Tokyo');
    $date =  date("Y-m-d H-i-s", strtotime("today"));
    
    $wpdb->query("DELETE FROM $table_name WHERE date = '$date'");
    
    $query = "
                SELECT date, count, diff
                FROM $table_name 
                ORDER BY date DESC
            ";  
    $results = $wpdb->get_results("SELECT date, count, diff FROM $table_name ORDER BY date DESC LIMIT 1");
    $diff = $count - $results[0]->count;
    $wpdb->insert(
        $table_name,
        array(
          'date' => $date,
          'count' => $count,
          'diff' => $diff,
        )
      );
    
}
/** 日々の投稿文字数の表示*/
function chiilabo_daily_count_display(){
    chiilabo_daily_count_display_inner(-1);
}
/** 日々の投稿文字数の表示*/
function chiilabo_daily_count_display_inner($num){
    global $wpdb;
    /* データベースのクリア用フラグ 通常はfalse*/
    if (false) {
        chiilabo_db_install();
        delete_db();
        chiilabo_db_initial_data();
    }
    
    add_count_to_db();
    $table_name = CHIILABO_COUNT_TABLE_NAME;
    if ($num>0) {
        $limit = "LIMIT $num";
    }
    $query = "
                SELECT date, count, diff
                FROM $table_name 
                ORDER BY date DESC
                $limit
            ";  

    // Retrieve the access logs
    $results = $wpdb->get_results($query);

    // Initialize the table
    echo '<table class="a">';
    echo '<thead><tr>';
    echo '<th>日付</th>';
    echo '<th>入力文字数</th>';
    echo '</tr></thead>';
    
    // Populate the table
    echo '<tbody>';
    foreach ( $results as $idx => $row) {
        echo '<tr>';
        echo '<td>' . substr($row->date, 0, 10)  . '</td>';
        echo '<td align="right">' . ( $row->diff) . '</td>';
        echo '</tr>';
    }
    
    
    echo '</tbody>';
    echo '</table>';    
}
こちらもどうぞ。
[WordPress]カスタムプラグインで投稿文字数の自動集計機能を追加した
[WordPress]カスタムプラグインで投稿文字数の自動集計機能を追加した
WordPressの投稿文字数を日々集計し、データベースに保存するプラグインを作成しました。従来は集計画面表示時のみ実行されていた処理を、記事保存時に自動実行するように改善しました。下書き保存時の処理は負荷を考慮して省略し、公開・更新・削除時のみ実行する仕様としました。

[WordPress] 投稿月でグループ分けした月別PV集計表を見るためのカスタムプラグインを作った【ChatGPTと】
[WordPress] 投稿月でグループ分けした月別PV集計表を見るためのカスタムプラグインを作った【ChatGPTと】
一ヶ月分のブログ公開がどれぐらいのページビューにつながっているのか、集計する自分用のWordPressプラグインを作成しました。自分にとっては未経験の分野でしたが、対話型AI「ChatGPT」に相談してみると、使える叩き台を用意してくれました。WordPressプラグインづくりははじめてでしたが、かなりの時間短縮。無事に完成しました。アクセス集計プラグイン一ヶ月分のブログ公開が、どれぐらいの成果になっているのか知りたいことがあります。これまでは、Google Analytic...

[WordPress] 「月の投稿ごとの集計」をするためにブログのパーマリンクを変更した【Search Regexプラグイン】
[WordPress] 「月の投稿ごとの集計」をするためにブログのパーマリンクを変更した【Search Regexプラグイン】
「Google アナリティクス」でアクセス数を見ているのですが、「投稿した月ごとの集計」を知りたいと思いました。そのために、サイトのパーマリンクを変更しました。手作業で内部リンクを修正するのはしんどそうだったのですが、プラグインのおかげで一気にできました。ポイントGoogleアナリティクスでは、「ディメンション」ごとにアクセス数を集計できる。WordPressのパーマリンクは、「設定」から変更できる。投稿内のURLを一括置換するのに、「Search Regexプラグイン」をイ...

(補足)

  1. 正規表現:最短一致でマッチさせる表現 | WWWクリエイターズ
  2. html – PHP HTMLコードから特定のclassを持つタグと中身を消したい – スタック・オーバーフロー
QRコードを読み込むと、関連記事を確認できます。

[WordPress] 自作プラグインに投稿文字数を計測するスクリプトを追加した【dbDelta】
【スポンサーリンク】
タイトルとURLをコピーしました