お問い合わせ

SWELL不具合:関連記事ブロック(ブログカード)文字化け対策カスタマイズ

SWELLのブログカード(関連記事ブロック)が特定の外部サイトだけ文字化けするようになりました。

今までは文字化けしていなかったのですが、先方サイトのリニューアルの影響があった模様です。

フォーラムに同じ内容の投稿があったので、この記事でまとめてみます。

今回の問題は、SWELL ver2.7.8.3で改善されました。
SWELL最新版にアップデートすることでこの記事の不具合は起きません。

時間が無い人用のまとめ:関連記事ブロック(ブログカード)文字化け

SWELLの関連記事ブロック(ブログカード)は、文字コードが指定されていなかったり、UTF-8以外だと文字化けします。

最新バージョンでも完全には修正されていません。

修正は親テーマのget_ogp_inwp.phpファイルを直接いじれば簡単に直せます。

修正方法を知りたい方は、こちらからどうぞ。

以前のバージョンで発生した問題点のまとめ

ブログカードが文字化けしたサイト

↓関連記事がこんな感じで文字化けします。

SWELLのブログカードが文字化けする理由

SWELLのブログカードはで外部サイトのデータをget_ogp_inwp.phpparse()でHTMLとして取得しています。

public static function parse( $response_body, $targets ) {

		// Data to be finally returned
		$ogp_data = [];

		// Avoid getting a loadHTML () parsing error
		$old_libxml_error = libxml_use_internal_errors( true );

		// Load HTML
		$doc = new DOMDocument();
		$doc->loadHTML( $response_body );

		libxml_use_internal_errors( $old_libxml_error );

DOMDocument::loadHTML特に指定しない限り、文字列は ISO-8859-1 (HTTP/1.1 のデフォルト文字セット) であるものとして扱われます。これにより、UTF-8 文字列が正しく解釈されなくなります。

https://stackoverflow.com/questions/8218230/php-domdocument-loadhtml-not-encoding-utf-8-correctly

元サイトのHTMLに以下の記述がないことが原因のようです。

<?xml encoding="utf-8" ?>

読み込んだHTMLを処理してブログカードの情報として利用しているのですが、HTMLの文字コードが明示的にUTF-8に指定されていない場合、ブログカードが文字化けします。

つまり、SWELLが利用しているコードは、PHPでnative DOMをスクレーピングする処理では定番の文字化け処理が抜けています。

SWELLのブログカードが文字化けを回避するコード

親テーマのアップデートで消えてしまうので、あまりやりたくない方法ですが、SWELLが使っているライブラリを直接書き換えるしか方法がありません。

$doc->loadHTML( $response_body );$doc->loadHTML( mb_convert_encoding($response_body, 'HTML-ENTITIES', 'UTF-8') );

に置き換えます。

public static function parse( $response_body, $targets ) {

		// Data to be finally returned
		$ogp_data = [];

		// Avoid getting a loadHTML () parsing error
		$old_libxml_error = libxml_use_internal_errors( true );

		// Load HTML
$doc = new DOMDocument();
//$doc->loadHTML( $response_body );
$doc->loadHTML( mb_convert_encoding($response_body, 'HTML-ENTITIES', 'UTF-8') );

		libxml_use_internal_errors( $old_libxml_error );

SWELL最新版でも解消しない文字化けへの対応

SWELLでブログカードの文字化け対策は行われましたが、以前としてブログカードの文字化けが発生するサイトはあります。

むしろ増えてきている感じもあります。

例えば、Xserverのマニュアルページなどは、SWELLでブログカードを作成すると文字化けします。

↓こんな感じです。(将来のバージョンで直っているかもしれません・・・)

SWELLで文字化けが発生するようなサイトでも、Cocoonを使うとブログカードの文字化けが発生しません。

Cocoonのブログカードのソースコードはgithubで公開されているので、SWELLのブログカードと何が違うか調べてみました。

$HTML = mb_convert_encoding($HTML, 'UTF-8', 'ASCII, JIS, UTF-8, EUC-JP, SJIS');が追加されています。

SWELLのコードにも同じように追加すると文字化けが発生しなくなりました。

    // //UTF-8ページの文字化け問題
    // //対処法1:http://qiita.com/kobake@github/items/3c5d09f9584a8786339d
    // //対処法2:http://nplll.com/archives/2011/06/_domdocumentloadhtml.php
    // $HTML = @mb_convert_encoding($HTML, 'HTML-ENTITIES', 'ASCII, JIS, UTF-8, EUC-JP, SJIS');

    // 上記の方法で新しいPHPの仕様で非推奨になったため、以下の方法を選択
    // //対処法3:https://wp-cocoon.com/community/postid/77632/
    $HTML = mb_convert_encoding($HTML, 'UTF-8', 'ASCII, JIS, UTF-8, EUC-JP, SJIS');
    $HTML = mb_encode_numericentity($HTML, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8');

SWELLのブログカードの文字化け解消(Cocoon相当)

	public static function parse( $response_body, $targets ) {

		// Data to be finally returned
		$ogp_data = [];

		// DOMDocument::loadHTML は、文字列をISO-8859-1として扱うため UTF-8 文字が化けてしまう。それを防ぐために mb_convert_encoding() を使う。
		// $response_body = mb_convert_encoding( $response_body, 'HTML-ENTITIES', 'UTF-8' );
$response_body = mb_convert_encoding($response_body, 'UTF-8', 'ASCII, JIS, UTF-8, EUC-JP, SJIS');
		// 非推奨な mb_convert_encoding の代わりに mb_encode_numericentity を使ってhtmlエンコード
		$response_body = mb_encode_numericentity( $response_body, [0x80, 0x10FFFF, 0, 0x1FFFFF ], 'UTF-8' );

SWELLは有料テーマなのに無料テーマのCocoonに機能的に劣っているというのはとても残念なことです。

SWELLブログカードの文字化け修正がアップデートでも消えないようにする

修正するファイルは、get_ogp_inwp.phpなのですが、親テーマにあるファイルです。

親テーマのファイルを変更すると、SWELLのアップデートがあった時に先祖返りしてしまいます。

それを避ける方法を考えてみました。

まず、子テーマに修正したget_ogp_inwp.phpを用意します。

SWELLにアップデートがあった時に、swell_versionが更新されます。

そのタイミングで、親テーマのget_ogp_inwp.phpを、子テーマのget_ogp_inwp.phpで上書きするようにフックで動かします。

add_filter('pre_update_option_swell_version', 'swell_version_callback_update', 10, 3);

function swell_version_callback_update(  $value,  $old_value,  $option ) {

	// do stuff on update_option    
	$ogp_fname = get_template_directory()."/classes/plugins/get_ogp_inwp.php";
	$ogp_child_fname = get_stylesheet_directory()."/get_ogp_inwp.php";


	rename($ogp_fname , $ogp_fname.".bak");
	copy($ogp_child_fname,$ogp_fname);
	
	return $value;
}

It’s worth mentioning that this hook won’t fire if the old option value is exactly the same as the new one, meaning it won’t change anything in DB.

If you want to fire some additional code on update option event, I suggest using "pre_update_option_{$option}" hook instead.

https://developer.wordpress.org/reference/hooks/update_option_option/

SWELLのサイトが複数ある場合の処置

今どきのレンタルサーバーはマルチドメインで10個ぐらいWordpressを入れても普通に動きます。

SWELLが1つのライセンスで複数サイトに適用可能なので、一つのサーバーで多くのサイトを運用している人も多いかと思います。

いちいち、ファイルを置き換えるのも面倒ですから、以下のコマンドで一発で置き換えることができます。

コマンド実行場所の一つ上に、コピーしたいget_ogp_inwp.phpを置いておきます。

コマンド実行場所の下位ディレクトリにあるget_ogp_inwp.phpを全てコピーして上書きします。

 find ./ -type f -name get_ogp_inwp.php -exec cp ../get_ogp_inwp.php {} \;

SWELLのアップデートがあるたびに実行すれば一瞬で対応できます。

まとめ

世の中に、SWELLのブログカードが文字化けするようなサイトがどれぐらいあるのか?というとそれほど多くはないでしょう。

通常のWordpressサイトであれば、以下の記述は間違いなくあるからです。

<?xml encoding="utf-8" ?>

今回のように、Vue.jsやNuxt.jsで作られたようなサイトの場合は、headに必要な情報が無いこともあり、今後は文字化けするサイトが増えていく可能性があります。

他の人にもシェアしてね
コメントを閉じる

コメント

コメントする

コメントは日本語で入力してください。(スパム対策)

クリックできる目次