Wonderful! WordPress

いまさらの Ajax でのコメントの編集機能プラグイン

Page No.1

またしても、いまさらの・・・だけど。
コメントの編集機能に手をつけるのは、これでなんと4度目。
まぁ、コメント自体、ほとんど無いので作りっぱなしでほっぽってあったのだけれど。
Google PAGESPEED INSIGHTS とか Chrome Lighthouse のパフォーマンスにおいて、なんとか100ポイントを、と、じたばたしているときに、このコメント編集プラグインにおいても、もっと省ける部分があるのでは?となったわけです。それならついでに、今ではもう当たり前のように使うようになった Ajax にしてしまおうと。

機能的には今までのと全く同じ。ただ JavaScript が無くても、ページ遷移で可能だった部分を無くしてしまったのと、ページ遷移を無くしたので、その部分を Ajax にて代用したという事。

2023/2/26 に、細かい部分をちょっと新しくして v3.0 から v3.1 へとアップデートさせてる。主に改良したのは、プラグインオプションの取得部分と現在日時の取得を DateTime クラスを使用する方法にしたこと。あとは細かいところでわずかでも速くなるかなと、効率が良くなるだろうというところを変更してる。プログラムの本流部分というか、肝心の部分はほとんどいじってはいない。JavaScript においては全く手を入れて無く、v3.0 そのまま。
で、一応、どういう感じかというと。

  • 認証用のeditkey を入力するためのインプットボックスをコメントフォームに挿入
  • そのeditkey はそのコメントのメタ情報としてcommentmeta テーブルに保存
  • 実際の編集作業、および削除確認のためのフォームはポップアップするhtmlタグ<section>にて表示
  • option を設けて都合によって使いやすくする
  • そのoption は管理画面内に設定画面を設ける
  • ついでにスパム防止用のチェックボックスも設置
  • メール入力を必要としないようにダミーアドレスを自動で入力する機能も付加
  • リクエストをへらすためポップアップのスタイル設定は js から設定しスタイルシートの読み込みを無くす
  • そして一番こだわった部分は、コメントが無い時に不必要な js ファイルの読み込みをなくす

コメントフォーム自体の表示がない場合は、プラグインの読み込み自体を無くせれば良いのだけれど、プラグインの読み込みは投稿の情報の読み込みよりも前のようなので、いかんせん、これは無理のよう。
編集と削除確認のポップアップウィンドウ用のスタイル設定は、JavaScript からするようにして、それ用のスタイルシートの読み込みのリクエストを、まずは一つ減らすことができた。
そして、なぜ前回の時にこれに気が付かなかったのだろうか?と思ったのだけれど、JavaScript ファイルのロードに関して、そのフックへの登録を、コメントがあった場合の edit-key 入力用のインプットボックスを書きだすフックに一緒に設定すればよかったのだと。こうすれば、コメントがあるページでだけ JavaScript ファイルをロードすることになって、コメントの無いページにおいては、そのリクエストを減らすことができる。
フィルターフックにせよアクションフックにせよ、どこに書いても機能するというわけではないので、WordPress のロードプロセスを考えて、ここなら機能しそうだというところで試してやってみるしかないのだけれど。
と、いうことでコメントの無いページにおいては、スタイルシートと JavaScript ファイル、2つのリクエストを減らすことができたわけです。

まぁ、ただ単にスピードアップさせるためなら、もともと自作なのだからプラグインという形態ではなく、テンプレートに組み込んでしまえば、その方がよほど無駄な部分がなくなるのだけれど、なにかそれでは本末転倒という気もしないでもなく、あえてプラグインという形態にこだわって Lighthouse に挑戦してみた。

あと、プラグインという形式になっているのなら、WordPress の公式プラグインディレクトリになぜ登録しない?ということもあるけれど、Ajax によるコメント編集プラグインはすでに先人たちがアップロードしてくれているので、それこそいまさら!という感じが否めない。ただ、自分的には、必要な機能だけで極力軽いもので、100%自的に対応できるもの、ということになるとやはり自作でしか、ということになるりまする。
で、管理画面の option で設定できるのは以下の項目。

  • 起動させたくないページは ページid で複数指定可。( 固定ページ、個別投稿ページ(カスタム投稿含む))
  • コメントの削除の可否
  • コメントの編集・削除が可能な期間の設定
  • スパム防御機能の使用設定
  • スパム防御機能において拒否したアドレスのログの保存の設定
  • JavaScript ファイルのロード設定
  • ポップアップウィンドウのスタイル設定の如何
  • 編集、削除があった場合の管理者への通知メールの設定
  • メールアドレスにダミーアドレスを入力する機能の使用設定
  • 編集用ポップアップの背景色設定

と、いったところ。
起動させたくないページの設定に関しては、前述したとおり、基本的にそのページにコメントが無かったり、コメントがあっても編集可能期限内のコメントが無い場合は、JavaScript ファイルはロードされません。ただ、その場合でも、新規のコメントに対する備えとして、edit-key やスパムチェックのための要素は挿入されます。
それが、この起動させたくないページid を指定したページにおいては、それら edit-key やスパムチェックを含むプラグインのすべての機能が作動しないということになります。

コメント更新の wp_update_comment() と 削除の wp_delete_comment()

まずは、とりあえずコメント更新の関数 wp_update_comment() と 削除においての wp_delete_comment() について触れておきませう。
削除する方の wp_delete_comment() については、その使い方はいたってシンプルで、引数としてコメントID を指定するだけ。デフォルトではこの関数はコメントを完全に削除するのではなく、 comment_approved の値を trash に更新するということ。いわゆるごみ箱行きということです。で、第2引数として “true” を渡してやれば、ゴミ箱をバイパスしていきなり削除ということも可能だとのこと。

そして wp_update_comment()
WordPress.orgCodeReference を見ると使用例が載っています。
コメントを未承認にする場合の使用例として、

<?php
    $commentarr = array();
    $commentarr['comment_ID'] = 123;
    $commentarr['comment_approved'] = 0;

    wp_update_comment( $commentarr );
?>
PHP
CopyExpand

まぁ、これだけでもだいたいはわかるが、今一度、/wp-includes/comment.php にある元の関数を見てみると、以前にこの関数に関しての記事を書いた時のものよりも、その内容は随分と多くなってる。けれど、要点部分はほぼ同じである。はじめの部分だけ引っ張ってくると、

function wp_update_comment( $commentarr, $wp_error = false ) {
	global $wpdb;

	// First, get all of the original fields.
	$comment = get_comment( $commentarr['comment_ID'], ARRAY_A );
	if ( empty( $comment ) ) {
		if ( $wp_error ) {
			return new WP_Error( 'invalid_comment_id', __( 'Invalid comment ID.' ) );
		} else {
			return false;
		}
	}

	// Make sure that the comment post ID is valid (if specified).
	if ( ! empty( $commentarr['comment_post_ID'] ) && ! get_post( $commentarr['comment_post_ID'] ) ) {
		if ( $wp_error ) {
			return new WP_Error( 'invalid_post_id', __( 'Invalid post ID.' ) );
		} else {
			return false;
		}
	}

	// Escape data pulled from DB.
	$comment = wp_slash( $comment );

	$old_status = $comment['comment_approved'];

	// Merge old and new fields with new fields overwriting old ones.
	$commentarr = array_merge( $comment, $commentarr );

	$commentarr = wp_filter_comment( $commentarr );

	// Now extract the merged array.
	$data = wp_unslash( $commentarr );

	/**
	 * Filters the comment content before it is updated in the database.
	 *
	 * @since 1.5.0
	 *
	 * @param string $comment_content The comment data.
	 */
	$data['comment_content'] = apply_filters( 'comment_save_pre', $data['comment_content'] );

	$data['comment_date_gmt'] = get_gmt_from_date( $data['comment_date'] );

	↓ まだまだつづく・・・
PHP
CopyExpand

5行目で、引数で渡した comment_ID により目的のコメントを取得し、29行目で更新したいデータを array_merge で上書きさせているのは、以前とやっていることは同じ。
要は、引数で渡すデータとして、comment_ID は必須で(そりゃそうだ、これがないと目的のコメントがわからない)後は、更新したいデータだけを一緒にして渡せば良いというだけのこと。
ちなみに、45行目を見るとわかるように、コメントを送信した日付を変更しようとした場合、自動的に comment_date_gmt の方も変更してくれるので、わざわざそれを変更する必要はありません。

plugin Simplistic Comment User Editable v3.1

と、いうことでさっそくプラグインの中身を。
はじめはワンパターンというかバカの一つ覚えというか、自分のプラグインのお決まりになっているプラグインオプションの処理。ただ、先述したとおりこの部分は新しくしてる。以前は、既存のオプションがある場合は、ただ、デフォルトとの個数を比べるだけでオプション項目に変更がないか確認していた。しかし、やはりこれでは完全とはいえず、まぁ、それを変更するのは自分だけだからということで良しとしてた。それを、処理速度を考えつつも完全な方式に変更してます。

<?php
	//delete_option('Smplstc_Commedt_option');//既存のオプション値を強制的にデフォルトに戻す時使用

	class Simplistic_Comment_User_Editable {

		private $comid;
		private $editkey;
		private $opestr;
		private $e_startup;
		private $s_startup;
		private $current;
		private $default;
		private $ret_option;
		private $option_name;
		private $lang;
		private $is_editkey;
		private $is_first;
		private $server;
		private $ipadrs;
		private $version = '3.1';

		public function __construct() {
			$this->e_startup = 1;//0:edit起動しない、1:起動
			$this->s_startup = 1;//0:spam起動しない、1:起動
			$this->option_name = 'smplstc_commedt_option';
			$this->is_editkey = 0;
			$this->lang = $this->lang_recognize();
			$this->is_first = true;
			$this->ipadrs = $_SERVER['REMOTE_ADDR'];
			$this->load_option();
		}

		private function load_option() {
			$this->default = array(//オプションのデフォルト値設定
				'ignore_page' => '', //起動しない固定ページのページidを,で区切って指定
				'edit_possible_period' => '5', //編集可能な日数
				'en_def_spam' => '1', //spam防御機能を使用、使用:1、非使用:0
				'save_check_er_log' => '1',//spam防御機能のエラー時のログを残す、1:残す、0:残さない
				'en_delete' => '1',//コメントの削除の可否、可:1、否:0
				'load_style_sheet' => '1',//style sheetをロードする、1:ロードする、0:しない
				'load_js' => '1',//javascript fileをロードする、1:ロードする、0:しない
				'en_notice_mail' => '1',//編集、削除があった場合に管理者に通知メールをする、1:する、0:しない
				'en_dummy_mailadrs' => '0',//ip addressから作るダミーメールアドレスを入力する、1:する、0:しない
				'back_color' => '0',//編集用画面の背景色、0:えんじ、1:緑、2:青、3:深紫、4:黒
			);

			$this->current = get_option( $this->option_name );

			if ( false === $this->current ) {//初使用の時などオプションが設定されていない時
	
				update_option( $this->option_name, $this->default );//デフォルトでオプション設定
				$this->ret_option = $this->default;
			} else {
				// すでに保存してあるオプション値が存在する場合
  			// デフォルトと既存値で共通のキーだけの配列を array_intersect_key() で取得し、
			// それら3つのそれぞれの要素の数が同じならば、オプション項目に変更は無い
				$deff = array_intersect_key( $this->default, $this->current );
				$countary = array( count ( $this->default ) , count ( $this->current ) , count ( $deff ) );
	
				if ( 1 !== count ( array_unique( $countary ) ) ) {
					foreach ( $this->current as $key => $val ) {
						if ( isset ( $this->default[ $key ] ) ) {// デフォルトオプションにそのキーが存在する要素だけ保存されている値で上書き。
							$this->default[ $key ] = $val;
						}
					}
					update_option( $this->option_name, $this->default );
					$this->ret_option = $this->default;
	
				} else {
					$this->ret_option = $this->current;
				}
			}

			//spam防止用のチェックボックスと認証用editkeyのテキストボックスを登録
			add_action( 'comment_form_after_fields', array( $this, 'add_comment_check' ) );

			//ekitkeyが入力されているそれぞれのコメントにコメントIDを表示する関数を登録
			add_filter( 'comment_text', array( $this, 'add_commentlist_edit_bt' ), 10, 3 );

			//コメントが保存された時にeditkeyを保存する関数を登録
			add_action( 'comment_post', array( $this, 'save_comment_editkey' ) );

			//コメントが削除された時にeditkeyも削除する関数を登録
			add_action( 'deleted_comment', array( $this, 'delete_editkey' ) );

			//編集および削除ボタンが押され再読み込みの時の処理の分岐関数の登録
			add_action( 'wp', array( $this, 'branch_start' ) );

            // コメントが承認された時に、コメントの日付をその時の日付に更新する
			add_action( 'wp_set_comment_status', array( $this, 'set_approve_date' ), 10, 2 );

			//spam防止用のチェックボックスをコメントが保存される前にチェックする関数の登録
			add_action( 'pre_comment_on_post', array( $this, 'my_comment_spam_check' ) );

			if ( '1' === $this->ret_option['en_dummy_mailadrs'] ) {
				//mail addressにip addressから作ったダミーアドレスをセットする関数を登録
				add_filter( 'preprocess_comment', array( $this, 'set_dummy_mailaddress' ) );
			}

            // コメントを編集するときに editkey をチェックするための Ajax の php 側
			add_action( 'wp_ajax_verifyeditkey', array( $this, 'verifyeditkey' ) );
			add_action( 'wp_ajax_nopriv_verifyeditkey', array( $this, 'verifyeditkey' ) );

            // コメントを編集するときのアップデートをする Ajax の php 側
			add_action( 'wp_ajax_updatecom', array( $this, 'updatecom' ) );
			add_action( 'wp_ajax_nopriv_updatecom', array( $this, 'updatecom' ) );
		}// function load_option ここまで

           // アクセスされているブラウザの言語設定を所得設定する関数
		private function lang_recognize() {
			if ( isset( $_GET['lang'] ) ) {
				return 'en';
			}

			$this->server = array(
				'HTTP_ACCEPT_LANGUAGE' => '',
				'HTTP_REFERER' => 'none',
			);
			$this->server = array_merge( $this->server, $_SERVER );

			if ( isset ( $this->server['HTTPS'] ) ) {
				$this->server['HTTPS'] = 'https://';
			} else {
				$this->server['HTTPS'] = 'https://';
			}

			$langs = array();
			$tmp_langs = $this->server['HTTP_ACCEPT_LANGUAGE'];

			if ( $tmp_langs ) {
				$langs = explode( ',', $tmp_langs );
				$langs = array_reverse( $langs );
			}

			$result = 'en';

			foreach ($langs as $lang) {
				if ( false !== stripos( $lang, 'ja' ) ) {
					$result = 'ja';
					break;
				} elseif ( false !== strpos( $lang, 'en' ) ) {
					$result = 'en';
				}
			}

			return $result;
		}

		private function japtime( $ope = '' ) {

			// 関数が複数回呼ばれたときに、初回に呼ばれて設定した値を使うための static
			static $nowdate = null;
		
			if ( null === $nowdate ) {
				$nowdate = new  DateTimeImmutable( '', new DateTimeZone( 'Asia/Tokyo' ) );
			}
			$basestamp = $nowdate->getTimestamp();
		
			if ( $ope ) {
				if ( '*' === $ope ) {
					$el = array();
					$el['seconds'] = $nowdate->format('s');// string 00-59
					$el['minutes'] = $nowdate->format('i');// string 00-59
					$el['hours'] = $nowdate->format('H');// string 00-23
					$el['mday'] = $nowdate->format('d');// string 01-31
					$el['wday'] = $nowdate->format('w');// string 0(日曜)-6(土曜)
					$el['mon'] = $nowdate->format('m');// string 01-12
					$el['year'] = $nowdate->format('Y');// string 2023
					$el['yday'] = $nowdate->format('z');// int 年間の通算日, 0 から 365
					$el['weekday'] = $nowdate->format('l');// 小文字のL, string 曜日, フルスペルの文字, Sunday から Saturday
					$el['month'] = $nowdate->format('F');// 月, フルスペルの文字, January から December 
					$el['timestamp'] = $basestamp;
					$el['now'] = $nowdate->format('Y/m/d H:i:s');// 2023/01/30 15:05:59 
		
					return $el;
				} else {
					return $nowdate->format( $ope );
				}
			} else {
				return $basestamp;
			}			
		}
		// ↓class 続く
?>
PHP
CopyExpand

最後にくっついてる japtime() なる関数は、見ての通り日本における現在日時を得る関数。日時を得る関数等の仕様を変更されるととにかく鬱陶しくて、日本だけの使用と限ったものなら自前のものを使っていたほうがよほど安心していられる、という経験から以前は自前のものを使っていたのだけれど、これからはこの DateTime クラスがわかりやすくてこれならという感じで良さげ。

ちょっと疑問なのは、WordPress/wp-includes/comment.php にある、wp_new_comment()wp_insert_comment() にしても、comment_date の値には、current_time( ‘mysql’ ) を使っていること。current_time() はその時に非推奨になって current_datetime() を使えってことではなかったのか?たぶん、current_time( ‘mysql’ ) を使っているということは、これを使わなければいけない何かがあるのだと思うのだけれどよくわからない。そもそも両方ともに使ったこともないし。

Leave a Reply!

JavaScript is necessary to send a comment.
You can edit and delete your comment if you input a edit key.
Edit key is necessary for attesting you when you edit and delete it.
The tag of HTML cannot be used in comment.
When you comment for the first time, it is displayed after the approval of the administrator.
Because I cannot speak English so much, it takes time to answer.
Required fields are marked *.

※Please enter more than 5 characters only alphabets.
※Edit or delete are possible for 2000 days after approval.

*

♠Simplistic Comment User Editable v4.0

♠When visitors leave comments on the site this site collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection.
♠This site does not use cookie when visitors leave comments and commenter edit comment.
♠This site uses Akismet to reduce spam. Learn how your comment data is processed.

Comments feed

Trackback URL : https://strix.main.jp/wp-trackback.php?p=167155

Sanbanse Funabashi
2010.10.24 sunrise

Top

スクロールさせるか画像をクリックすると元に戻ります。