Amazonランキング大賞2018

[WordPress]この記事だけでいい!特定の記事、固定ページだけでHTMLの自動整形を無効化する方法

WordPressのおせっかい機能。HTML自動整形。

HTMLを編集し、ビジュアルエディタとテキストエディタを行き来していると勝手に<br>、<p>タグが消えてたり。
<span>タグも容赦なく葬られていたり。

CSSで装飾したのに反映されていない。どうして?と思ったら表示されている記事に見に覚えのない<p>タグが挿入されていてセレクタが届いていない、widthもそっちに引っ張られてて表示が崩れている。

ブログに書くのもなれてきて、ちょっとHTMLもいじってみようかな〜。で誰しもがぶち当たる問題だと思ってます(個人的に)。

自動整形を止めることは出来るけど、問題が…

テーマによっては自動整形を無効化する機能が標準で備わっています。
プラグインを利用する手段もありますね。

テーマ、プラグインに頼らずfunctions.phpに記述して無効化する手段もあります。

functions.php
//記事表示時の整形無効
add_action(
	'wp_head',
	function(){
		remove_filter('the_content', 'wpautop');
		remove_filter('the_excerpt', 'wpautop');
	}
);

//ビジュアルエディタ(TinyMCE)の整形無効
add_filter(
	'tiny_mce_before_init',
	function($init_array){
		global $allowedposttags;
		$init_array['valid_elements']          = '*[*]';
		$init_array['extended_valid_elements'] = '*[*]';
		$init_array['valid_children']          = '+a[' . implode( '|', array_keys( $allowedposttags ) ) . ']';
		$init_array['indent']                  = true;
		$init_array['wpautop']                 = false;
		$init_array['force_p_newlines']        = false;
		return $init_array;
	}
);

しかし…!既に運用中のブログで導入すると、今まで書いてきた記事全てに影響してしまいます。
自動整形によって改行されていた(自動で<p>タグを挿入してくれていた)部分が、無効化されてしまい、以前書いていた記事全てから改行が無くなっている、なんてことが起きる場合も(当ブログのことですが)。

参考 WordPressの自動整形(ビジュアルエディタ含む)を無効にする方法Qiita

なぜこんな事が起きるのか

記事編集中にタグが消えることばかりが目立っていますが、自動整形機能は記事を表示するときにも行われています。

その時にも、改行が2つ続いている時は<p>タグで囲って段落化してくれる…といった整形をしてくれているわけですね。

自動整形機能は2種類ある

wpautop関数による整形機能と、ビジュアルエディタ(TinyMCE)の整形機能、2つの整形処理が働いています。
記事編集中はTinyMCEの整形機能が…記事表示の時にはwpautop関数の整形機能が…。

2種類の整形機能が動いているため、混乱の原因になっているんですね。
前述で紹介したfunctions.phpの無効化処理は、この両方を止めています。

参考 TinyMCECodex 参考 wpautopCodex

本題はここから

述べたとおり、既に運用中のブログで自動整形機能を無効化するのは厳しいです。
今まで書いてきた記事全てを総点検、総編集する必要が出てきます。

そもそも自動整形機能は、それはそれで便利ですしね。
HTMLをいじらない記事であれば知らず知らずにお世話になっているものです。

そこで投稿記事ごとに、整形の有効無効が切り替えられれば…ということで作ってみました。

記事投稿画面のサイドバーに、上記のカスタムフィールドを追加しました。
「整形しない」にチェックすることで記事毎に整形機能の有効無効を切り替えられます。

通常は「整形する」を利用し、HTMLの編集をする記事を書く時だけ「整形しない」にすれば、自動整形を便利に利用しながら運用していけます。

「整形しない」を選択した記事だけが整形無効化の処理をするので、既に運用中のブログで実装しても、既存記事に影響はありません。

実装方法は下記のコードをfunctions.phpにコピペすればOKです。
※WordPress管理画面から[外観]→[テーマの編集]→[functions.php]

functions.php
//==============================================================================
//
//	自動整形を無効にするカスタムフィールドを作成
//
//==============================================================================

//	アクションフックに登録:管理画面にカスタムボックスをエントリー
add_action(
	'add_meta_boxes', 
	function(){
		$screens = array('post', 'page');
		foreach($screens as $scrn){
			add_meta_box(
				'peralab-custombox-dont-autoformatting', 	//編集画面セクションのHTML ID
				'自動整形を無効化', 	//メタボックスのタイトル
				'PeralabDontAutoFormatting_CustomBoxCreate', 	//入力フォーム作成で呼び出されるコールバック
				$scrn, 								//表示するページ
				'side', 							//メタボックス表示箇所(advanced, normal, side)
				'default', 							//表示優先度(high, core, default, low)
				null);								//コールバック時に渡す引数があれば指定
		}
	}
);

//	メタボックスを作成
function PeralabDontAutoFormatting_CustomBoxCreate($post){	//$postには現在の投稿記事データが入っています
	//入力済みのデータを取得
	$data_str = get_post_meta($post->ID, "dont_autoformat_radio", true);
	if($data_str != 'dont'){
		$data_str = 'format';
	}
	
	//nonce作成
	wp_nonce_field('action-noncekey-dontautoformat', 'noncename-dontautoformat');

	?>
	<div>
	
	<!-- 出力する文字列 -->
	<p><label><input name="name-metabox_autoformat_radio" type="radio" value="format" <?php echo (($data_str == 'format') ? 'checked' : '') ?>>整形する(初期値)</label></p>
	<p><label><input name="name-metabox_autoformat_radio" type="radio" value="dont" <?php echo (($data_str == 'dont') ? 'checked' : '') ?>>整形しない</label></p>
	<p><label>ビジュアルエディタの整形無効の切り替えは[下書き保存] [更新]などで記事の保存後から反映されます。</label></p>
	
	</div>
	<?php
}

//--------------------------------------------------------------
//	カスタムボックス内のフィールド値更新処理
//--------------------------------------------------------------
add_action(
	'save_post', 
	function($post_id){
		//nonceを確認
		if(isset($_POST['noncename-dontautoformat']) == false 
				|| wp_verify_nonce($_POST['noncename-dontautoformat'], 'action-noncekey-dontautoformat') == false) {
			return;	//nonceを認証できなかった
		}
		
		//自動保存ルーチンかどうかチェック。そうだった場合はフォームを送信しない(何もしない)
		if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE){
			return;
		}
		
		//パーミッション確認
		if(isset($_POST['post_type'])){
			if($_POST['post_type'] == 'page'){
				if(!current_user_can('edit_page', $post_id)){
					return;	//固定ページを編集する権限がない
				}
			}
			else{
				if(!current_user_can('edit_post', $post_id)){
					return;	//記事を編集する権限がない
				}
			}
		}
		
		//== 確認ここまで ==

		
		//予約投稿時は、データが有るにも関わらず$_POSTからデータ取得ができないので、
		//issetでデータ確認が出来るときのみ値の更新処理を行います。
		if(isset($_POST['name-metabox_autoformat_radio'])){
			update_post_meta($post_id, "dont_autoformat_radio", $_POST['name-metabox_autoformat_radio']);
		}
	}
);

//=========================
//	自動整形無効の実処理
//=========================

//記事表示時の整形無効
add_action(
	'wp_head',
	function(){
		if(get_post_meta(get_the_ID(), 'dont_autoformat_radio', true) == 'dont'){
			remove_filter('the_content', 'wpautop');
			remove_filter('the_excerpt', 'wpautop');
		}
	}
);

//ビジュアルエディタ(TinyMCE)の整形無効
add_filter(
	'tiny_mce_before_init',
	function($init_array){
		if(get_post_meta(get_the_ID(), 'dont_autoformat_radio', true) == 'dont'){
			global $allowedposttags;
			$init_array['valid_elements']          = '*[*]';
			$init_array['extended_valid_elements'] = '*[*]';
			$init_array['valid_children']          = '+a[' . implode( '|', array_keys( $allowedposttags ) ) . ']';
			$init_array['indent']                  = true;
			$init_array['wpautop']                 = false;
			$init_array['force_p_newlines']        = false;
		}
		return $init_array;
	}
);

正しくコピペできていれば、記事投稿画面に設定項目が追加されます。

注意点

ビジュアルエディタの整形機能の有効無効は画面の読み込み時に行われているため、「整形する・しない」を切り替えたら、いったん記事を保存するなどして画面全体を再読込させないと整形の有無は切り替わりません。

「整形しない」に設定してもビジュアルエディタとテキストエディタの切り替えをしていると、HTML上、完全に表示に関係のない空白などが除去されてしまいますが、これは防げませんでした。
調べた限り見つからない。古い情報だと「それは出来ない」みたいなのもあったので、現時点で難しそう。タグの追加や削除などは行われないので、実用上は問題ないはずです。

既にテーマやプラグインなどで自動整形無効化処理を導入している場合、「整形する」を選択しても自動整形機能は有効になりません。
これは紹介したカスタムは「整形しない」場合に、自動整形機能を無効化する処理を行っているだけであり、「整形する」を選択した場合は「何も処理をしない」ためです。(自動整形機能を止めないから結果的に整形機能が有効になる)
従ってテーマなどで整形機能を既に無効化している場合は、このカスタム機能は意味をなしません。

おわり

このカスタムは下記記事を書いている時に必要に迫られて作りました。

[SANGO]ヘッダーアイキャッチの文字に縁取りをして見やすくしよう。カスタムツールでCSS自動生成。

※今はVue.jsで別ページに作り直してしまいましたが、当時はjQueryを使って記事内にカスタムツールを作っていました。

フォームを書いてCSSで編集して、とやっていたけど自動整形でめちゃめちゃにされる。
当ブログで使っている「SANGO」は自動整形無効機能があるから、チェック入れてみたら既存記事がめちゃめちゃ。

なんとかいい形で解決ができてよかったです。

それとあまり言及してませんでしたが、投稿記事だけでなく固定ページでも使えます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です