かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

PugでPHPタグを出力したい

pugはHTMLテンプレートエンジンなのですが gulp などで拡張子をリネームしてしまえば PHPのテンプレートファイルにする事もできます。
ex:

var gulp    = require("gulp"),
    plumber = require("gulp-plumber"),
    rename  = require('gulp-rename'),
    pug     = require("gulp-pug");

gulp.task('pug', function(cb) {
  let options = {
        pretty: true
      };
  return gulp.src( files )
    .pipe( plumber() )
    .pipe( pug(options) )
    .pipe( rename({
      extname: '.php'
    }) )
    .pipe( gulp.dest( destPath ) );
});

こんな時にpugで生成するファイルにPHPタグを出力する方法のメモ。

pugの機能であるHTMLタグなどをエスケープしない Plain Text を利用するとPHPタグを出力することができます。(エスケープされないので、この方法を使うとPHPタグに限らず<script>タグなども出力できます。)

Plain Text
Pug provides four ways of getting plain text
...
And because plain text is not escaped, you can also include literal HTML.
出典: Plain Text – Pug

HTMLのタグ内にPHPを出力する

1行で出力する時はタグの後スペースを置き直接 PHPタグを書く ( Inline in a Tag )

// pug
div <?php the_content(); ?>

// コンパイル後
<div><?php the_content(); ?></div>

 
複数行で出力する場合

1. タグ名 の後に .を置き改行&インデントしてPHPを書く ( Block in a Tag )
// pug
div.
  <?php
    $id = get_the_ID();
    echo get_the_title( $id );
  ?>

// コンパイル後
<div><?php
  $id = get_the_ID();
  echo get_the_title( $id );
?></div>
2. タグ名を書き改行・インデントして行毎に | +スペースに続けてPHPを書く ( Inline in a Tag )
// pug
div
  | <?php
  |   $id = get_the_ID();
  |   echo get_the_title( $id );
  | ?>

// コンパイル後
<div><?php
  $id = get_the_ID();
  echo get_the_title( $id );
?></div>

hrefaltなどの属性の値にPHPを出力する

pugの属性の値はエスケープされるので Inline in a Tag のように書いても上手くコンパイルされません。

// pug
p(href="<?php the_permalink(); ?>") Link Text

// コンパイル後  < > がエスケープされてしまう
<a href="&lt;?php the_permalink(); ?&gt;">Link Text</a> 
!= を使うと属性にPHPタグが出力できる

Using != disables HTML-encoding in attributes.
出典: node.js - Jade: Why && is compiled to &amp; when used in angularjs in Jade template? - Stack Overflow

属性の場合、pugの変数を属性に設定する時と同じように != の後にスペースを開けて"の括った中に出力したいPHPタグを書けばOK。PHPタグを " で囲うことでタグを含む文字列としてそのまま出力させることができます。

// pug
a(href!= "<?php the_permalink(); ?>") Link Text

// コンパイル後
<a href="<?php the_permalink(); ?>">Link Text</a>

HTMLタグ外に直接PHPタグを出力する

PHPファイルの先頭のコメントなど、HTMLタグの外にPHPタグを出力させる方法。
複数行で出力する場合と同じ方法を、先頭にHTMLタグ名無しでも使用することができるようです。

1. . の後に改行したインデント内に記述する方法 ( Block in a Tag )
// pug
.
  <?php
    /**
     * hoge
     */
  ?>

// コンパイル後
<?php
  /**
   * hoge
   */
?>
2. | + スペースで記述する方法 ( Piped Text )
// pug
| <?php
|   /**
|    * fuga
|    */
| ?>

// コンパイル後
<?php
  /**
   * fuga
   */
?>
3. < で始まるタグはプレーンテキストとして解釈される事を利用する ( Literal HTML )

Literal HTML
Whole lines are also treated as plain text when they begin with a left angle bracket (<), ...
出典: Plain Text – Pug

pugは < から始まる行をプレーンテキストとして出力するので、PHPの開始タグに関してはこの方法を利用することができます。

//pug
<?php
.
   /**
    * Mofu
    */
  ?>

// コンパイル後
<?php /**
  * Mofu
  */
?>
//pug
<?php
  |
  | /**
  |  * Bar
  |  */
  | ?>

// コンパイル後
<?php
/**
 * Bar
 */
?>

先頭の <?php だけ Literal HTML で出力し、あとの部分は . block か | を使う必要があるので、全部 . block か | で書いてしまった方が簡単だと思いますが...  

まとめ

pugでPHPタグやhtmlタグを直接出力する時は

  • HTMLタグ内/外 の場合は
    1. . の後に改行しインデントしてタグをそのまま記述する
    2. | に続けて出力するタグをそのまま記述
  • 属性の値として出力する時は != "<?php 出力するコード ?>" の形式で記述

と覚えておけば良さそうです!


[参考]

Pug 変数を返すMixinをつくりたい。


HTMLプリコンパイラのpugを使っていて、引数から計算をして値を返すMixinを作ろうとした所

mixin getCalendarRow(dayNum, start)
  return Math.ceil( (dayNum + start - 1) / 7 );

// 呼び出し側
div(class="row"+ +getMonthRow(30, 6))

👇 次のようなエラーになってしまいました。

Plumber found unhandled error:
 TypeError in plugin 'gulp-pug'
 getCalendarRow is not a function

どうやら、pugのmixinはHTMLとかblockを出力するものでないと、mixinを呼び出した際にエラーになってしまうっぽいです...

function にしてしまえば、変数を返すmixinが作れる!

mixinキーワードでなく-の後に改行とインデントをしてfunctionとして作成すると変数を返すmixinが作成することができるみたいです!!

-
  function getCalendarRow(dayNum, start) {
    return Math.ceil( (dayNum + start - 1) / 7 );
  }

// 呼び出し側 呼び出しは通常の mixin と同じ
div(class="row"+ +getMonthRow(30, 6))

👇 出力

<div class="row5"></div>

(๑˃̵ᴗ˂̵)و ハッピー!

関数を作成する時に - を書いて改行&インデントをするのがポイントです。
- の後にインデントした範囲は普通のjavascriptとして認識されるのかもです。


[参考]

PHP A~Zを簡単に出力したい。

range() 関数を使う

range
range — ある範囲の整数を有する配列を作成する

array range ( mixed $start , mixed $end [, number $step = 1 ] )

<?php
$list = range('A', 'Z');

👇

array(26) {
  [0]=> string(1) "A"
  [1]=> string(1) "B"
  [2]=> string(1) "C"
  [3]=> string(1) "D"
  [4]=> string(1) "E"
  [5]=> string(1) "F"
  [6]=> string(1) "G"
  [7]=> string(1) "H"
  [8]=> string(1) "I"
  [9]=> string(1) "J"
  [10]=> string(1) "K"
  [11]=> string(1) "L"
  [12]=> string(1) "M"
  [13]=> string(1) "N"
  [14]=> string(1) "O"
  [15]=> string(1) "P"
  [16]=> string(1) "Q"
  [17]=> string(1) "R"
  [18]=> string(1) "S"
  [19]=> string(1) "T"
  [20]=> string(1) "U"
  [21]=> string(1) "V"
  [22]=> string(1) "W"
  [23]=> string(1) "X"
  [24]=> string(1) "Y"
  [25]=> string(1) "Z"
}

range()関数はASCIIコードを元に範囲を作るらしいので、
大文字小文字の[A-z]を作ろうと思って、range('A', 'z') としても Za の間に記号が入るので注意が必要っぽい。


[参考]

おしえて A to Z

おしえて A to Z

Javascript Chromeでページトップに戻る(scrollTop)が効かなくなってた件。

Chromeで以前作ったサイトを見ていて、jQueryで実装していたページトップに戻るが効かなくなっているのに気づいてしまいました…

スペック

  • Mac OSX
  • Chrome v61.0.3163.91

$(‘body’).scrollTop() が効かなくなっていた。

今までは、FireFoxIE系はhtmlタグで、webkit系はbodyタグでscrollTopが動作していたので、$('html, body') とするとコールバックが2回呼ばれてしまうのが嫌だったので👇 の様な感じでブラウザ判別してscrollTopを使用するタグを切り替えていました。

var scrollTag = ( window.chrome || 'WebkitAppearance' in document.documentElement.style )? 'body' : 'html';

$(scrollTag).animate({
  scrollTop: 0
}, 'fast', function() {
  console.log('callback');
});

Chromeでは上記の判定で scrollTagbodyになっているので、$('body').scrollTop() が効いているか調べてみると…

// Chrome
$('body').scrollTop(); // => 0 ※常に0が返る

Chromeのアップデートで仕様変更になったようで、Firefoxを同じでhtmlタグでscrollTopが動作するようになり、$('body').scrollTop() が常に0になってしまうようになっていた為に「ページトップに戻る」が動作しなくなっていたようです… (いつのアップデートで変更になってたんだろう???

ブラウザごとの scrollTop の効くタグを調べてみる。

改めて、どのブラウザがbodyで動作するのか、htmlで動作するのかを調べてみました。
IE系が手元に無いので、調べ次第追加します。

👇 codepen に簡単なHTMLとscriptを作成して、各ブラウザでチェックしてみて動作する方のタグを調べます。にちょっとしたチェック用のHTMLとかJSをcodepenに作っておくと緊急時に割りとお役立ちなのです!

See the Pen scroll test HTML or BODY? by KIKIKI (@chaika-design) on CodePen.

ブラウザ バージョン html body
Chrome 61.0.3163.91 ×
Safaei 10.1.2 ×
Firefox 55.0.3 ×
Vivaldi 1.12.955.36 ×
Opera 47.0.2631.83 ×
Safari (iPhone) 10.0 ×

以前調べた時と違って、ChromeVivaldi では body タグではscrollTopが効かなく、htmlタグで効くようになっていました。

scrollTopを使用するタグのブラウザ別判定を変更する。

使用していたscrollTopを使用するタグを決めるブラウザ判定のスクリプトを変更します。

var ua = navigator.userAgent;
var scrollTag = ( (!window.chrome && 'WebkitAppearance' in document.documentElement.style) || ua.indexOf('OPR') !== -1 )? 'body' : 'html';

Operaが少し厄介で。window.chrome オブジェクトを持っているけど、body タグにしなければならないので、Operaの判定のためだけにユーザーエージェントを利用して ua.indexOf('OPR') !== -1 なら常にbodyになるようにしてあげる必要がありました。

Operaをサポートしないのであれば下記で問題ないように思います。

var scrollTag = ( !window.chrome && 'WebkitAppearance' in document.documentElement.style )? 'body' : 'html';

 
調べていると body, html {height: 100%}というCSSが原因?という記事も出てきたのですが、私の確認できる範囲ではこれを削除してもうまく動作せず、変更時のサイトへの影響範囲が大きいのでjavascriptの判定の方を変更する事にしました。

また、いつブラウザの仕様が変わってしまうか解りませんので、その時はまた調べて変更する必要がありそうです。(メンドー
昔作ったサイトでは色々と動かなくなってそう…


[参考]

トップをねらえ2! Blu-ray Box

トップをねらえ2! Blu-ray Box

Ajaxを使ってWordPressからコンテンツを取得したい。

WordPress製のサイトに独自のコンテンツなどを取得できるAjaxを作成する方法のメモ

  1. 呼び出すアクション名を決める
  2. Ajax送信先をjsから使えるように出力する
  3. Ajaxで呼び出される関数を作成する (PHP)
  4. フロントからAjaxでの呼出しを作成する (javascript)

1. 呼び出すアクション名を決める

アクション名はPHPの関数名やnoce、jsのAjax内などで何度も使うので、どんな仕様にするか決めて仕様に合ったアクション名を先に決めておくのが良いと思います。

今回は my-ajax-action というアクション名にします。

2. Ajax送信先のパスなどの出力

WordPressAjaxのリクエス送信先 /wp-admin/admin-ajax.php のパスやnoneなどの情報をjavascriptグローバル変数として出力する

<?php // function.php
function my_enqueue_scripts() {
  $handle = 'my-script';
  // Ajaxの呼出しが書かれているスクリプトのパス
  $jsFile = 'path/to/myscript.js';
  
  wp_register_script($handle, $jsFile, ['jquery']);
  
  // 1.で決めたアクション名
  $acrion = 'my-ajax-action';
  // 配列をJSのオブジェクトに変換したscriptを出力する
  wp_localize_script($handle, 'MY_AJAX', [
    'api'    => admin_url( 'admin-ajax.php' ),
    'action' => $acrion,
    'nonce'  => wp_create_nonce( $acrion ),
  ]);
  
  wp_enqueue_script($handle);
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );

$handleで指定された myscript.js の出力タグの前に次のようなスクリプトが出力されます。

<script type='text/javascript'>
/* <![CDATA[ */
var MY_AJAX = {
  "api": "http:\/\/example.com\/wordpress\/wp-admin\/admin-ajax.php",
  "action": "my-ajax-action",
  "nonce": "生成されたNONCE値"
}
/* ]]> */
</script>

※ 実際には1行で出力されます。グローバル変数になっちゃうので、ちょっとイケてない感あります…

複数のアクションを作成する場合は、アクションとそれに対応したnonceが取得しやすいように配列をネストするなどして工夫してください。

3. 呼び出される関数の作成 (PHP)

3.1 Ajaxから呼び出される関数を定義する

add_action アクションフックで、Ajaxから呼び出される関数を登録する。

<?php // function.php
function my_ajax_event() {
}
add_action( 'wp_ajax_my-ajax-action', 'my_ajax_event' );
add_action( 'wp_ajax_nopriv_my-ajax-action', 'my_ajax_event' );
  • wp_ajax_{action名} … ログインユーザーの時、呼び出される
  • wp_ajax_nopriv_{action名} … 非ログインユーザーの時、呼び出される

フロントから呼び出される場合は、両方のアクションフックを設定する必要がある。
管理画面で使うだけなら、常にログインユーザーなので wp_ajax_{action名} の方だけでOK。

3.2 Ajaxで呼び出される関数の処理を作成する

<?php // function.php
function my_ajax_event() {
  // wp_create_nonce の引数に渡したものと同じ アクション名
  $action = 'my-ajax-action';
  
  // nonceのチェック
  if( check_ajax_referer($action, 'nonce', false) ) {
    $data = [];

    // Ajax(post)のdataから渡される値を使用する場合は $_POST から取得する (適時エスケープ)
    $id = intval( $_POST['post_id'] );
    $name = esc_html( $_POST['name'] );
    
    /* wordpressから色々取得したり、Ajaxで返すデータ作成する */
    
    // 配列をjson形式にエンコード
    $data = json_encode($data);
  } else {
    // エラー
    status_header( '403' );
    $data = 'Forbidden';
  }

  // Ajaxに返す
  header( 'Content-Type: application/json; charset=UTF-8' );
  echo $data;

  die();
}
add_action( 'wp_ajax_my-ajax-action', 'my_ajax_event' );
add_action( 'wp_ajax_nopriv_my-ajax-action', 'my_ajax_event' );

nonceのチェック

check_ajax_referer( $action, $query_arg, $die )
  • $action (string)
    nonceのアクション名
    nonce作成時の wp_create_nonce() に渡したアクション名と同じ文字列を指定する
  • $query_arg (string)
    $_REQUESTで渡される配列の nonce が格納されているキーを指定
    上の例の場合は data: { nonce: 値 } としてAjaxから送ればOK
  • $die (boolean) default: true
    trueの時 nonce が無効なら die() する
    falseの時 nonce のチェック結果を true / false で返す

Ajax(post)のdataで渡される値は$_POSTで取得することができます。
nonceのチェック関数は内部では$_REQUESTから取得している様なので、$_REQUESTの方がget/postどちらでも取得できるで良いのかもしれません。

Ajaxで呼び出される関数の最後に die() がないと返されるデータの最後に0が追加されてしまうので、忘れないようにdieしておく必要があります。

4. Javascriptの作成 (Ajax呼出し)

後はフロントのjavascriptからAjaxで呼び出すだけです。
URLやアクション名は 2. で作成したグローバル変数から使用します。

// global MY_AJAX
"use strict";
$(function() {
  $.ajax({
    url: MY_AJAX.api,
    type: 'post',
    data: {
      // 呼び出すアクション名
      action: MY_AJAX.action,
      // アクションに対応するnonce
      nonce: MY_AJAX.nonce,
      // ▼ その他 渡したいデータがあれば適時 ▼
      post_id: 12345,
      name: 'name'
    }
  })
  .done(function( res ) {
    console.log( res );
  })
  .fail(function( jqXHR, textStatus, errorThrown ) {
    console.log( jqXHR, textStatus, errorThrown, arguments);
  });
});

 
これで、Ajaxを使ってWordPressから独自のコンテンツとか値を取得することができるようになりました。
Ajaxを使うために出力するjavascriptの変数がglobal変数になってしまうのが、やっぱイケてない感じなので、どうにか出来ないものかと思っています。。。


[参考]

世界一わかりやすいWordPress 導入とサイト制作の教科書 (世界一わかりやすい教科書)

世界一わかりやすいWordPress 導入とサイト制作の教科書 (世界一わかりやすい教科書)

WordPress WP_Query カスタム投稿の特定のtaxonomyを除く(含む)の指定方法

基本的にマニュアルに書いて有ることだけど、すぐ忘れるのでメモ。

タクソノミー(taxonomy)のパラメーター

タクソノミーに関する指定は、tax_queryをキーにした配列内に指定する。

特定の term を除く(含む) WP_Queryの指定方法

operator オプジョンで指定する。

<?php
$args = [
  'post_type' => ['my_post_type'],
  // タクソノミーに関する指定
  'tax_query' => [
    [
      // タクソノミー作成時に指定したタクソノミー名
      'taxonomy' => 'tax_name',
      // terms を slug で指定する
      'field'    => 'slug',
      // fieldで指定した方法で term そ指定する。この場合は slug 名で指定
      'terms'    => [
        'term_slug',
      ],
      // 上記のtermを除く場合は 'NOT IN' ・含む場合は 'IN'
      'operator' => 'NOT IN',
    ],
  ],
];
$the_query = new WP_Query($args);
// 処理
wp_reset_postdata();

 
関係ないけど、はてなブログのマークダウン、リンクをリストにしようとした時URLによっては-だとリストにならない時があってちょっとイライラする…


[参考]

Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術

Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術

PHP Bool値を文字列として出力したい。

PHP製の管理画面とかでtruefalse といったBoolean値をそのまま表示させたい時

単純に文字列にキャストしても上手くいかない

<?php
(string) true;  // => "1"
(string) false; // => ""
strval( true );  // => "1"
strval( false ); // => ""

// 空文字を連結してもダメ
echo true . '';  // => "1"
echo false . ''; // => ""

(string), strval で文字列化しても上手く表示することができません。

var_export 関数を使うと true / false の文字列で表示される

<?php
var_export( true );  // => "true"
var_export( false ); // => "false"

変数にして使用したい時は、第二引数をtrue にすればOK

<?php
$boolean = true;
$val = var_export( $boolean, true );
echo $val; // => "true"

三項演算子やif文を使うパターン

簡単ですが、Boolean値以外でもtrueかfalseでされてしまう問題があるのでそれを許容できるのであればOK。

<?php
function print_boolean($val) {
  echo ($val)? 'true':'false';
}
print_boolean( true );  // => "true"
print_boolean( false ); // => "false"

// Boolean値以外でも true か false で出力される
print_boolean(  );  // => "false"
print_boolean( 0 ); // => "false"
print_boolean("false"); // => "true"

Boolean を var_dump、prent_r した時の違い

<?php
var_dump( true );  // => bool(true)
var_dump( false ); // =>  bool(false)

print_r( true );  // => "1"
print_r( false ); // => ""

 
Bool値を文字列にキャストした際にfalse""になってしまうのは、文字列の"false"をBoolean値にキャストするとtrueになる仕様のためなんじゃないかなと思いました。👇

<?php
$bool = (bool) "false";
var_dump( $bool ); // => bool(true)
$bool = (bool) 0
var_dump( $bool ); // => bool(false)

[参考]

いきなりはじめるPHP~ワクワク・ドキドキの入門教室~

いきなりはじめるPHP~ワクワク・ドキドキの入門教室~

SublimeText マークダウンの時だけ行末スペースの自動削除をOFFにしたい。

Atomに乗り遅れてSublimeTextを使い続けてるマンです。
SublimeTextの設定で"trim_trailing_white_space_on_save": trueにしていると不要な行末のスペースを自動削除できて超便利です。

しかしREADME.mdとかマークダウンを書くことが増えているので、同じプロジェクト内のプロフラムのファイルは行末の無駄なスペースを削除したいけど、マークダウンで削除されるのは改行の時にチョット困る…
と、暫くマークダウンだけ別のエディタで開いたりしていましたが、いい加減面倒くささがMAX限界値に達したので重すぎる腰を上げてマークダウンの時だけ行末スペースの自動削除をOFFにしたのでメモしておきます。

インストールしてるテーマやパッケージなど

  • MarkdownLight - マークダウンのシンタックスハイライト
  • Markdown Extended - マークダウンのコード内のシンタックスハイライト
  • OmniMarkupPreviewer - ブラウザでリアルタイムでマークダウンのプレビューがみれるパッケージ
    ⌘+alt+Oでプレビューを起動
  • Table Editor - テーブルをフォーマットしてくれるパッケージ
    テーブルの記述位置でtabキーを押すとキレイにフォーマットしてくれる

Markdownの時だけ有効な設定ファイルを作成する

  1. テキトーな.mdなマークダウンファイルを作成し、シンタックスMarkdown Extendedにする
  2. メニューからView > Syntax > Open all with current extension as... > Markdown Extended を選択
  3. 設定ファイル Markdown Extended.sublime-settingsMacの場合~/Library/Application Support/Sublime Text 3/Packages/User/内に作成される

シンタックスMarkdownにする時は、2ではMarkdownを選択。設定ファイルはMarkdown.sublime-settingsになります

シンタックスMarkdown(Markdown Extended)の時、保存時の行末スペースの自動削除をOFFにする

先の手順で作成された設定ファイル(Markdown Extended.sublime-settings)を開き下記のように記述して保存すればOK

{
  // シンタックスハイライトに使用するカラースキームファイルのパス (適時変更してください)
  "color_scheme": "Packages/User/SublimeLinter/MarkdownLight (SL).tmTheme",
  // Table Editor パッケージを使用する
  "enable_table_editor": true,
  // Markdown Extended で使用する拡張子
  "extensions":
  [
    "md",
    "markdown"
  ],
  // タブサイズ
  "tab_size": 2,
  // タブをスペースに変換する
  "translate_tabs_to_spaces": true,
  // 保存時の行末スペース自動削除 OFF
  "trim_trailing_white_space_on_save": false
}

設定は適時変更してください。

color_scheme に使用したいファイルが見つからない時

パッケージコントロールcolor_schemeで使用したいスキームをインストールしてもファイルが見つからない時は、 一度メニューSublime Text > Preferences > Color Scheme から使用したいスキームを選択するとSublime Text 3/Packages/User/内にファイルが作成されます。
この時、全体のカラースキームが変更されるので、ファイルが作成されたら同様にメニューから元のスキームを再選択してもとに戻して上げる必要があります。
 
これで、ようやく面倒くささから開放されました!
pug(旧jade)でも行末スペースが欲しいときもあるので、同じような設定にしても良いかもしれません。
Atomとかならもっと簡単に設定できるのかしら?

ほんと、世の中 W◯rdとか辞めてMarkdownが主流になって欲しい。(TinyMCEゴリゴリカスタマイズって苦いお仕事の体験もあってビジュアルエディアあまり好きじゃない)


[参考]

最速の仕事術はプログラマーが知っている

最速の仕事術はプログラマーが知っている

WordPress ContactForm7 動的なオリジナルのフォームタグを作りたい。

WordPressでサイトを作る時のフォームの定番Contact Form 7はすごく便利なのですが、カスタム投稿から動的にselectタグを作るなどカスタマイズしたタグが欲しいことがあります。

ゴール (作りたいフォームタグ)

f:id:kikiki-kiki:20170730234424p:plain
例えばこんな感じに、タレント(talent)というカスタム投稿タイプを作成して所属するアイドルを登録して
フォームでは、お仕事を依頼するタレントを選べるようにしたいような場合。

タレントを登録・削除するたびに、フォームのセレクトタグのvalueの値を変更するのはメンドーだし、ジョニー先生に任せた時に上手く運用できるか怪しいので、タレントの登録情報を動的に取得してセレクトタグを出力できると運用の手間も減ってハッピーになれそうです。

※ カスタム投稿タイプの登録は割愛します

Contact Form 7 のカスタムフォームタグ・フォーム登録画面で使えるショートコードを作成する

Contact Form 7 は管理画面からショートコードを使ってフォームを作成できるので、同じようにショートコードのフォーマットでカスタムフォームタグを生成出来るようにしたいと思います。

どうやら wpcf7_add_form_tag と言う関数でショートコードと実際のフォームでどのように出力するかを決めているようでした。

contact-form-7/includes/form-tags-manager.php
function wpcf7_add_form_tag( $tag, $func, $features = '' ) {
  $manager = WPCF7_FormTagsManager::get_instance();
  return $manager->add( $tag, $func, $features );
}
note. Contact Form 7 バージョン 4.8.1
  • 第1引数が ショートコード
  • 第2引数が 実際のフォームに出力する際に呼ばれる関数
  • 第3引数が 使用できるオプション?

な感じっぽいです。

各フォームタグがどのように作られているかはcontact-form-7/modules/の中にあるtext.phpなどフォームパーツごとのファイル参考にしてカスタムフォームタグを作成していきます。今回はselectタグを作成するので contact-form-7/modules/select.php を参考に、 下の画像の感じで select_talent_list という名前のショートコードでタグが出力できるようにしたいと思います。👇

f:id:kikiki-kiki:20170731011733p:plain

functions.php にコードを記述します。

<?php // functions.php
// Contact Form 7 が導入されていて wpcf7_add_form_tag が有効な場合のみ
if( function_exists('wpcf7_add_form_tag') ) {
  // ※タグを出力するfunctionを先に記述していないと上手く動作しない
  function make_talent_select_tag($tag) {
    // 基本的な設定は参考にするタグの出力の仕方を参考に
    $t = new WPCF7_Shortcode($tag);
    $atts = [];
    $class = wpcf7_form_controls_class( $tag->type );
    $atts['class'] = $tag->get_class_option( $class );
    $atts['id'] = $tag->get_id_option();
    $atts['name'] = $tag->name;
    $name = sanitize_html_class( $atts['name'] );

    if ( $tag->is_required() ) {
      $atts['aria-required'] = 'true';
    }

    $atts['aria-invalid'] = $validation_error ? 'true' : 'false';
    
    // デフォルト選択 selected:値 というオプションがあれば該当するoptionタグを selected にする    
    $default = $tag->get_option( 'selected', '', true );

    // first_as_label オプションで先頭を未選択状態の文字を表示できるようにする
    $first_as_label = $tag->has_option( 'first_as_label' );
    $values = $tag->values;
    
    $options = '';
    if( $first_as_label && count($values)) {
      $options = '<option value>' . esc_html($values[0]) . '</option>';
    }

    // タレント名一覧を取得してセレクトタグのオプションにする
    $talents = get_talent_name_list();
    foreach($talents as $val) {
      $value = esc_attr($val);
      $selected = "";
      // デフォルト選択に該当している場合 selected 属性を出力する
      if( $default == $value) {
        $selected = ' selected="selected"';
      }
      $options .= '<option value="' . $value . '"' . $selected . '>' . esc_html($val) . '</option>';
    }

    $atts = wpcf7_format_atts( $atts );
    $html = sprintf(
      '<span class="wpcf7-form-control-wrap %1$s"><select %2$s>%3$s</select></span>',
      $name, $atts, $options
    );

    // 出力するタグのHTMLを返す
    return $html;
  }

  // ショートコードなどを登録
  wpcf7_add_form_tag(['select_talent_list', 'select_talent_list*'],
    'make_talent_select_tag',
    [
      'name-attr' => true,
      'selectable-values' => true,
    ]
  );

  // バリデーションは 元の select のものを利用
  add_filter( 'wpcf7_validate_select_talent_list', 'wpcf7_select_validation_filter', 10, 2 );
  add_filter( 'wpcf7_validate_select_talent_list*', 'wpcf7_select_validation_filter', 10, 2 );
}

// カスタム投稿タイプ `talent` のタイトル(名前)を返す
function get_talent_name_list() {
  $data = [];
  $args = array(
    'post_type'      => 'talent',
    'post_status'    => 'publish',
    'posts_per_page' => -1,
    'orderby'        => [
      'menu_order' => 'ASC',
      'date' => 'ASC',
    ],
  );
  $the_query = new WP_Query($args);
  if ( $the_query->have_posts() ) {
    while ( $the_query->have_posts() ) {
      $the_query->the_post();
      $talentName = get_the_title();
      $data[] = $talentName;
    }
  }
  // reset query
  wp_reset_postdata();
  return $data;
}

ざっくり作ってあるので、ショートコードにvalueを追加しても無視したり、他にあるオプションが使えなかったりしますが、

[select_talent_list <name> id:<id属性> class:<追加するclass> first_as_label "未選択状態に表示される文字"]

というショートコードでカスタム投稿タイプ talent 一覧を選択できるselectタグを作成することができました!

カスタム投稿タイプを変更すると、フォームタグが動的に変わる!

タレントに ジョニー別府 を追加・保存して、フォームをリロードすると…
f:id:kikiki-kiki:20170731010516p:plain

_人人人人人人人人人人人人人人人人人人人人人_
> 自動的に「ジョニー別府」が追加されます <
 ̄YYYYYYYYYYYYYYYYYYYY

元のselectタグのバリデーションを利用しているので、
[select_talent_list* first_as_label "---"] の様に入力必須にすれば未選択時にはちゃんとエラーが表示されました!
わーい! 

まとめ

プラグインの仕様が変わるとコードを更新しなければならなかったりしてくると思いますが、簡単に独自のフォームタグを作成することができるし、フォームパーツの出力はコードでどんなふうにもできるので、カスタム投稿だけでなく、タクソノミーを取得するとか色々と動的に更新されるフォームパーツを作ることができそうです!


[参考]

アイカツ! フォトonステージ! ! イラストコレクション

アイカツ! フォトonステージ! ! イラストコレクション

MVNO DMM モバイルにしてて助かった話。

いま気胸で入院をしている病室からこの記事を書いています。さっきまでCT撮ってましたw
病室に21世紀にもなって基本的人権であるネット環境・wifiが無いのでモバイル端末のデザリングをしている状態です。(Japaniはビジネスホテルでも未だにネット無いところも多いのでインターネッツ権の後進国でありましょう!)

そのモバイル端末ですが、長らく ぷららLTEモバイル を使っていました。

しかし、ぷららからLTEモバイルサービス終了が発表され、同グループでのオススメの移転先プランの通知を貰ったのですが容量無制限プランは無ありませんでした。電話は自分からは殆どかけないし外出時以外は自宅のwifiなので、これを期にランニングコストを下げようと思い最近格安プランに惹かれてiPadに試験導入したDMMのSIMが思ったより快適だったのでメインのモバイル端末もDMMに変更していました。

今回DMMに変更しておいて良かった。と実感たのでこの記事を書くことにしました。

それでは、DMMの回し者のようなDMMモバイルにして良かった点の話。
行ってみましょー!

回線速度が速い!

新幹線の中でも快適に繋がります。
今までは新幹線だけでなく、ローカルの電車内でもTwitterの画像が全然表示されませんでした。早くえっちなイラスト(予想)みたいのに!!!! となる事もあったのですが、DMMに変えてからは移動中でも快適ついったライフが送れています!
今思えばぷららLTEが遅すぎたのかもしれません…w

ど田舎ちほーだから恐らくDMMモバイルを使っている人も少ない事もあり速度的な不満を感じたことはありません。
東京に行った時お昼帯は少しもっさりするなーと思いましたが、ぷららの時はもっと遅かったのであまりストレスには感じませんでしたw
(幸せの沸点を下げておくと不幸が減るのです!)

余った容量が翌月に持ち越せる!

DMMにした一番の決め手がこれでした。
初めての容量制限ありだったので自分の使用料をあまり把握しておらず若干の不安があったのですが、余った分の容量を貯金のように持ち越せるので仕事柄 自宅での作業が多く容量が余ることが結構あるので、遠征や出張の予定が入っている時も容量の貯金があると精神衛生にも良いです!

また、残りの容量はWEBサイトから簡単に確認できるので毎月請求の際に貯金はどれだけあるかなぁ〜と確認しています。

ネットから簡単に容量を追加できる

WEBだけで完結できて楽ちん。
今入院していて身動きがとれないのにモバイルの容量をガンガン使っている状態でどうしよう…と思っていたのですが、DMMにログインしてモバイルの管理画面を見に行くと容量を追加するボタンが有り、そこから追加したい容量を選んで確認ボタンをクリックするだけでクレジットカードの入力も必要なく容量を追加することが出来ました!
f:id:kikiki-kiki:20170721152019p:plain

それも翌月への繰越なしなら1000MB 480円ワンコイン以下なのでとても助かっています。
これでアマプラやabemaTVでもアニメが見れるぞ!

結構繋がる

先日下の画像のようなグンマーちほーの奥地に行ってきたのですが、軒並み a◯ 回線が圏外な中 そこそこの電波拾いっぷりを発揮しました!
f:id:kikiki-kiki:20170724130413p:plain あれ?結構繋がるんやん!!!!  

請求書が発行できる

クレジットカードの明細がDMMって付くのでアレって意見もありますが、
ちょっと遷移方法が解り難いのですがWEBサイトの「お客様情報」の下の方にある「購入履歴」から領収書を発行できます。
DMM mobile 名義なので経費に積むにも領収書発行しちゃえば«いかがわしく»ないと思いますw

まとめ

インターネッツに依存しまくってる生活に慣れてしまうと、ネットに繋げなくなるって恐怖心がマジっぱない。
そして、最近覚えたギガ減るって感覚を身をもって体験することが出来ました。
願わくばDMMさんが二重認証を導入してくれんことを!

あーはやく治ってほしい。お体…