Wonderful! WordPress

プラグイン Simplistic Prism Highlighter Loader

Page No.2

まだまだ続くclass。
管理画面メニューにオプション設定ページを表示するための処理と、Gutenberg block editor に対応するための処理なのだけれど・・・。
Gutenberg への対応においては、まずはカスタムblock の作成を考えました。が、あれやこれやとやってみたもののこれがなかなか難儀で・・・。なんとも難解ですね、すんなりとはいかせてくれない。block を作成したあとでタグを編集すると、どうしてもjavascript はコンソールに'Block validation failed' という長々としたエラーを吐き出すし、まぁ、でも止まってしまうというわけでもないので、そんなもの無視してしまえば良いという気もするのだけれど。
この時点で、とりあえず、きちんとした結果が得られたのはカスタムblock を作成することではなくて、ページ生成時にブロックが生成される時のフィルターフック'render_block'を使ってタグを編集するやり方。しかし、これだとページにアクセスがあって実行されることなので、表示することに負荷が増えるということであまり気が乗らない。できれば、セーブされた投稿ですでにそうなっているということが理想なんだなぁ。ということで、紆余曲折と試行錯誤が続きます。
WordPress Gutenberg のサイトにあるチュートリアルをやって、基本的なブロックをつくるのは簡単なことがわかりましたが、いざ、それをcode ブロックのようなものに、となるとこれがうまくいかない。texterea を使ってみたりとか色々と散々やってみたものの、まったく、どうにもならない。それでも諦めずにヒントを探しまわっていると、ちゃんとGithub にありました。 wp.blockEditor.PlainText を使用するとのこと。→WordPress/gutenberg/packages/block-editor/src/components/plain-text/
ありがたいことに、これによってまずまず目的のblock ができたと思います。
いくつかのパラメータはサイドバーの項目で設定できるようになってます。そのサイドバーあたりの処理は、InspectorControlsで、これもGithub にあったもの。ここですね→ gutenberg/packages/block-editor/src/components/inspector-controls/
これらに関してはもう少し下の方で。
« Gutenberg block editor » においては、実は、標準の code block prism を使用することが可能です。
普通に、目的のコードを貼り付けるか記入する。サイドバーの 高度な設定 -> 追加cssクラス において例えばそのコードがphpであれば、'language-php' と入力。これで、<pre><code> のタグによる素の prism が表示されます。行番号を表示させたければ、'language-php line-numbers' と。ただ、この場合だと、<pre> タグに 'data-line' 属性を付加することはできないのでラインマークを表示させることはできません。まぁ、素のprism がよければ、そちらで。

<?PHP
    // ↓ class 続き
    // ↓ここから管理画面のメニューにオプション設定ページを登録する処理
	public function smplcprsm_add_menu() {
		add_options_page( 'Simplistic Prism Highlighter Loader plugin Option', 'Simplistic Prism Highlighter Loader Option', 'administrator', 'smplcprsm_plugin_options', array( $this, 'smplcprsm_page_output' ) );
		add_action( 'admin_init', array( $this, 'register_smplcprsm_settings' ) );
	}
	 
	public function register_smplcprsm_settings() {
		register_setting( 'smplcprsm-settings-group', $this->option_name );
	}
	
	public function smplcprsm_page_output() {
        // $lang = $this->lang_recognize();
        $lang = 'ja';

        // 管理画面、プラグインオプションページに表示させる内容は別ファイル
        include_once 'smplcprsm_options.php';
	}
	//↑ここまで

    // Gutenberg block editor において、標準のcode block を使用した場合に、
    // ページ生成時にブロックが生成される時のフィルターフック、'render_block'を使ってタグを編集する処理
    // highlighter 用の custom block が作れたので、この関数は使用していないが、参考までに掲載
    // 実際のプラグインでは消去済み。
    public function wporg_block_wrapper( $block_content, $block ) {

        // ローカル環境で得た$block の持つ情報
        // $block['blockName'] -> 'core/code'
        // $block['attrs']['className'] -> 'language-php line-numbers data-line10,13-15,20 data-numbers5-10,_2,25-35,40 enhook'
        // $block['attrs']['className']は、block editor サイドバーの 高度な設定->追加cssクラス において入力した文字列そのまま
        // $block['innerHTML'] -> 排出されるタグを含んだコンテント全て === $block_content
        // $block['innerContent'][0] -> $block['innerHTML']と同じで排出されるタグを含んだコンテント全て === $block_content
        // タグを含まない素のコンテントの情報を持っていればと期待したのだけれど・・・

        if ( $block['blockName'] === 'core/code' ) {
            if ( isset( $block['attrs']['className'] ) ) {
                $preelem = explode( ' ', $block['attrs']['className'] );

                if ( in_array( 'enhook', $preelem ) ) {

                    $tmpcont = $block_content;
                    $data_line = '';
                    $lang = '';
                    $language = '';
                    $data_numbers = '';
                    $line_number = '';
            
                    foreach( $preelem as $val ) {
                        if ( false !== strpos( $val, 'data-line' ) ) {
                            $data_line = str_replace( 'data-line', ' data-line="', $val ) . '"'; 
                        } elseif ( false !== strpos( $val, 'language-' ) ) {
                            $lang = str_replace( 'language-', '', $val );
                            $language = $val;
                        } elseif ( $val === 'line-numbers' ) {
                            $line_number = ' line-numbers';
                        } elseif ( false !== strpos( $val, 'data-numbers' ) ) {
                            $data_numbers = str_replace( 'data-numbers', ' data-numbers="', $val ) . '"';
                        }
                    }
            
                    $from = strpos( $tmpcont, '<code' ) + 6;
                    $piece = strpos( $tmpcont, '/code>' ) + 6 - $from ;
                    $tmpcont = substr( $tmpcont, $from, $piece );
            
                    $content = '<!-- ' . $block['attrs']['className'] . " -->\n" . '<div class="highlighter_js" data-name="' . $lang . '"' . $data_numbers . '>';
                    $content .= '<pre class="' . $line_number . '"' . $data_line . '>';
                    $content .= '<code class="' . $language . '">';
                    $content .= $tmpcont;
                    $content .= '</pre></div>';
                    return $content;
                }
            }
        }
        return $block_content;
    }

    // Gutenberg block editor 用にhighlighter 用の custom code block を登録
    public function smplcprsm_cgb_register_block() {
        wp_register_script(
            'smplcprsm-hilighter-01',
            plugins_url( 'stx_cgb.js', __FILE__ ),
            array( 'wp-blocks', 'wp-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',
        ));
    }
    // ↓ class 続く
?>
PHP
CopyExpand

そしてclass の最後。

<?PHP
    // ↓ class 続き
    // option設定により起動するページを選択する関数郡
    // それぞれのページの属性の違いにより呼び出す関数を別にしている
    private function isfront() {
        $result = 0;

        if ( 'top' === $this->ret_option['onlyhome'] ) {
            $result = 1;
        }    

        if ( $this->page_prop['ispage'] ) {
            $result = $this->ispage( $result );
        }
        return $result;
    }

    private function issingle() {
        $result = 0;

        if ( '' !== $this->ret_option['onlysingle'] ) {
            $single = explode ( ',', $this->ret_option['onlysingle'] );

            if ( 'all' === $single[0] ) {
                $result = 1;
            } elseif ( 'lc' === $single[0] ) {
                // custompost の場合は先に iscustompost がヒットする
            } else {
                if ( in_array ( $this->page_prop['postid'], $single, true ) ) {
                    $result = 1;
                }
            }
        }
            // ページidによりロードさせない指定がある場合
        if ( $this->ret_option['unload'] ) {
            $unloads = explode( ',', $this->ret_option['unload'] );

            if ( in_array( $this->page_prop['postid'], $unloads, true ) ) {
                $result = 0;
            }
        }
        return $result;
    }

    private function ispage( $res = 0 ) {
        $result = $res;

        if ( '' !== $this->ret_option['directpage'] ) {
            if ( 'all' === $this->ret_option['directpage'] ) {
                $result = 1;
            } else {
                $pages = explode ( ',', $this->ret_option['directpage'] );

                if ( in_array( $this->page_prop['postid'], $pages, true ) ) {
                    $result = 1;
                }
            }
        }
            // ページidによりロードさせない指定がある場合
        if ( $this->ret_option['unload'] ) {
            $unloads = explode( ',', $this->ret_option['unload'] );

            if ( in_array( $this->page_prop['postid'], $unloads, true ) ) {
                $result = 0;
            }
        }
        return $result;
    }

    private function iscategory() {
        $result = 0;

        if ( '' !== $this->ret_option['onlycate'] ) {
            $cates = explode ( ',', $this->ret_option['onlycate'] );

            if ( 'all' === $cates[0] ) {
                $result = 1;
            } else {
                if ( in_array ( $this->page_prop['iscategory'], $cates ) ) {
                    $result = 1;
                }
            }
        }
        return $result;
    }

    private function istag() {
        $result = 0;

        if ( '' !== $this->ret_option['onlytag'] ) {
            $tags = explode ( ',', $this->ret_option['onlytag'] );

            if ( 'all' === $tags[0] ) {
                $result = 1;
            } else {
                if ( in_array ( $this->page_prop['istag'], $tags ) ) {
                    $result = 1;
                }
            }
        }
        return $result;
    }

    private function iscustompost() {
        $result = 0;

        $customs = [];
        if ( '' !== $this->ret_option['directcustom'] ) {
            $customs = explode ( ',', $this->ret_option['directcustom'] );
            $customs = array_filter( $customs );

            if ( in_array( $this->page_prop['iscustompost'], $customs, true ) ) {
                $result = 1;
            }
        }

        if ( $this->page_prop['issingle'] ) {
            if ( '' !== $this->ret_option['onlysingle'] ) {
                $single = explode ( ',', $this->ret_option['onlysingle'] );

                if ( 'all' !== $single[0] and 'lc' !== $single[0] ) {
                    if ( ! in_array( $this->page_prop['postid'], $single, true ) ) {
                        $result = 0;
                    }
                }
            }
            // ページidによりロードさせない指定がある場合
            if ( $this->ret_option['unload'] ) {
                $unloads = explode( ',', $this->ret_option['unload'] );

                if ( in_array( $this->page_prop['postid'], $unloads, true ) ) {
                    $result = 0;
                }
            }
        }
        return $result;
    }

    private function istax() {
        $result = 0;

        if ( '' !== $this->ret_option['onlytax'] ) {
            $terms = explode ( ',', $this->ret_option['onlytax'] );

            if ( 'all' === $terms[0] ) {
                $result = 1;
            } else {
                if ( in_array ( $this->page_prop['istax'], $terms, true ) ) {
                    $result = 1;
                }
            }
        }
        return $result;
    }

    //option設定により起動するページを選択する関数
	private function smplcprsm_load_direct() {
        $result = 0;

        if ( ! $this->page_prop ) {
            return $result;
        }

        if ( 'unboot' !== $this->ret_option['onlyhome'] ) {

            $no_limit = true;
            $op_elem = [ 'onlysingle', 'onlycate', 'onlytag', 'onlytax', 'directpage', 'directcustom', 'onlyhome' ];
    
            foreach ( $op_elem as $val ) {
                if ( '' !== $this->ret_option[ $val ] ) {
                    $no_limit = false;
                    break;
                }
            }
    
            if ( $no_limit ) {
                $result = 1;
            } else {

                $props = $this->page_prop;
                unset( $props['postid'] );

                $props = array_filter ( $props );

                // matchはphp8以降でしか使えない。
                // その場合は下のコメントアウトしてあるforeach が代替え、しかしmatch の方がより高速ではある
                if ( reset( $props ) ) {// 配列のポインタを先頭にセット、空ならfalseを返す

                    // 配列の先頭の要素のキーを取得し、そのキーで呼び出す関数を指定
                    $result = match( key( $props ) ) {
                        'isfront' => $this->isfront(),
                        'issingle' => $this->issingle(),
                        'ispage' => $this->ispage(),
                        'iscategory' => $this->iscategory(),
                        'istag' => $this->istag(),
                        'iscustompost' => $this->iscustompost(),
                        'istax' => $this->istax(),
                    };
                }

                // matchはphp8以降でしか使えないので、php7まではこちらで稼働
                /*foreach ( $props as $key => $val ) {// php では連想配列においてもその順番が保証されている
                    $result = $this->$key();// クラス内の関数を、$key の文字列で可変関数呼び出し
                    break;
                }*/
            }
        }
        return $result;
    }

    // ブラウザの言語設定から日本語表示か英語表示かを指定する関数
    private function lang_recognize() {
        $result = '';
    
        if ( isset ( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) {
            $langs = explode( ',', $_SERVER['HTTP_ACCEPT_LANGUAGE'] );
            $langs = array_reverse( $langs );

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

    // Crayon から乗り換えたなど、既存のpre タグを有効化するための関数
	public function apply_pre_tag( $content ) {
        // そのページにおいてロードするか判別する関数の結果
        $showscript = $this->smplcprsm_load_direct();
        $pattern = '';
        $goflg = false;

		if ( 1 === $showscript ) {
            if ( $this->pre_tag_ids ) {
                global $post;
                if ( in_array( $post->ID, $this->pre_tag_ids ) ) {
                    $goflg = true;
                }
            } else {
                $goflg = true;
            }

            if ( $goflg and false === strpos( $content, '<div class="highlighter_js' ) ) {
                $default_lang = $this->ret_option['replacement_lang'] ? $this->ret_option['replacement_lang'] : 'php' ;
                $content = str_replace( array( '</pre>', 'lang:default' ), array( '</code></pre></div>', 'lang:' . $default_lang ), $content );

                if ( '1' === $this->pre_tag_flg ) {
                    $pattern = '/<pre.*class="lang:(.*?)\s.*?>(\n|\r\n)*/';
                    $content = preg_replace( $pattern, '<div class="highlighter_js" data-name=""><pre class="line-numbers"><code class="language-' . "$1" . '">', $content );
                } elseif ( '2' === $this->pre_tag_flg ) {
                    $pattern = '/<pre.*?>(\n|\r\n)*/';
                    $content = preg_replace( $pattern, '<div class="highlighter_js" data-name=""><pre class="line-numbers"><code class="language-' . $default_lang . '">', $content );
                } elseif ( $this->pre_tag_flg ) {
                    $pattern = '/' . htmlspecialchars_decode ( $this->pre_tag_flg ) . '/';
                    $content = preg_replace( $pattern, '<div class="highlighter_js" data-name=""><pre class="line-numbers"><code class="language-' . "$1" . '">', $content );
                }
            }
        }

		return $content;
	}
}// ↑ class ここまで
}// if

$smplc_prism_highlighter_start = new smplc_prism_hilighter();

// ↓ 管理画面のメニューにオプション設定ページを登録する処理
add_action( 'admin_menu', array( $smplc_prism_highlighter_start, 'smplcprsm_add_menu' ) );
?>
PHP
CopyExpand

Sanbanse Funabashi
2011.01.01 sunrise

Top

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