Gutenberg(ブロックエディタ)メモ: 自動でテーマCSSの指定箇所をGutenberg用CSSとして用いる方法の検討

WordPressのGutenberg
WordPressのGutenberg

Gutenbeg自体が追加するCSSもありますが、自作したパーツのCSSはテーマとエディタ用の2つを用意する必要があります。

この点は旧エディタのビジュアルエディタでも同じではあるのですが、Gutenbergの特徴からCSSを反映させる必要度が上がったように思えましたので、少しでも楽にできないかと方法を検討しました。

実現したいこと

  • テーマ用のCSSの任意の範囲を、自動でGutenberのエディタ用CSSとして抜き出して使う
  • 箇所を複数設定しても対応可能

ローカルでCSSファイルを分割作成してから統合するなどの方法が一般的なのかもしれませんが、今回はサーバー側でテーマ用CSSの更新に合わせて自動作成する方法となります。

結構無理矢理で実用に足るかは微妙なため、見ても参考程度にお願いします。

前提など

  1. テーマのCSS(style.css)内で、エディタ画面で必要な指定をまとめておく
  2. テーマ内のCSSフォルダにeditor-style.cssとしてGutenberg用のCSSファイルを作っておく
  3. テーマのCSS内に指定開始位置と終了位置を判別するための文字列(コメント文)を追加する

既に面倒さを感じますが、前提と準備は上記の通りです。

ファイル名などは任意で変更可能ですが、今回は3の「指定開始位置と終了位置を判別するための文字列」を以下のように設定します。


/***for-guten-start***/

/* この間が抽出対象  */

/***for-guten-end***/

CSSのコメントを利用しているのでスラッシュとアスタリスクは必須になりますが、正規表現を使う場合にはこれらをエスケープしなければなりません。他の記号を使う場合も同様にエスケープが必要な場合があります。

クラスやIDの削除や置換に関する必要性の有無

上記の記事で知りましたが、WP5.0.2現在で以下のようになっています。

これまでのエディタでスタイルを適用させたい場合、CSSのセレクタの頭に#tinymceとか.mce-content-bodyを付けて指定していた方も多いと思いますが、Gutenbergの場合はそれらが基本的に不要になり、記述されたセレクタの頭に.editor-styles-wrapperというclassが自動で付与、またはbodyが記述されていたら.editor-styles-wrapperに置換して出力されるようになっています。

この仕組みのおかげでIDやクラス名を置換や削除する必要性がなくなったかと思ったのですが、以下の問題があるため置換と削除の機能は残しています。

  • .post h2のように任意のクラス指定は、削除や置換がされない(.editor-styles-wrapper .post h2のようになる?)
  • .single h2やカテゴリースラッグを使うようなページに対して自動で付与されるタイプのクラスは、投稿画面内では対応できない

ユーザー側が独自で追加したクラスをWP側が勝手に削除するわけにもいきませんから、上記は構造的に仕方がない部分となります。

サンプルコード


//初期設定
add_action( 'enqueue_block_editor_assets', function() {

  wp_enqueue_script(
    'myplugin-gutenberge',
    plugins_url( 'block.js', __FILE__ ),
    [ 'wp-blocks', 'wp-element', 'wp-components', 'wp-editor']
  );

  //cssの読み込み
  wp_enqueue_style(
    'editor-style',
    get_stylesheet_directory_uri() . '/css/editor-style.css',
    [],
    false
  );

} );

//今回作成する仕組みを動作させる
//指定したフックのタイミングで、Gutenberg用CSSの作成を行わせる
//CSSの読み込みや出力自体は前項のwp_enqueue_styleで行う
add_action( 'get_header','my_css_add_gutenberg');

まずGutenberg用の基本設定として上記のように記載します。今回はGutenberg自体が対象ではないのでwp_enqueue_scriptで読み込ませているGutenberg用のコンポーネントは適当に書いています。

wp_enqueue_scriptsよりも前に動作させられればよいので、get_headerのフックを使っています。

ファイルの日付取得処理を毎回走らせるのが問題になる場合は、admin_initなどを使い管理画面各ページがレンダリングされる前に毎回実行させるなど管理画面側のフックを使う方法も検討できます。

このようにアクションを任意のタイミングに変えたい場合は別のフックで実行してください。


function my_css_add_gutenberg(){

  //テーマのCSSファイルの場所を指定
  $origin_file  = get_stylesheet_directory() . '/style.css';
  //GutenbergのCSSファイルの場所を指定
  $guten_file   = get_stylesheet_directory() . '/css/editor-style.css';
  //抽出開始位置指定用文字列(正規表現のためいろいろエスケープ)
  $start        = '\/\*\*\*for-guten-start\*\*\*\/';
  //抽出終了位置指定用文字列(正規表現のためいろいろエスケープ)
  $end          = '\/\*\*\*for-guten-end\*\*\*\/';
  //置換用設定
  $list_replace = array(
    //置換後 => 置換対象 の形で記述
   '.edit-post-visual-editor.editor-styles-wrapper' => array('.post','.page','#main'),
   '[class="wp-block-"]' => array('.page','.single')
  );
  //削除用設定 あっては困るクラスやIDを削除する
  $list_delete  = array('.home','.archive');

  //cssの中身を入れる変数
  $css  = '';
  //Gutenbergのエディタ用CSSファイルの中身を上書きするかどうかの判断に用いるフラグ
  $flag = false;

  //テーマとGutenberg用のCSSのファイルの日付を比較し、Gutenbergの方が新しい場合にフラグを立てる
  //テーマのCSSファイルの日付を取得
  $origin_file_date = filemtime($origin_file);
  //gutenbergのファイルの日付を取得
  $guten_file_date  = filemtime($guten_file);
  if($guten_file_date < $origin_file_date){
    //テーマのCSSファイルの方がgutenberg用のCSSファイルよりも新しい場合
    $flag = true;
  }

  //オリジナルの方がGutenberg用CSSよりも新しい場合に処理を開始
  if($flag){
    //ファイルの内容取得や書き込みにWP_Filesystemオブジェクトを使うため、準備として必要なファイルを読み込み
    require_once(ABSPATH . 'wp-admin/includes/file.php');
    if( WP_Filesystem() ){
      //$wp_Filesystemオブジェクトの呼び出し
      global $wp_filesystem;

      //CSSの中身を取得
      $css = $wp_filesystem->get_contents($origin_file);
      //抽出用パターン設定
      $pattern = '/' . $start . '(.*?)' . $end .'/us';
      //CSSから指定記述を探して抽出
      preg_match_all($pattern, $css, $matches);
      //抽出できていれば半角スペースで結合して文字列にし。抽出できていなければ中断
      if(!empty($matches[0])){
        $str = implode(" ", $matches[1]);
      } else {
        return;
      }

      //削除設定どうりに削除
      foreach ($list_delete as $value) {
        $str = str_replace($value, '', $str);
      }
      //置換設定通どうりに置換
      foreach ($list_replace as $key => $values) {
        foreach ($values as $value) {
          $str = str_replace($value, $key, $str);
        }
      }

      //念のため削除後にできる可能性がある半角スペース2つを1つにする
      $str = preg_replace('/\s+/', ' ', $str);
      //文字コードを設定
      $str = '@charset "UTF-8";' . $str;

      //グテンベルグ用ファイルに書出し
      $wp_filesystem->put_contents($guten_file, $str);

    }
  }

}

初期設定

上記の内の下記が初期設定箇所です。


//テーマのCSSファイルの場所を指定
$origin_file  = get_stylesheet_directory() . '/style.css';
//オリジナルとGutenbergを合わせてminifyした後のcss
$guten_file   = get_stylesheet_directory() . '/css/editor-style.css';
//抽出開始位置指定用文字列(正規表現のためいろいろエスケープ)
$start        = '\/\*\*\*for-guten-start\*\*\*\/';
//抽出終了位置指定用文字列(正規表現のためいろいろエスケープ)
$end          = '\/\*\*\*for-guten-end\*\*\*\/';
//置換用設定
$list_replace = array(
//置換後 => 置換対象 の形で記述
 '.edit-post-visual-editor.editor-styles-wrapper' => array('.post','#main'),
 '[class="wp-block-"]' => array('.page','.single')
);
//削除用設定 あっては困るクラスやIDを削除する
$list_delete  = array('.home','.archive');

基本的には「置換でクラスやIDを書き換えたり削除する」という動作なので、置換後のクラスやID名は.edit-post-visual-editor.editor-styles-wrapperのように指定します。

無理矢理な感じですが配列にしているので、置換対象が増える場合はサンプルの[class="wp-block-"]のように追加することで対応可能です。

削除用は単純な配列なので追加していけばよいですが、場合によっては無害と思われるクラス名にして影響を避けるという手段も視野に入るかもしれません。
CSSにゴミを作る行為なので推奨し難いところではありますが、今回の方法では融通が効きにくい部分もあるため回避措置としてはありかなと…。

結び

試してできたという程度なので荒いですが、テーマのCSSの変更を自動で反映する仕組みとして形にしてみました。

Gutenbergは未だ固まっていないようですし、今までが今までなので今後もどう変更されるのか(あるいは変更されないのか)分かりません。
また、テーマのCSSにしても追加や変更があるでしょう。

これらの点を考えると柔軟に書換え対象を変更できる形にした方がよいかとこの形にした次第です。

投稿画面を開かないと更新されないなど不便はありますが、動作開始の部分はまた別に状況に合わせて変更すればよいだけなので、とりあえずこの状態で試作は終えたいと思います。

関連記事

Gutenberg(ブロックエディタ)に関連する記事一覧。

0人がこの記事を評価

役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。

連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。

コメント欄