tohokuaikiのチラシの裏

技術的ネタとか。

WordPressの編集画面がメチャ重くなったのでメタ情報のキャッシュを作って回避

調べてみると、カスタムフィールドの定義を取得するSQLで20秒も掛かってた。

カスタムフィールド使いまくってて、20万行越えてた。
過去のデータ中から、編集画面でプルダウンを作るんだけどそれはちょっと時間かかるよね…

ということで、テーマのfuncitons.phpに以下を追加。テーマディレクトリに tmpディレクトリを作ってパーミション777に。

<?php
class AnonymousTekitou
{
    /* ローカルキャッシュの時刻 */
    private $cache_lifetime  = 8000;
    
    /* ローカルキャッシュのディレクトリレベル */
    private $cache_dir_level = 2;
    

    /**
     * @brief 
     * @param 
     * @retval
     */
    public static function getInstance($cache_lifetime = null)
    {
        static $ins ;
        
        if (is_null($ins)){
            $ins = new self();
            if (!is_null($cache_lifetime)){
                $ins->cache_lifetime = $cache_lifetime;
            }
        }
        return $ins;
    }
    
    /**
     * @brief ファイルキャッシュ
     * @param 
     * @param 保存する場合は必要
     * @retval
     */
    private function cache($url, $body = null)
    {
        $cache_file = sprintf('%s/tmp/cache/%s',
                              __DIR__, $this->splitString(md5($url), $this->cache_dir_level));
        $cache_dir  = dirname($cache_file);
        if (!is_dir($cache_dir)){
            self::mkdir($cache_dir, 0777);
        }
        chmod($cache_dir, 0777);
        
        if (is_null($body)){
            if (file_exists($cache_file)){
                $s = stat($cache_file);
                if ($s['mtime'] + $this->cache_lifetime > time()){
                    $file = file($cache_file);
                    array_shift($file);
                    return implode("", $file); // キャッシュ有効・ファイルが存在してライフタイム内
                }
                else {
                    unlink($cache_file); // キャッシュ無効・再度取得
                    return null ;
                }
            }
            return false; 
        }
        else {
            file_put_contents($cache_file, $url."\n".$body);
            chmod($cache_file, 0666);
        }
    }

    

    /**
     * @brief 文字スラッシュを入れる。ex: abcdefg => a/b/c/defg
     * @param 文字列
     * @param 分割個数
     * @retval
     */
    private function splitString($str, $num) 
    {
        $ret = "";
        for ($i=0; $i< strlen($str) ;$i++){
            $ret .= $str{$i};
            if ($i<$num){
                $ret.= "/"; 
            }
        }
        return $ret;
    }
    
    
    /**
     *  mkdir -p
     *
     *  @access public
     *  @param  string  $dir    作成するディレクトリ
     *  @param  int     $mode   パーミッション
     *  @return bool    true:成功 false:失敗
     *  @static
     */
    public static function mkdir($dir, $mode)
    {
        if (file_exists($dir)) {
            return is_dir($dir);
        }

        $parent = dirname($dir);
        if ($dir === $parent) {
            return true;
        }

        if (is_dir($parent) === false) {
            if (self::mkdir($parent, $mode) === false) {
                return false;
            }
        }

        return mkdir($dir, $mode) && chmod($dir, $mode);
    }
    
    
    
    
    /**
     * @brief postmeta_form_keysのキャッシュを作成する
     * @param $WP_Post
     * @retval
     */
    public function getPostmetaFormKeysCache($post) 
    {
        global $wpdb;

        $key_name = md5(__CLASS__ . __METHOD__ . DB_NAME . __FILE__ . $_SERVER['SERVER_NAME']);

        // postがnullの時だけキャッシュを使う
        if (!is_null($post)) {
            return null;
        }

        if ($cache = $this->cache($key_name)){
            $keys = unserialize($cache);
        }
        else {
            // make cache
            $limit = apply_filters( 'postmeta_form_limit', 30 );
            $sql = "SELECT DISTINCT meta_key
          FROM $wpdb->postmeta
          WHERE meta_key NOT BETWEEN '_' AND '_z'
          HAVING meta_key NOT LIKE %s
          ORDER BY meta_key
          LIMIT %d";
            $keys = $wpdb->get_col( $wpdb->prepare( $sql, $wpdb->esc_like( '_' ) . '%', $limit ) );
            $this->cache($key_name, serialize($keys));
        }
        
        return $keys;
    }
}

add_filter('postmeta_form_keys', function($p){
    $a= AnonymousTekitou::getInstance();
    return $a->getPostmetaFormKeysCache($p);
});