MB blog

こちらは主に自分用のメモです。

RankMath Breadcrumbs (パンくずリスト)の区切りに Divi アイコンを使う

2021年時点で最強の無料 Wordpress SEO プラグインであるところの RankMath。
wordpress.org

Breadcrumbs 機能を使うと、カスタマイズ性の高いパンくずリストを作ってショートコードで入れられます。
区切り記号であるセパレーターのチョイスがデフォルトだとイマイチ。

このデフォルトチョイスではなく、セパレータにDivi のアイコン群を使う方法です。

1. RankMath のカスタムセパレータに、Unicode を入れる

The Elegant Icon Font – 360 Of The Best Free Icons For The Modern Web | Elegant Themes Blog

上記ページのガイドを参考に、使いたい Divi アイコンに対応するユニコードを調べ、カスタムセパレータの欄に記入します。
今回はこちらの [5] をピックアップ。

f:id:lake_michigan:20210225113958p:plain

2. CSS をセットしてアイコンとして読み込ませる

以下のフォントファミリーをあててあげることで、上記のユニコードがアイコンとして読み込まれます。

.rank-math-breadcrumb .separator {
	font-family: 'ETmodules';
}

Divi のコードモジュールだけではリンクの色やフォントサイズなど細かなスタイルができないので、.rank-math-breadcrumb もここで装飾してあげれば完璧。

f:id:lake_michigan:20210225121020p:plain

完成!

Contact Form 7 Multi-Step Forms で、前のフォームからの入力値に応じて条件分岐をする

Contact Form7 って、いろんな組み合わせプラグインがあってカスタマイズ性が高く、めっちゃ便利ですね。

ページを分割して長いフォームを作ることができる Contact Form Multi-Step Forms。
ja.wordpress.org

ユーザーの入力値に応じて、質問項目の出し分け(条件分岐)ができる Contact Form Conditional Fields 。
ja.wordpress.org

どちらもすごく便利なプラグインですが、両者を組み合わせても、前のフォームの入力値に応じて条件分岐をすることはできません。
Conditional Fields は、同じページのフォーム内の入力値からしか条件を引っ張れないためです。

そこで、Multi-Step で作った前ページのフォームから値をとって、それを元に質問項目を出し分ける JavaScript を書きました。
1ページ目のフォーム内の "prefecture" というフォームへの入力内容が「岐阜」だった場合のみ、次のページでのフォームで「美濃」「飛騨」を選ばせるラジオボタンを出す、というサンプルです。


以下は Contact Form 7 の2つ目のフォームに記載しておく内容。Multi-step プラグインで用意される [multiform] で前フォームの回答内容を取得できますが、値を使うだけなので非表示にしておきます。

<label id="prefecture" class="hide">[multiform "prefecture"]</label>
<div id="area" class="none">
地域を選んでください
  [radio area use_label_element "飛騨地方" "美濃地方"]
</div>

上記にあてる CSS はこちら。[multiform] は値を使うので隠すだけの visibility: hidden とし、div は条件に該当しない限り使わないので display: none で存在を消しておきます。

.hide {
  visibility:hidden;
}

.none {
  display: none;
}

そして、こちらの js を body 下部に挿入。prefecture が岐阜の時のみ、ラジオボタンのエリアを display: block に上書きしています。

  prefecture = document.getElementById("prefecture").textContent;
  var elem;
  if ( prefecture == "岐阜" ) {
    elem = document.getElementById("area");
    elem.style.display ="block";
  }

ACF Pro のギャラリーフィールドの画像から、すべての記事に自動で注目画像を設定する

Advanced Custom Fields の有料版 ACF Pro についてくる、Gallery というフィールドタイプ。画像の数を設定せずに無制限に追加でき、画像をたくさん設定させたい投稿タイプに便利な機能。
このギャラリー内の画像から、自動的に投稿のサムネイル(注目画像)を設定したいと考えました。
投稿内の画像から最初のものをとってきて注目画像に自動設定するためには、XO Featured Image Tools という素晴らしいプラグインがあります(日本人の方が開発されています)。
ja.wordpress.org
しかし、上記は ACF に対応していません。

そこで、以下のコード functions.php に追加することで、ギャラリー内の最初の画像を注目画像に登録するようにできました。

/* 投稿が保存されたときに、以下の function が発動するよう登録 */
add_filter('acf/save_post', 'gallery_to_thumbnail',11,11);
/* ギャラリーの最初の画像を取得して、記事のサムネイル画像にセットする */
function gallery_to_thumbnail ($post_id) {
	$gallery = get_field('ギャラリーフィールドの名前', $post_id, false);
	var_dump($gallery);
	var_dump($post_id);
if ($gallery) {
	$image_id = $gallery[0];
	set_post_thumbnail($post_id, $image_id);
  }
}

Google 広告で広告カスタマイザを使うときのちょっとした注意点

広告カスタマイザとは

「ネット広告運用“打ち手”大全」という本を読んでいて、「広告カスタマイザ」という機能を知った。

余談ですがこの本は神です。Google と Fb 広告の両方を押さえていて、しかもここ数年グッと進化した機械学習ベースの運用方法(ちょっと古い本だと手動運用が前提なので...)にも言及されている。入門書・基本書を押さえたけど運用者として次なるステージに進みたい方は必読!

広告カスタマイザとは、検索したユーザの位置情報時間、そして検索キーワードに応じて広告の文言をカスタマイズする機能のこと。
広告カスタマイザで利用する要素には、「データフィード」と「広告」がある。

データフィード

どの条件(Target location, Target keyword など)においてどんな文言(文字列、整数、価格などのデータ型で自由に設定)を発動させるか、というマッピングを記述したファイル。csv でビジネスデータとしてインポートするよ。

広告

通常のGoogle広告でいう「広告」。広告見出しや説明文の中から、独自構文を使ってデータフィードを呼び出して、広告文を作ります。

早速使ってみましたが、いくつか想定外のことが途中であって手戻りが発生してしまいました。構成を考える前に押さえておきたいTips。

広告カスタマイザを使う前に留意しておくべき点

1. 広告カスタマイザへのデータフィードが承認されるまで時間がかかる

数十件のデータが入ったフィードの審査が終わるまで、1-2時間かかってしまいました。
よーし広告作るぞー!と思ってからデータフィードを用意してたら、実際の広告文を作るところで待ちが発生するので、早めにフィードをアップしておこう。

2. 同じ広告グループの中に、1つは広告カスタマイザを全く使わない広告が必要

カスタマイザが何らかの原因で動かないような時に表示するものがないと困るので、そのためでしょうね。
これは、レスポンシブ広告でもOK。

3. ひとつ広告からは1つのデータフィードしか参照できない

例えば、「位置情報を条件に都市名をトリガしたい」と「検索ワードを条件に製品名をトリガしたい」という2つの要件があったとする。
データを正規化することに慣れている情報系の人なら、それぞれを別の csv ファイルにして独立したフィードとして登録するのが自然でしょう。
でも、これをしてしまうと、両方のカスタマイズを1つの広告に取り入れることができないのです...!これは想定外でした。
なので、csv が空セルだらけで汚くなっても、無理やり全部のカラムを1ファイルにまとめて、単一のフィードとして登録する必要があるというわけ。

4. レスポンシブ広告からは広告カスタマイザは使えない(2020年3月現在)

基本的に自分の広告文組み合わせを信じていなくて、レスポンシブ広告に全幅の信頼を寄せているので、これは地味に辛い。
いつか呼び出せるようになったらいいなぁ。すごく CTR 上がりそう。

5. フィードデータはあとから追加アップロード出来ない

同じ名前のフィードに対して CSV を上書き・追記でアップロードすることは出来ません。
なのでよくよく考慮してデータの漏れがないようにすること。
定期的に追加があるのであれば、スケジューラを使って Google Docs で同期させるのが良いですね。

まとめ

上記を考慮した上で構成を考えましょう。とても便利です。

以下、参照。
support.google.com

Divi サイトを ConoHa Wing に移行したらページ保存できなくなった

Divi サイトを ConoHa Wing に移行

爆速という噂を聞いて ConoHa Wing を契約してみて、ロリポップサーバにあった Divi の Wordpress サイトを移行してみました。移行には下記同様、信頼の All in One Migration を使いました。

lake-michigan.hatenablog.com

ConoHa Wing へのインポート時にアップロードファイル上限などが引っかかりましたが、php.ini 上でインポートファイルを超える値まで十分に引き上げたら大丈夫でした。

(無料のエクステンションは  512MB までしか対応していないので、今回は使っていません)

 

ページ編集後、保存時にエラーが発生

移行後に固定ページを編集して、いざ保存しようとすると、見慣れないエラーが。

保存に失敗しました

 

divi エラー 保存


ここに書かれている対策は全て実行しても、やはり保存できず。

素の Wordpress の機能だけを使って編集した時は問題ないのですが、ページビルダーを使って編集したときは、どのページも同じ状態になってしまいました。

 

原因は、ConoHa の WAF が特定のファイルをブロックしていたこと

デベロッパーツールの Console を開きながら「保存」をしようとすると、403 エラーが出ていることがわかりました。

Failed to load resource: the server responded with a status of 403()

このようにファイアウォールに操作を邪魔されることが、 Divi のみならずページビルダーではよくあることのようです。

特に SiteGuard や、WordFence という WAF は Divi と相性が悪くて嫌われているみたいです。

ConoHa Wing では、サーバーサイドでですが SiteGuard が使われています。

ConoHa Wing の WAF でブロックされたファイルの除外設定

 ConoHa Wing の「サイト管理」から、「サイトセキュリティ」>「WAF」ページの下部に、攻撃としていくつかログが記載されています。

IP や日時を確認し、Divi を操作していた時のアクションだと確認できたら、左の「除外」ボタンをクリック。以降、同様のアクションはクリックされなくなります。

conoha wing WAF 除外

 

これ一回で済めば良いんですが、Divi でいろんな操作をしていると、いろんな理由でアクションがブロックされることがあります。その時は、都度この操作で除外をコツコツ繰り返す必要がありました。

 

また、WAF の設定はサーバ単位ではなく、サイト単位で都度行う必要があります。

Python 設定ファイルから値の読み込み(ConfigParser)

Python の ConfigParser とは

Python プログラムからプロパティファイルから値を読み込むのに、ConfigParser という標準モジュールを使うことで、めちゃ簡単に値の取得ができます。
8年前(!)書いた記事(Pythonで設定ファイルから値の読み込み (ConfigParser) - MB blog)の内容が古いので、Python 3.7 で書き直します。

設定ファイル setting.conf 準備

ちなみにファイル名を .conf 形式にすると、VSCode が自動的に設定ファイルだと読み取ってくれます。

[dest_id]
kyoto = 434312
tokyo = 346350
osaka = 2783622
takayama = 1905523
kanazawa = 2658464

コード

dest_id セクションのキーと値を全て出力するサンプルは以下の通り。

import configparser
conf = configparser.ConfigParser()
conf.read('/Users/hogehoge/Documents/hogehoge/setting.conf')
section = 'dest_id'
for key in conf.options(section):
  print (key, conf.get(section, key())

ConfigParser() は get(セクション名, オプション名) のほかにも、has_section や has_option 、また書き込みのための関数も用意されています。

Python の Null チェック

Python の NoneType


Java などでは戻り値が空だった時、

str != null

のようにして Null チェックを行います。
一方で静的型付け言語である Python は、戻り値を受け取る時にも型を指定しないので、ある関数を呼んで戻りの値が空だった時は NoneType という型を返します。

NoneType どうかの判定方法

前述のどのデータ型であっても、以下のやりかたで None であるかどうかの判定をすることができます。

if obj is None:
  print("None")

Python のコード規約的には if obj == None: とは書かず、None 判定には is を使うようです。

型はあるけど値が入ってない、の判定方法

NoneType 型ではないけれど、値が入ってないということもあります。
str の "" をはじめとして、整数の0、浮動小数の 0.0、bool の False、あらゆるコレクション型(リスト、タプル、ディクショナリ、セット)の中身が空、などなど。
例えばコレクションだと、他の言語だと list の length をとってそれが 0 以上かどうか... みたいなことをすると思うのですが、Python はシンプル。
if になんの演算子もつけなければ、その変数に何かしらの値が入っているときに True 、そうじゃないときに Falseを戻します。

if obj:
  print ("Not null")

この省略形、はじめは気持ち悪いけど、コードも短くなり結構合理的。
否定バージョン。

if not obj:
  print ("Null")