WP Twenty Seventeenテーマの1カラム表示

先ほどWordPressのTwenty-Seventeenテーマがver1.6への更新通知がきていたので更新したところ、表示が2カラム形式に戻ってしまっていた。本来は1カラムで設定をしていた。

  • 外観 > カスタマイズ > テーマオプション(この時にプレビュー表示が固定ページじゃないとこのメニューが表示されない) > 1カラム に設定する
  • 外観 > カスタマイズ > ウィジェット > ブログサイドバー で全てのウィジェットを削除する

雑な感じだったけど、これでもとの1カラム表示に戻った。

WordPress ACF ProのInstagramとYouTube表示が異常に重い

WordPress ACF Proプラグインでカスタムフィールドを作成して、InstagramとYouTubeコンテンツをフィールドタイプ「oEmbed」を使って、10件ほど登録したところ、表示までに8秒ほど時間がかかり、異常に遅くなった。

やったこと

フィールドタイプ「Wysiwyg」に置き換えてから、URLを貼り付けて登録したところ、劇的に改善した。表示速度が0.18秒になった(元々のKUSANAGIの速さに戻った)。

原因はわからず

WordPressのoEmbed機能自体は全く問題なく、ACF ProのoEmbedフィールドタイプが問題と思われるが、バグ情報などが見つからず、原因わからず。もしかしたらACFではない可能性もあるが、ひとまずACF ProのoEmbedは利用してないでおく。(非常に便利だったらので改善されたらまた使いたい)

ACF Proの柔軟コンテンツ

プライベートでWordPressのプラグイン ACF Pro を購入して柔軟コンテンツを利用したため、そのメモ。

柔軟コンテンツの超わかりやすい図解はこちら。
[WordPress] Advanced Custom Fieldsの拡張パッケージ、Flexible Content Fieldの使い方

柔軟コンテンツの登録例

柔軟コンテンツの中に柔軟コンテンツを入れる、っていう入れ子の構造も可能。
ACF Proの繰り返しフィールドの中に繰り返しフィールドを入れる、っていう入れ子と同じ仕組みが使える。

柔軟コンテンツの入力例

「行を追加」ボタンで柔軟コンテンツを呼び出せる。
以下の画像はすでに呼び出した後だが、右下にそのボタンを押したときにパターン選択できる模様も表示しておいた。

ACF ProはPersonal(1サイトのみ利用)で日本円で2,000円ぐらいだった。
がんばって開発するぐらいなら、これ買ったほうが確実に楽できる。安いし。
Developer(サイト無限に利用)はいつでもアップグレードできるらしいので、まずはPersonalからスタート。

WP Mail SMTPでOAuth認証するときに401エラーが出る場合

WordPressのWP Mail SMTPやRubyとかでOAuth認証を実装するときに、「Client ID」と「Client Secret」を作成するアプリケーション側に記述することになるが、OAuth認証を実行しようとすると、Google側には遷移するものの、「401. That’s an error.」と表示される。
これは、「Client ID」や「Client Secret」がちゃんと入力されていない可能性がある。Google Cloud Platform側でそれらの値をコピーしてから、ペーストすると、なぜか文頭と文末に空白(スペース)が入ってしまう。このスペースが入っていると動作しないため、前後にスペースが入ってしまっていないか要注意。(HanamiのOAuth認証実装時と、WordPressのOAuth認証実装時と、2回もこれでハマってしまった。)

この画面でコピーすると、すでに空白も一緒にコピーされている

OAuth認証を実行すると401エラー

参考サイト

入力フォームで改行する場合は’¥n’ではなく”¥n”

何年かおきに同じところでハマってしまう。
恥ずかしい内容だけど学習しないのでメモ。

入力フォーム(textarea)内で文章を改行させたい
場合は改行コードを入れてあげる必要がある。

$str = ‘1行目¥n2行目’; // サニタイズして¥nに変換してたとする
echo str_replace(‘n’, “¥n”, $str); // 改行コードに置換する

のような感じで改行が可能となる。

この時に、 “¥n” ではなく ‘¥n’ としてしまうと
改行コードではなく文字列としての ¥n になってしまうため
うまく改行されず、そのまま ¥n がtextareaに表示
されてしまう。
シングルクォーテーションとダブルクォーテーションで
意味が変わってしまうので要注意。

■参考
データベースから取り出したテキストの改行 – PHP – 教えて!goo

異なるDB間をモデル内でリレーション定義→利用不可

■環境 
 CakePHP 1.3.x 

■やりたいこと
 モデル内で異なるDB間(複数のDB)をリレーションし、
 それぞれのDBのカラムを出力する関数を定義する。
 
■結論
 普通の仕組みではムリ。ハックすればできる(らしい)。
 
■現状の整理
 異なるDB間のリレーション自体ができないわけではない。
 
 異なるDB間のモデルの紐付け(hasManyとか) → ○
 異なるDB間のモデル紐付け後にmodelsに関数作成 → ×(unknown columnと言われる)
 異なるDB間のモデル紐付け後にcontrollersに関数作成 → ○(model以外なら実行可)

■自分が取った対策
 modelsで関数定義はあきらめて、component化した。
 (ファットモデルはあらきめた) 

 【app/config/database.phpの設定】 
  こんな感じで設定 → CakePHP で複数のデータベースを使用する - mallowlabsの備忘録
 
 【app/models/読み込むモデルの設定】
  同上
 
 【app/controllers/components/読み込むコンポーネントの設定】
  ここを参考に異なるDBのカラムを出力する関数を作成
  第12回 コンポーネントの作り方:CakePHPで高速Webアプリ開発|gihyo.jp … 技術評論社 
  
 
 【app/controllers/コントローラの設定】 

  冒頭でこんな感じで呼び出し

  var $useDbConfig = 'userdb';
  var $uses = array('DB1のモデル', 'DB2のモデル';
  var $components = array('DB1とDB2両方を参照する関数を書いたコンポーネント');
 
  そのあと、コンポーネントを呼び出す。
 
■参考資料
 本件についての議論など(ハックすればできるよ的な内容含む)。
 ※日本語での内容は見当たらず
 CakePHP - querying across models with multiple databases and useDbConfig
 cakephp - Association and model data saving problem - Stack Overflow
 Multiple Databases Model Relationship - CakePHP | Google Groups 
 
■補足
 自分がCakePHPの仕組みをあまり分かっていない可能性もあり、
 そもそも、そういう動きをさせない(こういう疑問が出ないのが普通?)のが
 普通かもしれません。

画像アップロード関連メモ

以下、完全に自分用メモ

■CakePHPで画像アップロードした場合の中身
 参照ボタンで画像を選択してアップロード後に debug($this->data) すると、

    [image] => Array
        (
            [name] => Bonsai.gif
            [type] => image/gif
            [tmp_name] => /Applications/MAMP/tmp/php/phpCXMUmf
            [error] => 0
            [size] => 2105
        )

 [tmp_name]が画像を一時的に設置するテンポラリフォルダの場所 になっている。
 画像アップ後は move_uploaded_file で移動させる処理を行う。

■テンポラリフォルダの取得方法
 テンポラリフォルダは2つある。
 1)php.ini で upload_tmp_dir にパスを記載している場合
   → var_dump(ini_get(‘upload_tmp_dir’));
     でパスを取得できる
     ※記述がない場合は no value となりbool(false)が返り
      システムのテンポラリフォルダが自動的に利用される。
 2)システムのテンポラリフォルダ
   →  echo sys_get_temp_dir();
     でシステムが利用するテンポラリフォルダのパスを取得できる

■URLを指定して画像を取得

 $author_img_url = 'http://images.apple.com/iphone/home/images/a6_hero.png';
 $tmp_author_img_data = file_get_contents($author_img_url);
 file_put_contents('./test-aaa.jpg', $tmp_author_img_data); 

■参考URL
 PHP: sys_get_temp_dir – Manual
 [PHP]画像をダウンロードしてサーバーの特定のディレクトリに保存する « Codaholic

CakePHP x さくら x サブドメイン で Internal Server Error

下記構成で、

 CakePHP 1.3.x
 さくらインターネット
 サブドメイン
 
Internal Server Error が出た。
 
 
↓この設定通りにやったら一発で解決(ありがとうございます)

 [CakePHP] さくら で「500 Internal Server Error」 Web Sytem | AIDREAM

他のサイトにも設定方法が載ってたが、
上記サイトの設定でしか動かなかった。

CakePHP Auth でパスワード変更フォームの暗号化周り(暗号化されずに登録される場合など)

Authコンポーネントでパスワード変更フォーム作ったら
保存した時に暗号化されなかったり、暗号化された
パスワードが入力欄に入ったりしたので備忘録。

■現象
【1つ目】
 Authコンポーネント使用後、パスワード変更フォームで
 パスワード入力して保存すると、DB側にはパスワードが
 裸のまま保存される(「aaa」と入力したらそのまま保存)。

 ※ユーザー新規登録画面からユーザー名と
  パスワードを入力した場合はちゃんと暗号化(ハッシュ化)
  されて保存される。

【2つ目】
 パスワード入力欄のvalueが暗号化されたパスワードが
 入ってるため、そのまま保存するとハッシュ化後の
 パスワードが二重に暗号化して保存されてしまう。

■原因
【1つ目】 
 パスワード変更時は暗号化されないっぽい。

【2つ目】
 DB保存のパスワードが暗号化後の値のため、
 当然そのまま引っ張ってきてしまっている。
 (ちなみに暗号化を戻す復号化して表示みたいなのはできない)

■対策
【1つ目】
 パスワード変更時に$this->Auth->hashPasswords($this->data)で
 丸ごと暗号化をかけてDB保存する。

【2つ目】
 パスワード入力欄をデフォ空白にしておき、
 「新しいパスワード」みたいなフォームにする。
 空白だったらパスワード変更なし、
 空白以外だったらパスワード変更あり とする。
 (但し、そうすると今度はバリデーションに引っかかるが、
  ここでは設けない)

■対策後のソース(UsersController) RESOLUTION Source
    function edit() {
        $id = $this->Auth->User(‘id’);

        if (!$id && empty($this->data)) {
            $this->Session->setFlash(‘ユーザーが見つかりません’, ‘flash_message’, array(‘result’ => ‘error’));
            $this->redirect(array(‘action’ => ‘edit’));
        }

        if ($id && !empty($this->data)) {
            // パスワード入力欄が空白だったら配列削除  delete array if empty the password input form
            if (empty($this->data[‘User’][‘password’])) {
                unset($this->data[‘User’][‘password’]);
            }

            // userのidとusernameを定義しないと暗号化されない hashing need both username and password
            $this->data[‘User’] += array(
                ‘id’ => $this->Auth->User(‘id’),
                ‘username’ => $this->Auth->User(‘username’),
            );

            // AuthのhashPasswords関数でパスワードを暗号化してから保存 hashing password
            if ($this->User->save($this->Auth->hashPasswords($this->data))) {
                $this->Session->setFlash(‘変更内容を保存しました’, ‘flash_message’, array(‘result’ => ‘success’));
                //$this->redirect(array(‘action’ => ‘edit’));
            } else {
                $this->Session->setFlash(‘変更内容を保存できませんでした。もう一度実行してみてください。’, ‘flash_message’, array(‘result’ => ‘error’));
            }
        }

        if (empty($this->data)) {
            $this->data = $this->User->read(null, $id);
        }
    }

■参考サイト
 5.2.5.4 hashPasswords
 CakePHP 1.3 API – hashPasswords
 cakePHP | Authコンポーネントのパスワード暗号化に対応する

■for English
I have problem two things that change password page on CakePHP Auth component.

[CAUSE]
1. I couldn’t save hashing password.
2. password form show the hashing password.

[RESOLUTION]
1. use hassPassword class.
   $this->Auth->hashPasswords($this->data)
2.  set blank password form then check the form. check the my source.

CakePHPで複数joinする方法 INNER JOIN

複数テーブルからリレーション関係にある
カラム同士を紐付けて(INNER JOIN)クエリー実行。

            $options =  array(
                ‘fields’ => $val[‘fields’],
                ‘conditions’ => array(
                    ‘GrouponList.category_id’ => $category_id,
                ),
                ‘limit’ => $val[‘limit’],
                ‘order’ => $val[‘order’],
                ‘group’ => $val[‘group’],
                ‘joins’ => array(
                    array(
                        ‘type’ => ‘INNER’,
                        ‘table’ => ‘groupon_lists’,
                        ‘alias’ => ‘GrouponList’,
                        ‘conditions’ => array(
                            ‘SoBookmark.groupon_list_id = GrouponList.id’,
                        )
                    ),
                    array(
                        ‘type’ => ‘INNER’,
                        ‘table’ => ‘tw_counts’,
                        ‘alias’ => ‘TwCount’,
                        ‘conditions’ => array(
                            ‘SoBookmark.groupon_list_id = TwCount.id’,
                        )
                    ),
                ),
            );

        $this->set($key, $this->SoBookmark->find(‘all’, $options) );