Gutenbergの段落（core/paragraph）にデフォルトのクラス名をつけるために調べたこと

# 概要
段落などcoreブロックには基本的に初めからクラス名が付与されていないものが多くあります。
またクラス名が付与されているcoreブロックもwp-block-{name}の命名法に沿ったクラス名になっています。

例えばコーディングをする人とWordpressを組む人が別の場合で、かつコーディングする人がWordpressの法則にあまりそった命名規則でコーディングをした場合、WP側でそのクラス名を付与しなければいけません。
その場合は通常は、サイドパネルの　<b>高度な設定</b> > <b>追加cssクラス</b>から追加すればOKなのですが、人によっては忘れてしまったりするので、初めから追加できないか色々調べたことを記載します。


# GutenbergのBlock Filterでできないか調べたこと

## blocks.getBlockDefaultClassName
こちらのBlock Filterでcoreブロックにデフォルトのクラス名を追加できるという記事がありましたので、調べてみたところ、リストやcodeブロックなどは問題なく追加できたのですが、段落は追加ができませんでした。

そこで調べたところ

公式のGitHubのissueでこんな感じでの質問がありました。
https://github.com/WordPress/gutenberg/issues/16884

```
In the case of paragraphs, headings and images
we decided to opt-out of these classNames
because these blocks are too common
and we don't want to pollute the post-content with these.
↓翻訳
段落、見出し、画像の場合、これらのブロックはあまりにも一般的で、
ポストコンテンツをこれらで汚染したくないので、これらのクラス名をオプトアウトすることにしました。
```

とのことでこれらのcoreブロックはこのフィルターは使えないようです。

そこでその他のフィルターで使えないか調べてみました。

## blocks.getSaveElementとblocks.getSaveContent.extraProps

見出しの2つのフィルターが使えそうというのがわかりました。
そこで、まずはこれらのフィルターを使った場合どこまで影響があるのか以下のコードでチェックしてみました。

```react

import { addFilter } from '@wordpress/hooks';


const addClassName = (element, blockType, attributes) => {

    if (blockType.name === 'core/paragraph') {
        
        console.log(element.props);
    }
    return element;
};

addFilter(
    'blocks.getSaveElement',
    'efc-filter/addDefClassName',
    addClassName
);


```

そうするとエディタ部分のエレメントだけでなく、デフォルトのパターンやその他のものがずらずらとコンソールに表示されました。
あぁ、これは相当色々なところに影響を及ぼすなということがわかりました。

試しに**blocks.getSaveContent.extraProps**の方を使って以下のコードで無理やり段落にクラス名を追加するようにするとできることはできました。

```react
import { addFilter } from '@wordpress/hooks';

function addClassName(props, blockType/*, attributes*/) {
    if (blockType.name === 'core/paragraph') {
        if (typeof props.className !== "undefined") {
            if (props.className === '') {
                Object.assign(props, { className: 'my-text' });
            }
        }
    }
    return props;
}

addFilter(
    'blocks.getSaveContent.extraProps',
    'efc-filter/addDefClassName',
    addClassName
);
```

ただし、初めからあるパターンを追加すると「このブロックには、想定されないか無効な〜」と表示され「ブロックのリカバリーを試行」ボタンが表示されてしまいます。
（挿入直後は平気で、ページリロードで出たりします）

![スクリーンショット 2022-07-14 18.28.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34746/9f383017-c42f-ca10-67d3-8730f1d955b4.png)

公式のハンドブックをよく読むと以下の注意が書かれています。

```
[翻訳]
注意: このフィルタが既存のコンテンツを変更した場合、
次に投稿が編集されたときにブロックバリデーションエラーが発生します。
エディタは、投稿に保存されているコンテンツが 
save() 関数によって出力されたコンテンツと一致するかどうかを検証します。

この検証エラーを回避するには、このフィルタの代わりにサーバーサイドで
render_block を使用して既存の投稿内容を変更してください。
```

[公式ハンドブック　blocks.getSaveContent.extraProps　](https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/#blocks-getsavecontent-extraprops)

多分このためデフォルトのパターンや別の人が作ったパターンなどは挿入時もしくはその後のリロードでエラーになってしまうようです。

既存のパターンを使わないというのであればこの方法も良いかもしれませんが、他の箇所にもクラス名が追加されてしまうのは後々問題が出てくるかもしれません。

# render_block関数

上記のあったPHPによるサーバーサイドでの処理をする方法。
こちらは、PHPがレンダリングする際のフィルターフックとなります。

下記のように記述すれば基本的に簡単に追加することができます。

```php
//functions.phpなどに記述
function wporg_block_wrapper( $block_content, $block ) {
     //追加するクラス名
     $addClassName = 'my-text';

     //段落のみに追加する
     if ( $block['blockName'] === 'core/paragraph' ) {
          preg_match('/<([a-z])+(\sclass=[\'\"](.*)[\'\"])?>(.*)<\/[a-z]+>/',$block_content,$matches);
          $className = '';
          if($matches[3] !== '') {
               $className = $matches[3] . ' ' . $addClassName;
          } else {
               $className = $addClassName;
          }

          $content = '<' . $matches[1] . ' class="' . $className . '">' . $matches[4] . '</' . $matches[1] . '>';

          return $content;
     }

     return $block_content;
    
}
if(!is_admin()) {
     add_filter( 'render_block', 'wporg_block_wrapper', 10, 2 );
}
```

PHP出力する時に追加するので、データベースには任意クラス名が付加された状態では保存されないのですが、その他のデータを汚染することもないです。

また、投稿ごとやカテゴリーごとや投稿タイプごとに同じブロックでも違うクラス名を追記するなどもこちらの方法では簡単にできると思います。