WordPress YARPPプラグインのInnoDB対応


※今回の対応内容をGithubにもアップしました。
https://github.com/yKanazawa/yet-another-related-posts-plugin/pull/1/files

# 背景

WordPressのYet Another Related Posts Plugin (YARPP)は、バージョン4.4現在、MySQLのMyISAMしか対応していません。
wp-postsテーブルがInnoDBの場合、管理画面上で以下の警告が表示されます。

![myisam_notice.png](https://qiita-image-store.s3.amazonaws.com/0/38162/d99f98e7-85b4-2f29-14d3-d89ef7182fa7.png)

そして、関連スコア設定の「内容」と「カテゴリー」の選択が無効になり、選択できなくなります。
![myisam_disable.png](https://qiita-image-store.s3.amazonaws.com/0/38162/dc1e5275-4b0a-337e-5b39-1e6ae6118e80.png)

MySQLのFULLTEXTインデックスがMyISAMしかサポートしていなかったのが理由だと思われますが、MySQL5.6.4からInnoDBでもFULLTEXTインデックスがサポートされました。

※MySQL5.6登場当初、このことが話題になり、対応の要望が出ていたようです。
Support for InnoDB with full-text index
https://wordpress.org/support/topic/support-for-with-full-text-index/?replies=4

YARPPプラグインには、強制的にMyISAMと認識させるオプション（myisam_override）があり、それを有効にすればInnoDBでも使えるようです。
しかしながら、最近ではデフォルトでInnoDBを使うパターンも多くなったと思います。
特に、WordPressのDBをAWSのRDSで稼働させる場合、RDSは基本的にInnoDBのみのサポートで、MyISAMでは機能が制限されてしまいます。

そこで、MySQL5.6.4以上であれば、デフォルトでInnoDBでも動作するように修正してみました。

# Fulltextインデックス判定処理の調査

Fulltextインデックスが必要なテーブルは、wp-postsです。
このテーブルがMyISAMになっていないと、管理画面で警告が表示されます。
しかし、wp-postsテーブルをInnoDBに変換しても、管理画面で警告が出るだけで、実際の動作は正常に行われてるようです。

そのため、管理画面でのチェック処理を修正するだけで良いはずです。

wp-postsテーブルがMyISAMかどうかの判定は、classes/YARPP_Core.php のdiagnostic_myisam_posts関数で行なっています。

show table status の出力結果のEngineカラムの値を取得しているようです。

```
/**
* DIAGNOSTICS
* @since 4.0 Moved into separate functions. Note return value types can differ.
*/
public function diagnostic_myisam_posts() {
    global $wpdb;
    $tables = $wpdb->get_results("show table status like '{$wpdb->posts}'");
    foreach ($tables as $table) {
        if ($table->Engine === 'MyISAM'){
            return true;
        } else {
            return $table->Engine;
        }
    }
    return 'UNKNOWN';
}
```

MySQLのバージョンは、select version()で取得できます。

```
mysql> select version();
+------------+
| version()  |
+------------+
| 5.6.10-log |
+------------+
1 row in set (0.01 sec)
```

これが、5.6.4以上であればInnoDBでもFULLTEXTインデックスが使えるわけですが、MariaDBのパターンも考えると、バージョンで判定するのは良く無さそうです。

確実に判定するために、innodb_ft関連のパラメータが含まれているかどうかで判定することにしました。

```
mysql> show variables like 'innodb_ft%';
+---------------------------------+------------+
| Variable_name                   | Value      |
+---------------------------------+------------+
| innodb_ft_aux_table             |            |
| innodb_ft_cache_size            | 8000000    |
| innodb_ft_enable_diag_print     | OFF        |
| innodb_ft_enable_stopword       | ON         |
| innodb_ft_max_token_size        | 84         |
| innodb_ft_min_token_size        | 3          |
| innodb_ft_num_word_optimize     | 2000       |
| innodb_ft_result_cache_limit    | 2000000000 |
| innodb_ft_server_stopword_table |            |
| innodb_ft_sort_pll_degree       | 2          |
| innodb_ft_total_cache_size      | 640000000  |
| innodb_ft_user_stopword_table   |            |
+---------------------------------+------------+
12 rows in set (0.00 sec)
```

# 修正内容

## classes/YARPP_Core.php

### 292行目

```
/**
* DIAGNOSTICS
* @since 4.0 Moved into separate functions. Note return value types can differ.
*/
public function diagnostic_myisam_posts() {
    global $wpdb;
    $tables = $wpdb->get_results("show table status like '{$wpdb->posts}'");
    foreach ($tables as $table) {
        if ($table->Engine === 'MyISAM'){
            return true;
        } else {
            return $table->Engine;
        }
    }
    return 'UNKNOWN';
}
```

↓
関数名変更：diagnostic_myisam_posts → diagnostic_fulltext_posts

```
/**
* DIAGNOSTICS
* @since 4.0 Moved into separate functions. Note return value types can differ.
*/
public function diagnostic_fulltext_posts() {
    global $wpdb;
    $params = $wpdb->get_results("show variables like 'innodb_ft%';");
    if (count($params) > 0) {
       return true;
    }
    $tables = $wpdb->get_results("show table status like '{$wpdb->posts}'");
    foreach ($tables as $table) {
        if ($table->Engine === 'MyISAM'){
            return true;
        }
        return false;
    }
}
```

## includes/yarpp_myisam_notice.php

### 34行目

```
$table_type = $yarpp->diagnostic_myisam_posts()
if ((bool) $table_type !== true) $yarpp->disable_fulltext();
```
↓
ファイル名変更：yarpp_myisam_notice.php →　yarpp_fulltext_notice.php

```
$fulltext_posts = $yarpp->diagnostic_fulltext_posts();
if ($fulltext_posts === true) {
    if ((bool) get_option('yarpp_fulltext_disabled', false) === true) {
        $yarpp->enable_fulltext();
        update_option('yarpp_fulltext_disabled', 0);
    }
} else {
    $yarpp->disable_fulltext();
}
```

### 49行目

```
            sprintf(
                'YARPP&#39;s "consider titles" and "consider bodies" relatedness criteria require your <code>%s</code> '.
                'table to use the <code>MyISAM</code> engine'.
                'fulltext indexing feature. Unfortunately your table seems to be using the <code>%s</code> engine. '.
                'Because fulltext indexing is not supported by your current table engine, these two options have been disabled.',
                $wpdb->posts,
                $table_type
            ).
            '</p>'.
            '<p>'.
            sprintf(
                'To restore these features, please do the following:<br/>'.
```
↓

```
            sprintf(
                'YARPP&#39;s "consider titles" and "consider bodies" relatedness criteria require your <code>%s</code> '.
                'table to use the fulltext indexing feature.<br/>' .
                'Unfortunately your table does not seem to be able to use fulltext index.<br/>' .
                'Fulltext indexing is supported in MyISAM, or InnoDB with MySQL 5.6.4 or higher. ',
                $wpdb->posts
            ).
            '</p>'.
            '<p>'.
            sprintf(
                'If you are using MySQL 5.6.3 or earlier version, to restore these features, please do the following:<br/>'.
```

## includes/yarpp_options.php

### 72行目

```
/* MyISAM Check */
include 'yarpp_myisam_notice.php';
```
↓

```
/* FullText Check */
include 'yarpp_fulltext_notice.php';
```

## 関数名変更

以下の箇所について

```
classes/YARPP_Core.php:     public function diagnostic_myisam_posts() {
classes/YARPP_Core.php:                     $table_type = $this->diagnostic_myisam_posts();
classes/YARPP_Core.php:                     if (!$this->get_option('myisam_override') && $this->diagnostic_myisam_posts() !== true) {
classes/YARPP_Core.php:                             'myisam_posts'          => $this->diagnostic_myisam_posts(),
includes/yarpp_myisam_notice.php:$table_type = $yarpp->diagnostic_myisam_posts();
```

diagnostic_myisam_posts()
↓
diagnostic_fulltext_posts()
に関数名変更