wordpressへのコード埋め込み機能をプラグインなしで作る方法

wordpressはphpやjquery、cssなど、さまざまな言語やプログラムと深く関わっています。そのため、wordpress上でこれらの使い方をソースコードとして紹介されることがしばしばあります。そんな時によく利用されるのがコード埋め込みタイプのプラグインですが、簡単な物であれば自分でも作れたりします。

wordpressで簡単にコードの埋め込みをする方法

簡単に言えば、軽く装飾したボックスを作って、上側にコピーボタンを設置したタイプです。<や>は、&#60;と&#62;に変換しないとwordpress上の記事の表示が崩れるため、ショートコードで自動変換します。

コードの埋め込みをするためのショートコード

こんな感じで文章があったとします。便宜上わざとタブと空白をいれてます。内容は気にしないでください。このショートコードを使ってコードの埋め込みをします。

[code_wp]
wordpressとIEの格闘
cssとjqueryを駆使する
wordpressと他のブラウザはうまくいく
[/code_wp]
[code_wp]
エッジとIEはoverflowが利かなくなってる
    fire foxとchromeは上手くいきやすい
[/code_wp]

コードの埋め込みをするためのCSS

cssをこんな感じにします。ポイントは「white-space: pre;」と「overflow-x: scroll;」ですかね。これらがないと長いコードを一行で収めることができず、変なところで改行が入って埋め込みコードが少し見にくくなります。

<style>
.code_wordpress,.removeCode{
position:relative;
width:90%;
line-height:1.3em;
font-size:14px;
margin:10px 0 30px 0;
padding:45px 30px 20px 35px;
border: solid 1px #ccc;
counter-reset: codebox;
overflow-x: scroll;
}
div.code_wordpress div:nth-child(2n+1){background-color: #e9e9e9;width:100vw;white-space:pre;}
div.code_wordpress div:nth-child(2n) {background-color: #f4f4f4;width:100vw;white-space:pre;}
.getCode_c:after{
content:'     Copy';
}
</style>

コードの埋め込みをするためのjQuery

jqueryをこんな感じで作ります。ポイントはIEと他のブラウザの判定とPolyfillによってIEでもclosestを使えるようにしている点です。IEは標準だとclosestをそのまま利用できないため、Polyfillによって動かせるようにしています。closestは最も近い親のthisを得るために必要です。

fire foxやChromeと違ってIEだけは異なる動作をすることがたまにあります。エッジも変なところがIEによく似ていますね。まあ、後継ですから当たり前なのでしょうけれど。実はブラウザの相性にwordpressが参入してくることもあります。こちらのブラウザではうまく動くのにwordpressがこうなってるとあっちのブラウザでうまく動かないとか。

<script>
$(function(){
var userAgent = window.navigator.userAgent.toLowerCase();
var is_ie = (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('trident') >= 0);
$('.code_wordpress').prepend($('<span class="getCode_c"></span>'));
$('.getCode_c').css({'position':'absolute','top':'0','left':'0','width':'100%','height':'24px','z-index':'1','cursor':'pointer','opacity':'1','background':'#fff','color':'#aaa'});
if(is_ie){
$('.code_wordpress').addClass('removeCode');
$('.getCode_c').addClass('removeGetCode');
}
$('.getCode_c').on('click', function(){
if(is_ie){
var index = $('.getCode_c').index(this);
$('.removeCode').eq(index).removeClass('code_wordpress');
$('.removeGetCode').eq(index).removeClass('getCode_c');
if(!Element.prototype.matches){Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;}
if(!Element.prototype.closest){
Element.prototype.closest = function(s) {
var el = this;
do { if (el.matches(s)) return el; el = el.parentElement || el.parentNode; } while (el !== null && el.nodeType === 1);
return null;
};
}
}
var range = document.createRange();
if(is_ie){
range.selectNodeContents(this.closest('div.removeCode'));
}else{
range.selectNodeContents(this.closest('div.code_wordpress'));
}
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
document.execCommand("Copy");
alert('コピーしました');
selection.removeAllRanges();
if(is_ie){
$('.removeCode').addClass('code_wordpress');
$('.removeGetCode').addClass('getCode_c');
}
});
});
</script>

「functions.php」

以下をfunctions.phpに記述します。ポイントは、the_contentフックの9という優先順位です。省略したり10以上に設定するとwordpressの自動整形により、PやBRタグなどが勝手に入って表示がおかしくなります。なぜショートコードをthe_contentフックに通しているのかと言えばadd_shortcodeはフックの優先順位を設定できないからです。設定できないとwordpressの自動整形にやられます。wordpressのテンプレートから直接入力した文章は自動整形されないのですが、投稿本文はもろにやられます。

そして、改行を目印に一行ずつDIVタグで囲んでいますが、囲まないとwordpressの自動整形にやられてしまうので囲んでいます。自動整形を解除させるフックもありますが、念のためこうしてます。仕様が変わったりしますから。あと、開始タグと終了タグのカッコも文字参照によって変換しています。

add_shortcode( 'code_wp', '__return_false' );
add_filter( 'the_content', function ( $the_content ) {
global $shortcode_tags;
$base_shortcode = $shortcode_tags;
remove_all_shortcodes();
add_shortcode( 'code_wp', function ($arg, $content = null){
$Cr=[
'<' => '&#60;',
">" => '&#62;',
];
$content=strtr($content,$Cr);
$borg=explode("\r\n",$content);
$val2="";
$tag="div";
foreach($borg as $key => $val){
$val2.='<'.$tag.'>'.$val.'</'.$tag.'>';
}
$val2= preg_replace('/[\r\n]+/', '', $val2);
$val2=preg_replace('/^<'.$tag.'><\/'.$tag.'>|<'.$tag.'><\/'.$tag.'>$/ium', '', $val2);
$val2 = preg_replace('/<'.$tag.'><\/'.$tag.'>/', '<'.$tag.'> </'.$tag.'>', $val2);
return '<div class="code_wordpress">'.$val2.'</div>';
});
$the_content = do_shortcode( $the_content );
$shortcode_tags = $base_shortcode;
return $the_content;
}, 9);

まとめ

wordpressでソースコードを埋め込みする場合は、基本的に文字参照による変換をしてから投稿したほうが良いような気もするのですが、あとからでもphpMyAdminのsql文やプラグインなどでデータベース内を書き換えることもできます。これは考え方の問題だと思いますが、はじめから変換しておいたらあとで何かwordpressの仕様変更やプラグインの干渉などによっておかしくなってしまう確率を下げることができます。投稿する前に自分専用のエディタやプラグインなどを通して自動変換しておいたらあとあと楽かも知れませんね。