PHP (WPテーマカスタマイザー) でCSSコードを組み立ててみた話

WordPressのテーマカスタマイザーで設定した内容を、HTMLではなく、CSSコードの組み立てに使用してみました。

その際の、CSSコードをPHPで処理するための知見をシェアしたいと思います。

なぜCSSコードをPHPで組み立てたのか

WordPressのブロックエディタでは、あらかじめ用意されたブロックを使用して「投稿」や「固定ページ」のコンテンツを作ります。

ブロックには、それぞれにスタイルが用意されていますが、全く使わないブロックのスタイルは全体のファイルサイズを増やすだけのデメリットしかありません。

また、よく使うブロックについても、オプションとして用意されているスタイルの中にも、全く使わないものがあります。

このような無駄なスタイルを増やさないためには、スタイルを設定するCSSコードそのものが選択できたらいいんじゃないかと考えたのが発端です。

CSSコードを選択するという手法

例えば、「warning (警告)」というclass属性値があるとします。このclass属性値が使用されたとき、どのようなCSSコードでスタイリングするかを選択できるようにします。

<p class="warning"> … </p>

文字色を変更したり、背景色を付けたり、境界線で囲んだり、更には、それらの色も指定できたらいいですよね。

/* 文字色を赤に設定する */
.warning {
  color: #ff0000;
}
/* 背景色を赤に設定する */
.warning {
  background: #ff0000;
  padding: 1em;
}
/* 赤い境界線を設定する */
.warning {
  border: solid thick #ff0000;
  padding: 1em;
}
/* 上記のCSSコードのうち1つを選択したい */

また「warning」そのものを使わないのであれば、CSSコード自体が生成されなくなると、更にいいですよね。

CSSコードを選択・生成するための下準備

WordPressのテーマカスタマイザーを使って、CSSコードを選択・生成する例を紹介します。

まずは、次のようなコードをfunctions.phpに追加します。

// テーマカスタマイザーに設定項目を追加する。
add_action( 'customize_register', function( $wp_customize ) {
  /*
  get_theme_mod( 'my_warning_type' )
  get_theme_mod( 'my_warning_color' )
  これらで取得できる項目を追加したとします。詳しい追加方法は
  https://codex.wordpress.org/Theme_Customization_API
  などをご覧ください。
  */
}, 10 );

// テーマカスタマイザーの保存時に生成したスタイルを保存する。
add_action( 'customize_save_after', function() {
  set_theme_mod( 'my_generate_style', my_generate_style() );
}, 10 );

// 生成したスタイルをインラインスタイルとして出力する。
add_action( 'wp_enqueue_scripts', function() {
  $my_generate_style = get_theme_mod( 'my_generate_style' );
  if( !empty( $my_generate_style ) ) {
    $handle = 'my-generate-style';
    wp_register_style( $handle, false, [] );
    wp_enqueue_style( $handle );
    wp_add_inline_style( $handle, $my_generate_style );
  }
}, 10 );

// テーマカスタマイザーの設定からスタイルを生成する関数。
function my_generate_style() {
  /* 後述 */
}

// 配列からCSSコードを生成する関数。
function my_array_to_css( $array ) {
  $output = '';
  if( !empty( $array ) && is_array( $array ) ) {
    foreach( $array as $key => $value ) {
      if( is_array( $value ) ) {
        $generated_value = my_array_to_css( $value );
        if( '' !== trim( "{$generated_value}" ) ) {
          $output .= $key. '{'. $generated_value. '}';
        }
      } elseif( '' !== trim( "{$value}" ) ) {
        $output .= $key. ':'. $value. ';';
      }
    } #endforeach
  }
  return $output;
}

CSSコードを配列として処理する

次に、スタイルを生成する関数 (my_generate_style) の内容ですが、CSSコードの部分的な上書き・結合・追加・削除が簡単に行えるよう、@mediaとその内容、セレクタとその内容、プロパティとその値、それぞれをキーと値にした、ツリー状の配列として処理します。

function my_generate_style() {
  $output = '';

  // 設定された「warning」のタイプを取得
  $warning_type = get_theme_mod( 'my_warning_type' );
  if( !empty( $warning_type ) ) {

    // 設定された「warning」の色を取得
    $warning_color = get_theme_mod( 'my_warning_color', '#800000' );

    // CSSコードの配列 (初期値は境界線の設定)
    $array = [
      '.warning' => [
	      'border' => "solid thick {$warning_color}",
	      'padding' => '1em',
      ],
    ];

    // CSSコードの上書き・結合・追加・削除
    if( '文字色を設定する' === $warning_type ) {
      // 上書き
      $array[ '.warning' ] = [
        'color' => $warning_color,
      ];
    } elseif( '境界線と文字色を設定する' === $warning_type ) {
      // 結合
      $array[ '.warning' ] = array_merge( $array[ '.warning' ], [
        'color' => $warning_color,
      ] );
    } elseif( '背景色を設定する' === $warning_type ) {
      // 追加
      $array[ '.warning' ][ 'background' ] = $warning_color;
      // 削除
      unset( $array[ '.warning' ][ 'border' ] );
    }

    // 「warning」のその他のスタイル
    $array[ '@media (min-width: 640px)' ][ '.warning' ] = [];

    // 配列からCSSコードを生成
    $output .= my_array_to_css( $array );
  }

  // その他のスタイル
  $array = [
    '.success' => [],
    '@media (min-width: 640px)' => [
      '.success' => [],
    ],
  ];
  $output .= my_array_to_css( $array );

  // その他のスタイル
  $array = [];
  $array[ '.failure' ] = [];
  $array[ '@media (min-width: 640px)' ][ '.failure' ] = [];
  $output .= my_array_to_css( $array );

  return $output;
}

これで、無駄のないCSSコードが生成されるようになります。

さすがに、全てのCSSコードをPHPで組み立てるのは現実的ではありませんが、ウェブサイト運営者が望むレイアウトや配色が選択できるようにしてみるといいかもしれません。

デザインをプログラミングする感じが好きです。

関連記事