かもメモ

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

WACOM Mac ペンタブレットIntuosのペンが反応しなくなった

WacomのFAQのサイトのURLが変わってしまっていて、新しいURLにリダイレクトされない為、記事中にあるhttp://tablet-faq.wacom.co.jp/faq/のリンクは無意味になっています m(_ _)m
2019 6.5 追記

このAI?が描いた絵を認識して当ててくれるゲームのようなサービスで遊ぼうと思いWacomのペンタブ(Intuos)を繋いだのですが、マッピングが画面の全画面なのに端の方だけになっていたり、ペンを認識してるのにマウスカーソルが動かない(反応しない)状態になってしまっていて、ペンタブの接続を切って再接続したり、ワコムのデスクトップセンターを再起動させたりしても症状は治らず解決に少しハマってしまったのでメモ。

Mac OS 10.14.5 にアップデートしてペンタブが動かなくなった場合は、ドライバを最新のものにアップデートしてみるのが良さそうです。
ref. macOS10.14.5にアップデートすると、ワコムタブレット製品が動作しなくなる | Wacom

私の症状としてはタブレット側でペンを認識はしている状態でした。
ペンが故障しているかどうかはWacomよくあるご質問と回答 (このページになかなか辿り着かなくて大変でした...)
2019 6.5 追記 WacomのサイトのFAQが変更になっているので「support | Wacom」から確認することができるようです。

Intuosの場合はこれでした👇
http://tablet-faq.wacom.co.jp/faq/show/2975
症状を確認しながら当てはまるものをチェックすると解決策が表示されます。

2019 6.5 追記 元のFAQページが何だったのか不明なのでそれっぽいページを貼っておきます。

ペンが反応しない場合の解決方法

1. アクセス権の修復 事前確認

2019 6.5 追記 現在のWacomのFAQのwindowサイトでは、アクセス権の修復ではなく、事前確認という項目になっているようでした。(Macの方はアクセス権の復旧を試してみるように書かれていました。

Macでトラブルが合った時の鉄板。
アプリケーション > ユーティリティ > ディスクユーティリティ.app でディスクのアクセス権を修復するやつです。

2. タブレット設定ファイルの初期化 (削除)

Wacomのドライバをインストールした時?だと思うのですが、「ワコムタブレットユーティリティ.app」というアプリケーションがインストールされていたのですね。今日まで全く知りませんでした...

Macの場合は

  1. アプリケーション > ワコム タブレット > ワコムタブレットユーティリティ.app を起動
    f:id:kikiki-kiki:20180327020815p:plain
  2. 設定ファイル「削除」を選択して設定ファイルを削除する。(私は削除する前に一度バックアップを選択して設定ファイルのバックアップを作成しました)
    f:id:kikiki-kiki:20180327020833p:plain
  3. システム環境にあるワコムタブレットの設定は再起動しないと反映されないので、PCを再起動
    f:id:kikiki-kiki:20180327020849p:plain
    👆OSのバージョンが古いのがバレる...
  4. ペンタブレットの設定ファイルが初期化されました
    f:id:kikiki-kiki:20180327020902p:plain

今回の場合はこの設定ファイルの初期化でマッピングも正常になりペンが反応するようになりました。
設定ファイルを初期化してもペンが反応しないような場合はドライバを削除して再インストールする必要があるようです。
今回私は試してないのですがその方法のリンクだけメモとして貼っておきます。

3. ペンタブのドライバを削除して再インストールする

タブレットドライバの削除と最新ドライバの再インストール http://tablet-faq.wacom.co.jp/faq/show/143 (リダイレクトされない旧FAQのリンク…)

2019 6.5 追記

 
旅行から帰ってきてMacを起動してペンタブを繋いだらペンが反応しない症状に初めて遭遇して、もしかして壊れた?とかなり焦ってしまいました。
おかげでワコムタブレットユーティリティというアプリケーションの存在を知ることができたのですが、デスクトップセンターとかのアプリからわかりやすくFAQに飛べるような導線があると良かったかな〜思いました。(解決方法のわかるFAQに辿り着くのが難しかったので...)

2019 6.5追記 WacomのFAQのサイトがリニューアルされていたの気づいていませんでした。ふつーこういう場合は旧URLが新しいFAQページにリダイレクトするように設計するものだと思うのですが、そうはなっていなくて調べてメモ代わりにFAQページのリンクを残していたのに、全くを持って無意味になってしまっていたので少し怒りのアフガン💢を感じましたが、人の振り見て我が振り直せ。
自分がこういうリプレイス案件に関わる時はUX損なわないように気をつけよーって思いました。


👆これ持ち運びにも良さそうなので欲しぃ

WordPress WP_Query 複数のカスタムフィールドを条件に投稿を取得したい。

WordPressでカスタムフィールドをたくさん作ったサイトとかでは、カスタムフィールドの値を条件にして投稿を取得したいケースが多々あります。
複数のカスタムフィールドの値を条件に投稿を取得する時のメモ。

条件にするカスタムフィールドが1つのとき

おさらい。
例えば product 投稿のカスタムフィールド pickuponのものを取得したい場合。
meta_key キーワードを使って指定する方法

<?php
$arg = [
  'post_type'    => 'product',
  'meta_key'     => 'pickup',
  'meta_value'   => 'on',
  'meta_compare' => '=', // "=" はデフォルトなので省略可
];
$the_query = new WP_Query($arg);

meta_query で指定する場合

<?php
$arg = [
  'post_type'  => 'product',
  'meta_query' => [
    [
      'key'     => 'pickup',
      'value'   => 'on',
      'compare' => '=',  // "=" はデフォルトなので省略可
    ],
  ],
];
$the_query = new WP_Query($arg);

複数のカスタムフィールドを条件にするとき

カスタムフィールド pickuponで、カスタムフィールドsale_end_atの日付が今日より大きい product (post_type)を取得した場合。
複数のカスタムフィールドを条件にしたい場合はmeta_queryの配列に条件を追加すればOK

<?php
$arg = [
  'post_type'  => 'product',
  'meta_query' => [
    [
      'key'     => 'pickup',
      'value'   => 'on',
    ],
    [
      'key'     => 'sale_end_at',
      'value'   => date( "Y-m-d" ),
      'compare' => '>',
    ],
  ],
];
$the_query = new WP_Query($arg);

複数のカスタムフィールドの値を AND で取得することができます。

複数のカスタムフィールドの条件をORで取得したいとき

meta_queryのカスタムフィールドの条件がある階層にrelationで指定することができます。(relationの指定がないとANDになります。)

カスタムフィールドsale_end_atの日付が今日より大きい または sale_end_atが指定されていない(未登録) で取得したい場合。

<?php
$arg = [
  'post_type'  => 'product',
  'meta_query' => [
    'relation' => 'OR',
    [
      'key'     => 'sale_end_at',
      'value'   => date( "Y-m-d" ),
      'compare' => '>',
    ],
    [
      'key'     => 'sale_end_at',
      'compare' => 'NOT EXISTS',
    ],
  ],
];
$the_query = new WP_Query($arg);

複数のカスタムフィールドでの複雑な条件での取得

カスタムフィールド pickuponで、
カスタムフィールドsale_end_atの日付が今日より大きい または sale_end_atが指定されていない(未登録) で取得したいような場合... 日本語で書くとややこしい...

pickup = "on" && ( sale_end_at > TODAY || NOT EXISTS (sale_end_at)  )

こんな感じの条件にしたいイメージです。

どうやら、meta_queryの配列内に配列を入れ子にして条件を作成することができるようです。

<?php
$arg = [
  'post_type'  => 'product',
  'meta_query' => [
    'relation' => 'AND',
    [
      'key'     => 'pickup',
      'value'   => 'on',
      'compare' => '=',
    ],
    [
      'relation' => 'OR',
      [
        'key'     => 'sale_end_at',
        'value'   => date( "Y-m-d" ),
        'compare' => '>',
      ],
      [
        'key'     => 'sale_end_at',
        'compare' => 'NOT EXISTS',
      ],
    ],
  ],
];
$the_query = new WP_Query($arg);

 
WP_Query すごい!!

ただ、カスタムフィールドの値でORDER_BYの条件にしたい時はmeta_keyに条件にするカスタムフィールドを指定しなければならないっぽいので、上記の条件でsale_end_atで並び替えようとするとsale_end_atが存在しない(NOT EXISTS)な投稿は取得されなくなってしまうのでORDER_BYと併用する場合は注意が必要です。(存在しない値のものがあるとどう並び替えるねん!ってなるから当然といえば当然ですが...

<?php
$arg = [
  'post_type'  => 'product',
  'meta_query' => [
    'relation' => 'AND',
    [
      'key'     => 'pickup',
      'value'   => 'on',
      'compare' => '=',
    ],
    [
      'relation' => 'OR',
      [
        'key'     => 'sale_end_at',
        'value'   => date( "Y-m-d" ),
        'compare' => '>',
      ],
      [
        'key'     => 'sale_end_at',
        'compare' => 'NOT EXISTS',
      ],
    ],
  ],
  'meta_key' => 'sale_end_at',
  'orderby'  => [
    'date'       => 'DESC',
    'meta_value' => 'ASC',
  ],
];
$the_query = new WP_Query($arg);

👆sale_end_atNOT EXISTS の投稿は取得されない。
並び替えが必要なら素直に2回 WP_Queryを発行するか、WP_Queryで取得した値をループさせて手動で並び替えを行うかで対処することになります。(DB問い合わせが少ないほうが良さそうかも!?

改めてWP_Queryって色々できるんだなーと知りました。


イタリア商事 ホットサンドメーカー ニュー・バウルー ダブル BW02

イタリア商事 ホットサンドメーカー ニュー・バウルー ダブル BW02


👆これ買ったので早く使いに行きたい。

WordPress pre_get_posts・WP_Query 別々の条件で記事を取得したい

WordPressWP_Querypre_get_postsアクション内で投稿を取ってくる時に、一緒にできない複数の条件(複数のSELECT文が必要な条件)で投稿を取得したいような時のメモ。

メインループ外の場合は2回WP_Queryを実行(SQLを発行)してそれぞれ取得したデータの配列をゴニョゴニョとマージしてしまうか、2回while( $the_query->have_posts() )で回してしまう方法もあります。(処理が多いかもですが、現実的にはこれが単純で簡単だと思います。)

サンプル

実現したいこと

story というカスタム投稿(post_type)を全て取得
数字の入るカスタムフィールド_sotry_noの値の順に並べて、
その後ろに、_sotry_no が存在しない投稿を続ける

UNION (MySQL)

WordPressで使われているMySQL的にはUNIONを使用すると1回のSQLで複数のSELECT文からデータが取得できるようです。

UNIONは複数のSELECT文によってデータをそれぞれ取得し、その結果を結合した上で1つのデータとして取得する場合に使います。書式は次の通りです。
SELECT col_name1, ... FROM tbl_name1
 UNION [ALL | DISTINCT] SELECT col_name2, ... FROM tbl_name2
 UNION [ALL | DISTINCT] SELECT col_name3, ... FROM tbl_name3;
出典: 取得データの結合(UNION句) - データの取得 - MySQLの使い方

また、UNIONを使って結合する、それぞれのSELECT文で並び替えを行いたい場合は、SELECT文にLIMITが含まれる必要がありました。

ex1. pre_get_posts() のメインクエリ書き換え内で別の

管理画面の一覧をカスタムフィールド_story_noで並び替えるようにしようとした場合、
_story_noフィールドが登録されていない状態で投稿(story)が作成されてしまうと、管理画面の一覧に表示されなくなってしまい編集すら行うことができなくなってしまう問題がありました。

WP_Queryを使える箇所であれば2回WP_Query()を使えば問題がないのですが、管理画面の一覧などpre_get_postsでメインクエリを書き換える必要がある箇所はpre_get_postsのアクション内でSQLを書き換えざるを得ません。 posts_requestフィルターを使えば実行されるSQLを直接書き換えることが可能なようなので、これを利用します。
[参考] Plugin API/Filter Reference/posts request « WordPress Codex

<?php // functions.php
add_action( 'pre_get_posts', 'my_posts_per_page' );
function my_posts_per_page( $wp_query ) {
  // 管理画面
  if( is_admin() ) {
    // 投稿タイプ story
    if( $wp_query->is_post_type_archive('story') ) {
      // カスタムフィールド _story_no で検索して表示させる
      $wp_query->set('meta_key', '_story_no');
      $wp_query->set('orderby', array(
        'meta_value_num' => 'DESC',
        'date' => 'DESC'
      ));

      /**
       * WP_QueryのSQLを置き換えるフィルター
       * @param: $request (Strings) ... 元のSQLのテキスト
       */
      add_filter( 'posts_request', function( $request ) {
        global $wpdb;
        // config.phpで設定されているDBのprefixを取得
        $prefix = $wpdb->base_prefix;
        // UNIONで追加するSQL文を作成
        $sql = "SELECT p.* FROM {$prefix}posts AS p
          WHERE p.post_type = 'story'
            AND p.post_status = 'publish'
            AND NOT EXISTS(
              SELECT meta.meta_id FROM {$prefix}postmeta AS meta
              WHERE meta.post_id = p.ID
                AND meta.meta_key = '_story_no'
          )
          GROUP BY p.ID
          ORDER BY p.post_date DESC
          LIMIT 0,18446744073709551615";

        // 実際に実行したいSQL文を返す
        // ※ 管理画面の一覧の$requestはデフォルトでLIMITが設定されれいるので別途LIMIT節を追加する必要なし
        return "({$request}) UNION ({$sql})";
      });
    }
  }
}

これで管理画面一覧でも特定のカスタムフィールドが無い投稿も表示され編集できるようになりました。

ex2. WP_Query() でUNIONを使う方法

残念ながらWP_Query()の引数の渡し方で複数のSELECTをマージできるような機能、UNIONを使ったSQLを作れる機能は無いようです。
[参考] Class Reference/WP Query « WordPress Codex

WP_Queryを2回実行しないのであれば、やはりposts_requestフィルターでSQLを変更するしかなさそうです。

<?php // functions.php
function get_my_story() {
  $arg = [
    'post_type' => 'story',
    // 該当する story を全件取得
    'posts_per_page' => -1,
    'meta_key'       => '_story_no',
     // _story_no が0以下のものは表示しない
    'meta_query'     => [
      [
        'key'     => '_story_no',
        'value'   => 0,
        'compare' => '>',
      ],
    ],
    // _story_no が小さい順に並べる
    'orderby'        => [
      'meta_value_num' => 'ASC',
      'date' => 'ASC',
    ],
  ];
  // SQLを書き換えるためのフィルター
  add_filter( 'posts_request', 'my_posts_request_filter');
  // WP_Query()が実行される際に↑の関数が実行される
  $the_query = new WP_Query($arg);
  // 同じページに他の WP_Query() があるとフィルターが動作してしまうので、フィルターを削除する
  remove_filter( 'posts_request', 'my_posts_request_callback');
  if( $the_query->have_posts() ) {
    while( $the_query->have_posts() ) {
      // 処理
    }
  }
  // 略
};

/**
 * WP_QueryのSQLを置き換えるフィルター
 * @param: $request (Strings) ... 元のSQLのテキスト
 */
function my_posts_request_filter( $request ) {
  global $wpdb;
  $prefix = $wpdb->base_prefix;
  $sql = "SELECT p.* FROM {$prefix}posts AS p
          WHERE p.post_type = 'story'
            AND p.post_status = 'publish'
            AND NOT EXISTS(
              SELECT meta.meta_id FROM {$prefix}postmeta AS meta
              WHERE meta.post_id = p.ID
                AND meta.meta_key = '_story_no'
          )
          GROUP BY p.ID
          ORDER BY p.post_date DESC
          LIMIT 0,18446744073709551615";

  // 実際に実行したいSQL文を返す
  // ※ 全件取得する元のSQLのORDER BYが効くようにするには LIMITが必要なので大きな値でLIMIT節を追加する
  return "({$request} LIMIT 0,18446744073709551615) UNION ALL ({$sql})";
}

表側のページの場合他の箇所でもWP_Queryが使われていたりする場合があるので、必要な箇所でのフィルター処理が完了したらremove_filterでフィルターを削除しておかないと、他のWP_Queryが使われている場所でもフィルターが実行されてしまうので注意が必要です。

 
WordPressの管理画面を見やすくなるようにと特定のカスタムフィールドで並び替えをしていたら、カスタムフィールドが空文字やNULLなら良いのですが、DBに登録されなかった場合、一覧に表示されず編集できなくなってしまう状況になり盛大にハマってしまいました。
いつもカスタムフィールドはCMB2というプラグインを使いコードベースで作成しているのですが、表示に際して必須なカスタムフィールドがある場合は必ず初期値を指定しておくべきだなと痛感しました。(初期値があれば今回のようにSQLを直接書き換える必要もなかったのです...)

MySQLとかWordPressで覚えた程度だったのでUNIONの存在を知らず、UNIONで結合したSELECT文をそれぞれ別にソートする方法にすごくハマりました... おかげで良い勉強になりなったので良かったです。
結局UNIONの問題と、存在しないカスタムフィールドを取得する複合的な問題だったので、それぞれ別の記事を作成するしました。


参考

SQLアンチパターン

SQLアンチパターン