Page No.3

plugin Simplistic Prism Highlighter Loader custom block

これは、コードを表示するブロックなので、当然、<pre><code> でラップされた要素ということになる。
まぁ、これがしかし、簡単そうで実に苦労したのですよ。”Block validation failed” エラーとの戦い。そして試行錯誤の繰り返し。
結局、→ Githubwp.blockEditor.PlainText を使う方法を見つけて解決できたのですけれど。
まずは php 部分から。

<?php
    function smplcprsm_cgb_register_block() {
        wp_register_script(
            'smplcprsm-hilighter-01',// スクリプトのid名を指定、下のregister関数で js ファイルを指定する時に使用する
            plugins_url( 'stx_cgb.js', __FILE__ ),
             // ↓ js ファイルのReactの方で、必要な関数のパッケージを指定
            array( 'wp-blocks', 'wp-block-editor', 'wp-element', 'wp-components' ),
            filemtime( plugin_dir_path( __FILE__ ) . 'stx_cgb.js' )
        );
         
        register_block_type( 'smplcprsm-hili/prism-hili',
            array( 'editor_script' => 'smplcprsm-hilighter-01',// js ファイルのidを指定
        ));
    }
?>
PHP
CopyExpand

そして javascript ファイル。
これも指定できるパラメータは、InspectorControls を使ってサイドバーにて設定できるようになってる。

( function( blocks, element, components, blockEditor  ) {
    var el = element.createElement,
        Fragment = element.Fragment,
        registerBlockType = blocks.registerBlockType,
        InspectorControls = blockEditor.InspectorControls,
        TextControl = components.TextControl,
        CheckboxControl = components.CheckboxControl;
   
    registerBlockType( 'smplcprsm-hili/prism-hili', {
        title: 'Hilighter: pre-code',
        icon: 'smiley',
        category: 'layout',
        description: 'prism.js HighLighter block',

        attributes: {
            content: {
                type: 'string',
            },
            linenumb: {
                type: 'boolean',
                default: true,
            },
            textlang: { type: 'string', default: '' },
            textline: { type: 'string', default: '' },
            textstart: { type: 'string', default: '' },
            textname: { type: 'string', default: '' },
            textnumber: { type: 'string', default: '' },
            textfont: { type: 'string', default: '' }
        },

        supports: {
            //save関数で返される要素に対する設定
            className: false, //(default:true)ブロック要素を作成した際に付く .wp-block-[ブロック名]で自動生成されるクラス名の設定。
        },

        edit: function( props ) {
            let content = props.attributes.content,
                linenumb = props.attributes.linenumb,
                textlang = props.attributes.textlang,
                textline = props.attributes.textline,
                textstart = props.attributes.textstart,
                textname = props.attributes.textname,
                textnumber = props.attributes.textnumber,
                textfont = props.attributes.textfont;

            return (
                el(
                    Fragment,
                    null,
                    el(
                        InspectorControls,
                        null,
                        el(
                            TextControl,
                            {
                                label: 'language',
                                help: 'e.g. php, javascript, css, html, empty default php',
                                value: textlang,
                                onChange: function ( newValue ) { props.setAttributes( { textlang: newValue } ); }
                            }
                        ),
                        el(
                            CheckboxControl,
                            {
                                heading: 'show line-numbers',
                                // label: 'Tick Me',
                                // help: 'Additional help text',
                                checked: linenumb,
                                onChange: function ( newValue ) { props.setAttributes( { linenumb: newValue } ); }
                            }
                        ),
                        el(
                            TextControl,
                            {
                                label: 'line-high-light',
                                help: 'e.g. 20,68,70,80-85',
                                value: textline,
                                onChange: function ( newValue ) { props.setAttributes( { textline: newValue } ); }
                            }
                        ),
                        el(
                            TextControl,
                            {
                                label: 'font-size',
                                help: 'parent div font-size em,px, etc.',
                                value: textfont,
                                onChange: function ( newValue ) { props.setAttributes( { textfont: newValue } ); }
                            }
                        ),
                        el(
                            TextControl,
                            {
                                label: 'start number',
                                help: 'start number of line-numbers',
                                value: textstart,
                                onChange: function ( newValue ) { props.setAttributes( { textstart: newValue } ); }
                            }
                        ),
                        el(
                            TextControl,
                            {
                                label: 'title',
                                help: 'code title e.g. file name, function name',
                                value: textname,
                                onChange: function ( newValue ) { props.setAttributes( { textname: newValue } ); }
                            }
                        ),
                        el(
                            TextControl,
                            {
                                label: 'random line-numbers',
                                help: 'e.g. 5-10,_2,25-35,_5,146,157,200-220  _ is no number line',
                                value: textnumber,
                                onChange: function ( newValue ) { props.setAttributes( { textnumber: newValue } ); }
                        ),
                    ),
                    el( wp.blockEditor.PlainText, {
                        className: props.className,
                       // 下の行、&lt; と &gt; の & は変換されてしまうため全角になっています
                        value: content ? content.replaceAll( '&lt;', '<' ).replaceAll( '&gt;', '>' ) : '',
                        onChange: function ( content ) { props.setAttributes( { content: content } ); },
                    })
                )
            );
        },

        save: function( props ) {
            let content = props.attributes.content,
                linenumb = props.attributes.linenumb ? 'line-numbers' : '',
                textlang = props.attributes.textlang,
                textline = props.attributes.textline,
                textstart = props.attributes.textstart,
                textname = props.attributes.textname,
                textnumber = props.attributes.textnumber,
                textfont = props.attributes.textfont,
                divprop = { className: 'highlighter_js' },
                preprop = {};
        
            textlang = 'language-' + ( textlang ? textlang.replace( /</g, '' ) : 'php' );
            if ( linenumb ) {
                preprop['className'] = linenumb;
            }
            if ( textline ) {
                preprop['data-line'] = textline.replace( /"/g, '' ).replace( /</g, '' );
            }
            if ( textstart ) {
                preprop['data-start'] = String( textstart ).replace( /"/g, '' ).replace( /</g, '' );
            }
            if ( textfont ) {
                divprop['style'] = 'font-size:' + textfont.replace( /"/g, '' ).replace( /</g, '' ) + ';';
            }
            if ( textname ) {
                divprop['data-name'] = textname.replace( /"/g, '' ).replace( /</g, '' );
            }
            if ( textnumber ) {
                divprop['data-numbers'] = textnumber.replace( /"/g, '' ).replace( /</g, '' );
            }

            return (
                el( 'div', divprop,
                    el( 'pre', preprop,
                        el( 'code', { className: textlang }, content )
                    )
                )
            );
        },
    } );
})(
    window.wp.blocks,
    window.wp.element,
    window.wp.components,
    window.wp.blockEditor
);
JavaScript
CopyExpand

今のところ、自作の custom block はこれだけ。
なお、この prism.js highlighter 用のブロックは、私のレンタルサーバーで使ってみたところ(このページのコード部分は全てこれを使ってます)、「更新に失敗しました。 返答が正しい JSON レスポンスではありません」のエラーが出てしまいました。で、試しに標準装備の code block でもやってみたところ同様のエラーが排出されてしまいます。なので、これは block 自体の問題ではなく、サーバーの WAF によるものです。念の為、サーバーの WAF のログを確認したところ、しっかりと我が ip によるログが残ってました。これの対処法はネットで検索すれば教えて下さってるサイトがすぐにみつかります。.htaccess に自ip を無視する記述をするだけです。以下のよう。言わずもがな、ip(***.***.***.***) は自己 ip アドレスを入力するということ。

<IfModule mod_siteguard.c>
SiteGuard_User_ExcludeSig ip(***.***.***.***)
</IfModule>
PHP
CopyExpand

で、このあと、新しい投稿を書いていて気がついたのだけれど、標準付属のブロックの中に <dl> タグが無いのではなかろうか?と。よくわからないけれどなぜ無いのだろうか?
なければ作りたくなるというもので、さっそく作ってしまった。これは innerblock を使えばよさそう、と言うことで以下のよう。
innerblock は本家Gutenberg Handbook Tutorials にある雛形ほぼそのまんま。子要素の dt、dd においてもほぼ基本的なもの。
一つの即時関数にまとめて入れているのだけれど、切ったり貼ったりしてやっていると指定している引数と仮引数の順番が違ってしまっていた、なんてことになっていた。当然のこと、これは対応している物同士が同じ順番にないとエラーとなってしまう。基本的なことではあるけれど、思わぬところではまってしまうということもあるので・・・。

( function( blocks, blockEditor, element ) {
    const { registerBlockType } = blocks, // 分割代入の書き方、registerBlockType = blocks.registerBlockType と同意
        el = element.createElement,
        RichText = blockEditor.RichText,
        InnerBlocks = blockEditor.InnerBlocks,
        useBlockProps = blockEditor.useBlockProps;

    registerBlockType( 'stx-dl/wrappeddl', {
        title: 'wrapped dl tag',
        icon: 'align-none',
        category: 'design',

        supports: {
            className: false, 
        },

        edit: function() {
            var blockProps = useBlockProps();

            return el(
                'dl',
                blockProps,
                el( InnerBlocks, {  allowedBlocks: [ 'stx-dt/wrappeddt', 'stx-dd/wrappeddd' ] } )
            );
        },

        save: function() {
            var blockProps = useBlockProps.save();

            return el(
                'dl',
                blockProps,
                el( InnerBlocks.Content )
            );
        },
    } );

    registerBlockType( 'stx-dt/wrappeddt', {
        title: 'wrapped dt tag',
        icon: 'align-pull-left',
        category: 'design',
        // description: 'wrapped p tag',
        parent: [ 'stx-dl/wrappeddl' ],
        attributes: {
            content: {
                // type: 'array',
                source: 'html',
                selector: 'dt',
            },
        },

        supports: {
            //save関数で返される要素に対する設定
            className: false, //(default:true)ブロック要素を作成した際に付く .wp-block-[ブロック名]で自動生成されるクラス名の設定。
        },

        edit: function( props ) {
            var blockProps = useBlockProps(),
                content = props.attributes.content;

            function onChangeContent( newContent ) {
                props.setAttributes( { content: newContent } );
            }

            return el(
                RichText,
                Object.assign( blockProps, {
                    tagName: 'dt',
                    className: props.className,
                    onChange: onChangeContent,
                    value: content,
                } )
            );
        },

        save: function( props ) {
            var blockProps = useBlockProps.save();
            return el(
                RichText.Content,
                Object.assign( blockProps, {
                tagName: 'dt',
                value: props.attributes.content,
                } )
            );
        },
    } );

    registerBlockType( 'stx-dd/wrappeddd', {
        title: 'wrapped dd tag',
        icon: 'align-pull-right',
        category: 'design',
        // description: 'wrapped p tag',
        parent: [ 'stx-dl/wrappeddl' ],

        attributes: {
            content: {
                // type: 'array',
                source: 'html',
                selector: 'dd',
            },
        },

        supports: {
            //save関数で返される要素に対する設定
            className: false, //(default:true)ブロック要素を作成した際に付く .wp-block-[ブロック名]で自動生成されるクラス名の設定。
        },

        edit: function( props ) {
            var blockProps = useBlockProps(),
                content = props.attributes.content;

            function onChangeContent( newContent ) {
                props.setAttributes( { content: newContent } );
            }

            return el(
                RichText,
                Object.assign( blockProps, {
                    tagName: 'dd',
                    className: props.className,
                    onChange: onChangeContent,
                    value: content,
                } )
            );
        },

        save: function( props ) {
            var blockProps = useBlockProps.save();

            return el(
                RichText.Content,
                Object.assign( blockProps, {
                tagName: 'dd',
                value: props.attributes.content,
                } )
            );
        },
    } );
}(
    window.wp.blocks,
    window.wp.blockEditor,
    window.wp.element
) );
JavaScript
CopyExpand

ということで React なんだそうだ。独自のカスタムブロックを作ろうとするなら、なにはなくとも React を勉強しないといけないということになる。
しかし、いざ、それに取り掛かろうとするにしても、どうにも気が乗らないのは、React を使うには、やれ Babel だの JSX だの webpack だのというもろもろが関わってくることである。React を一般的な感覚にあわせて使おうとするならば、それらが必須なのだそうだ。もはや jQuery でさえ、なるべく使わないようにして、プレーンな javascript でまかなおうと考えていたりするのに、そんなにいくつものライブラリに頼らないといけないということに、逆行というのかなんとも矛盾を感じてしまう。などなど考えていると、本当にこの React というものが必要なのだろうかと、気が重くなってきてしまい、どうにもぐずぐずとしてしまうわけなのである。一時的なものなのでは?とか、さほど大きくないページなのに?とか、先んじた ES6 の書式にしても結局 Babel にてわざわざ ES5 に戻されるのであれば、現時点においてそれを使う必要があるのか?とか、そもそも windowsNode.js を入れたくないということもあるしで、どうにもベクトルは否定的な方へと向かってしまうのである。それらを使うことによってより高速化ができるということなら、全く迷うことはなく、なんとかしてそれらを利用しようとはするのだけれど。Virtual DOM を謳う React ではあるけれど、個人のページや巨大でもないフォームページにおいて、はたしてどれだけ有効なものであるのか、余計なものを介する分、逆に負荷としての存在にしかならないような気がしてならない。
まぁ、ブロックエディタ自体が管理画面の投稿ページにおいてのことではあるし、速度的なことよりもシステムの作りやすさとか、実際のページの表示に近づけるとか、といったことにより重きをおいた選択なのだろう。
などと思うのではあるけれど、良く知るためには関わってみるしかないわけで、なんとか取り掛かって、少し覗き見てみると、それらのライブラリは必須ということではなく、本流のやり方からは外れてしまう少数派になってしまうのかもしれないけれど、無理して使わなくても ES5 でも書けるということがわかってきた。
つづく・・・> 「 Gutenberg Block Editor 自作その2 – id指定
そしてさらに・・・>「Gutenberg Block Editor 自作その3 – form編

Sanbanse Funabashi

Top

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