ACFのセレクトフィールドテスト

ACF用のcalculated-fields-for-acf-kaiでの「条件演算子」で疑似的な条件分岐をおこなう下調べを研究(GTP


ポイント:

  • calculated-fields-for-acf-kaiのFormulaフィールドに数値以外の値を入れた場合、その値はすべて数値の0.0として扱われる。
  • これによりPHP8での非数値演算エラーは発生しない。

calculated-fields-for-acf-kai:オリジナルのエラー

  • エラーは、PHP 8.0以降の型チェック強化が原因で、古いプラグイン(calculated-fields-for-acf)が未対応の記述をしているために発生
  • 数値(float)と文字列(string)を掛け算しようとした
    • PHP 7 までは、 ‘5’ * 2 のような処理は自動的に数値変換
      >$val = “abc” * 2; // 0 になる(警告すら出ない場合も)
    • PHP 8以降では「数値に変換できない文字列を演算に使うと致命的エラー」
      >$val = “abc” * 2; // 警告: A non-numeric value encountered
  • 重要:PHP 8以降は「演算子を使うすべての数値演算」で、非数値が混ざるとエラー(または警告)になる。

calculated-fields-for-acf-kai:コードの修正

  • EvalMath.phpテンプレートを修正する
  • オリジナル:$op1 または $op2 のどちらか、または両方が 数値以外(例:”abc”や空文字) になっている状態で掛け算が実行=結果/float * string という不正演算>エラーの原因
  • 修正:演算前に、数値でない場合は強制的に数値にキャスト(連携)する処理を加える
    • 演算の前に $op1 と $op2 を強制的に (float) キャストする
    • $op1 や $op2 が ‘abc’ のような文字列や空白だった場合 (float) によって自動的に 0.0 と変更する
  • 0ではなく、0.0にする理由はGTPを参照する

EvalMath.php:コードの修正点

オリジナルコード

foreach ($tokens as $token) { // nice and easy
// if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
if (in_array($token, ['+', '-', '*', '/', '^', '%', '==', '!=', '>', '<', '>=', '<='])) {
if (is_null($op2 = $stack->pop())) {
return $this->trigger("internal error");
}
if (is_null($op1 = $stack->pop())) {
return $this->trigger("internal error");
}
// ここから下の箇所がエラー原因:非数値を式に入れて計算実行が可能
switch ($token) {
case '+':
$stack->push($op1+$op2); break;
case '-':
$stack->push($op1-$op2); break;
case '*':
$stack->push($op1*$op2); break;
case '/':
if ($op2 == 0) {
return $this->trigger("division by zero");
}
$stack->push($op1/$op2); break;
case '^':
$stack->push(pow($op1, $op2)); break;
case '%':
$stack->push($op1%$op2); break;
case '==':
$stack->push($op1 == $op2 ? 1 : 0); break;
case '!=':
$stack->push($op1 != $op2 ? 1 : 0); break;
case '>':
$stack->push($op1 > $op2 ? 1 : 0); break;
case '<':
$stack->push($op1 < $op2 ? 1 : 0); break;
case '>=':
$stack->push($op1 >= $op2 ? 1 : 0); break;
case '<=':
$stack->push($op1 <= $op2 ? 1 : 0); break;
}

修正コード

foreach ($tokens as $token) { // nice and easy
// if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
if (in_array($token, ['+', '-', '*', '/', '^', '%', '==', '!=', '>', '<', '>=', '<='])) {
if (is_null($op2 = $stack->pop())) {
return $this->trigger("internal error");
}
if (is_null($op1 = $stack->pop())) {
return $this->trigger("internal error");
}
// 修正:非数値や空白がある場合、強制的に数値(float)(=0.0)に置き換える
// この処理により、PHP8の要件である「数値以外(例:”文字列”や空文字)での計算(=四則演算、剰余、累乗=すべての計算)」を回避する
switch ($token) {
case '+':
$stack->push((float)$op1 + (float)$op2);
break;
case '-':
$stack->push((float)$op1 - (float)$op2);
break;
case '*':
$stack->push((float)$op1 * (float)$op2);
break;
case '/':
if ((float)$op2 == 0) {
return $this->trigger("division by zero");
}
$stack->push((float)$op1 / (float)$op2);
break;
case '^':
$stack->push(pow((float)$op1, (float)$op2));
break;
case '%':
$stack->push(fmod((float)$op1, (float)$op2));
break;
case '==':
$stack->push(((float)$op1 == (float)$op2) ? 1 : 0);
break;
case '!=':
$stack->push(((float)$op1 != (float)$op2) ? 1 : 0);
break;
case '>':
$stack->push(((float)$op1 > (float)$op2) ? 1 : 0);
break;
case '<':
$stack->push(((float)$op1 < (float)$op2) ? 1 : 0);
break;
case '>=':
$stack->push(((float)$op1 >= (float)$op2) ? 1 : 0);
break;
case '<=':
$stack->push(((float)$op1 <= (float)$op2) ? 1 : 0);
break;
}
// 修正ここまで

 


  • ★戻り値の形式=ラベル
    値/ラベル/両方 (配列)
    戻り値を指定します
  • ラジオボタンなど(単一選択):
    • Value:値(例:「red」)が文字列で返されます。?
    • Label:ラベル(例:「赤」)が文字列で返されます。?
    • 値 : ラベル
  • ★初期値
    • 選択肢を表示する「Select」フィールドでは、「デフォルト値」設定で初期選択肢を選びます。

calculated-fields-for-acf-kaiを使った計算の事例

動作確認はこの固定ページの編集からおこなう(ACFのセレクトNEW)

名前を選択したら確認*(check01)の値が1、選択しない場合()は値が0

支払額の計算式でcheck01が0であると結果が0になる※支給先を未指定は計算外とする


【仲介手数料総額】sougaku番号:900
【名前を選択】onamae01選択:- 名前選択 -/値=- 名前選択 -/ラベル=onamae01(戻り値=値)
【割合を入力】wariai01番号:10(user_select)※以下、0=false、1=true
【確認*】check01番号:0(onamae01 < 1)Read only
【支払額】shokei_01番号:0(round(check01 * sougaku * 0.1 * wariai01 / 100))