fix: 修復 partner 偵測時序 bug(AddOn 從未生效)+ IG meta_key 錯配 #1
@@ -3,7 +3,7 @@
|
|||||||
* Plugin Name: 2meet Data Optimizer — Infocards AddOn
|
* Plugin Name: 2meet Data Optimizer — Infocards AddOn
|
||||||
* Plugin URI: https://2meet.io/2meet-data-optimizer/infocards
|
* Plugin URI: https://2meet.io/2meet-data-optimizer/infocards
|
||||||
* Description: 2meet-infocards 整合:hp_vendor 9 postmeta (3 Hot tmeetic_profile_* + 6 Cold tmeetic_ig_*) + 3 vendor profile 表 + doctor check
|
* Description: 2meet-infocards 整合:hp_vendor 9 postmeta (3 Hot tmeetic_profile_* + 6 Cold tmeetic_ig_*) + 3 vendor profile 表 + doctor check
|
||||||
* Version: 0.1.0
|
* Version: 0.1.1
|
||||||
* Requires at least: 6.0
|
* Requires at least: 6.0
|
||||||
* Tested up to: 6.9.4
|
* Tested up to: 6.9.4
|
||||||
* Requires PHP: 8.1
|
* Requires PHP: 8.1
|
||||||
@@ -24,7 +24,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
define( 'TMDO_INFOCARDS_VERSION', '0.1.0' );
|
define( 'TMDO_INFOCARDS_VERSION', '0.1.1' );
|
||||||
define( 'TMDO_INFOCARDS_PATH', plugin_dir_path( __FILE__ ) );
|
define( 'TMDO_INFOCARDS_PATH', plugin_dir_path( __FILE__ ) );
|
||||||
define( 'TMDO_INFOCARDS_URL', plugin_dir_url( __FILE__ ) );
|
define( 'TMDO_INFOCARDS_URL', plugin_dir_url( __FILE__ ) );
|
||||||
define( 'TMDO_INFOCARDS_FILE', __FILE__ );
|
define( 'TMDO_INFOCARDS_FILE', __FILE__ );
|
||||||
@@ -37,4 +37,10 @@ require_once TMDO_INFOCARDS_PATH . 'includes/back-compat-aliases.php';
|
|||||||
*
|
*
|
||||||
* @see ~/.claude/plans/wp-data-optimizer-2meet-data-optimizer-zesty-liskov.md
|
* @see ~/.claude/plans/wp-data-optimizer-2meet-data-optimizer-zesty-liskov.md
|
||||||
*/
|
*/
|
||||||
add_action( 'plugins_loaded', array( 'TMDO_Infocards_Bootstrap', 'init' ), 6 );
|
// priority 3(其餘 AddOn 慣例為 6):核心的 `fire_registration()` 最早在
|
||||||
|
// plugins_loaded:4 觸發,在 :6 bootstrap 會**必定錯過第一次註冊**,而
|
||||||
|
// Custom_Table_Registry 是「先註冊者勝」——主外掛 2meet-infocards 的 closure 在
|
||||||
|
// 檔案解析時就掛好,會在 :4 先以無 expected_columns 的版本佔走 key。
|
||||||
|
// 核心的 TMDO_API / TMDO_Custom_Table_Registry 於 file-parse 時(主檔 126/127/179 行)
|
||||||
|
// 即已 require,故提前到 :3 是安全的。
|
||||||
|
add_action( 'plugins_loaded', array( 'TMDO_Infocards_Bootstrap', 'init' ), 3 );
|
||||||
|
|||||||
@@ -13,6 +13,60 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [0.1.1] — 2026-08-08 — 修復 partner 偵測時序 bug(AddOn 從未生效)與 IG 欄位 meta_key 錯配
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **本 AddOn 從未掛上任何 hook,等同未啟用(嚴重)。** `TMDO_Infocards::register()`
|
||||||
|
舊版在 bootstrap 當下就以 `class_exists( 'TMEETIC_*' )` 偵測 partner,失敗即
|
||||||
|
early return。但本 AddOn bootstrap 掛在 `plugins_loaded:6`,而 2meet-infocards
|
||||||
|
要到 `plugins_loaded:20`(`tmeetic_run`)才 require 自身類別——在 :6 當下
|
||||||
|
TMEETIC_* 類別一律不存在,偵測**必定**失敗,於是 `wpdo_register_fields` /
|
||||||
|
`wpdo_register_custom_tables` 兩個 hook 從未被掛上(實測:`TMEETIC_Frontend`
|
||||||
|
在 prio 6 = MISSING、prio 21 = EXISTS)。三處修法:
|
||||||
|
1. 偵測從 bootstrap 移進 hook callback 內執行(`register_post_fields()` /
|
||||||
|
`register_custom_tables()` 開頭),hook 一律先掛上。核心於
|
||||||
|
`plugins_loaded:30` 有 late-bind safety net 會重新 fire 註冊 hook,唯有把
|
||||||
|
偵測延後到 callback 執行當下才會正確生效。
|
||||||
|
2. 偵測改以 `TMEETIC_VERSION` / `TMEETIC_PLUGIN_DIR` 常數優先,`class_exists()`
|
||||||
|
退為後備。這兩個常數在 `2meet-infocards.php` 的**檔案解析當下**即 define,
|
||||||
|
早於 `plugins_loaded`;核心 `fire_registration()` 最早在 `plugins_loaded:4`
|
||||||
|
觸發,該時點只有常數可用,只靠 `class_exists()` 會在最關鍵的第一次註冊誤判
|
||||||
|
為「partner 不存在」。
|
||||||
|
3. bootstrap priority 由 6 提前到 3,`wpdo_register_custom_tables` callback
|
||||||
|
priority 設為 5。理由有二:核心 `fire_registration()` 最早在
|
||||||
|
`plugins_loaded:4` 觸發,掛在 :6 必定錯過第一次註冊;且
|
||||||
|
`TMDO_Custom_Table_Registry` 對同一 `provider:table_name` 是「先註冊者勝、
|
||||||
|
後者回傳 false」,主外掛 2meet-infocards 的 closure 在檔案解析當下就掛上
|
||||||
|
prio 10,若不提前,會先以無 `expected_columns` 的版本佔走 key。
|
||||||
|
- IG token 兩個欄位註冊的 meta_key 與 2meet-infocards 程式碼實際讀寫的 key 不符,
|
||||||
|
導致它們從未真正進入 TMDO 加速路徑(仍落回 `wp_postmeta`):
|
||||||
|
- `tmeetic_ig_token_enc` → `tmeetic_ig_access_token_enc`
|
||||||
|
- `tmeetic_ig_token_expires_at` → `tmeetic_ig_token_expiry`
|
||||||
|
- `TMDO_Custom_Table_Registry::register()` 的索引期望值 config key 由
|
||||||
|
`expected_indexes` 更正為 `indexes`。該 API 以 `wp_parse_args()` 併入預設值,
|
||||||
|
未知 key 會被**靜默丟棄**——先前索引期望值等同從未送達 registry,
|
||||||
|
`wp wpdo doctor` 的 schema drift 只驗欄位、不驗索引。此問題橫跨全部 8 個 AddOn,
|
||||||
|
已一併更正。
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 註冊先前完全未註冊的兩個 `hp_vendor` Cold zone 欄位:`tmeetic_ig_username`、
|
||||||
|
`tmeetic_ig_feed_show`。
|
||||||
|
- 為 `2meet_vendor_profiles`(16 欄)/ `2meet_cards`(25 欄)/
|
||||||
|
`2meet_theme_styles`(8 欄)三張表補上 `expected_columns` 與 `indexes`,
|
||||||
|
`wp wpdo doctor` 才能對它們做 schema drift 檢查。先前只註冊表名,doctor
|
||||||
|
無從判斷欄位或索引是否漂移。
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- 移除 `tmeetic_ig_app_id`、`tmeetic_ig_app_secret_enc` 兩個幽靈註冊。IG 應用
|
||||||
|
憑證是**站台層級**設定,實際存於 `wp_options` 的 `2meetic_ig_app_id` /
|
||||||
|
`2meetic_ig_app_secret_enc`,並非 `hp_vendor` postmeta;全外掛對這兩個
|
||||||
|
postmeta key 零讀寫,註冊只會在 Cold zone 留下永遠空的欄位定義。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [0.1.0] — TBD
|
## [0.1.0] — TBD
|
||||||
|
|
||||||
### Added (initial release, scaffold)
|
### Added (initial release, scaffold)
|
||||||
|
|||||||
@@ -11,7 +11,13 @@
|
|||||||
* - Provide cache loader for inject_profile_styles() so it doesn't query DB
|
* - Provide cache loader for inject_profile_styles() so it doesn't query DB
|
||||||
* on every wp_head call
|
* on every wp_head call
|
||||||
*
|
*
|
||||||
* @package WP_Data_Optimizer
|
* NOTE: 2meet-infocards 主檔(2meet-infocards.php)自 v6.9.24 起也直接掛
|
||||||
|
* wpdo_register_fields / wpdo_register_custom_tables(belt-and-suspenders,
|
||||||
|
* 繞過舊版 wp-data-optimizer 曾有的時序偵測 bug)。兩邊重複註冊同一批欄位是
|
||||||
|
* 刻意的防禦性冗餘,Schema Registry 對同一 meta_key 重複 register 是 idempotent
|
||||||
|
* 操作,不會造成資料損壞;但若未來要精簡,應二擇一保留,勿只改其中一邊的 key 名稱。
|
||||||
|
*
|
||||||
|
* @package TMDO
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -25,19 +31,45 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
final class TMDO_Infocards {
|
final class TMDO_Infocards {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static registration entry. Called from TMDO_Core::run().
|
* Static registration entry. Called from the AddOn bootstrap on plugins_loaded:6.
|
||||||
|
*
|
||||||
|
* 時序修正:偵測**不可**在此處做。本 AddOn bootstrap 於 plugins_loaded:6 執行,
|
||||||
|
* 但 2meet-infocards 要到 plugins_loaded:20(`tmeetic_run`)才 require 自身類別,
|
||||||
|
* 因此在 :6 當下 TMEETIC_* 一律不存在 → 舊版在此早退,導致整個 AddOn 從未掛上
|
||||||
|
* 任何 hook(實測:TMEETIC_Frontend 在 prio 6 = MISSING、prio 21 = EXISTS)。
|
||||||
|
*
|
||||||
|
* 核心於 plugins_loaded:30 有 late-bind safety net 會重新 fire 註冊 hook,
|
||||||
|
* 所以改為「hook 一律掛上、偵測延後到 callback 執行當下」才會正確生效。
|
||||||
|
*
|
||||||
|
* priority 5(而非預設 10)的理由:Custom_Table_Registry 對同一
|
||||||
|
* `provider:table_name` 是「先註冊者勝、後者回傳 false」。主外掛
|
||||||
|
* `2meet-infocards.php` 的 closure 在**檔案解析當下**就掛上 prio 10,早於本
|
||||||
|
* AddOn 在 plugins_loaded:6 掛載,同 prio 內先掛先跑 → 主外掛會先以「無
|
||||||
|
* expected_columns」的版本佔走 key。本 AddOn 的定義較豐富(含 expected_columns
|
||||||
|
* / indexes / doctor_callback),故提前到 prio 5 讓它勝出;主外掛其餘 26 張表
|
||||||
|
* 不受影響,仍由它自己註冊。
|
||||||
*/
|
*/
|
||||||
public static function register(): void {
|
public static function register(): void {
|
||||||
// Detect partner plugin via known class names (any one is sufficient).
|
add_action( 'wpdo_register_fields', array( __CLASS__, 'register_post_fields' ) );
|
||||||
$detected = class_exists( 'TMEETIC_Plugin' )
|
add_action( 'wpdo_register_custom_tables', array( __CLASS__, 'register_custom_tables' ), 5 );
|
||||||
|| class_exists( 'TMEETIC_Frontend' )
|
|
||||||
|| class_exists( '\\TwoMeet_InfoCards\\Plugin' );
|
|
||||||
if ( ! $detected ) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_action( 'wpdo_register_fields', array( __CLASS__, 'register_post_fields' ) );
|
/**
|
||||||
add_action( 'wpdo_register_custom_tables', array( __CLASS__, 'register_custom_tables' ) );
|
* Detect the partner plugin.
|
||||||
|
*
|
||||||
|
* 以常數優先、類別為輔:`TMEETIC_VERSION` / `TMEETIC_PLUGIN_DIR` 在
|
||||||
|
* `2meet-infocards.php` 的**檔案解析當下**(第 25–33 行,不在任何 function 內)
|
||||||
|
* 就已 define,早於 `plugins_loaded`;而 TMEETIC_* 類別要到 plugins_loaded:20
|
||||||
|
* 才 require。核心的 `fire_registration()` 最早在 plugins_loaded:4 觸發,
|
||||||
|
* 該時點只有常數可用——只靠 class_exists() 會在最關鍵的第一次註冊時誤判為
|
||||||
|
* 「partner 不存在」。
|
||||||
|
*/
|
||||||
|
private static function partner_detected(): bool {
|
||||||
|
return defined( 'TMEETIC_VERSION' )
|
||||||
|
|| defined( 'TMEETIC_PLUGIN_DIR' )
|
||||||
|
|| class_exists( 'TMEETIC_Plugin' )
|
||||||
|
|| class_exists( 'TMEETIC_Frontend' )
|
||||||
|
|| class_exists( '\\TwoMeet_InfoCards\\Plugin' );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,6 +79,9 @@ final class TMDO_Infocards {
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function register_post_fields( TMDO_Schema_Registry $registry ): void {
|
public static function register_post_fields( TMDO_Schema_Registry $registry ): void {
|
||||||
|
if ( ! self::partner_detected() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$registry->register_many(
|
$registry->register_many(
|
||||||
'2meet-infocards',
|
'2meet-infocards',
|
||||||
array(
|
array(
|
||||||
@@ -81,30 +116,19 @@ final class TMDO_Infocards {
|
|||||||
'cache_ttl' => HOUR_IN_SECONDS,
|
'cache_ttl' => HOUR_IN_SECONDS,
|
||||||
),
|
),
|
||||||
// IG tokens — sensitive + display-only → Cold zone.
|
// IG tokens — sensitive + display-only → Cold zone.
|
||||||
|
// 註:app id / secret 不在此列——那是站台層級的 wp_options
|
||||||
|
// (`2meetic_ig_app_id` / `2meetic_ig_app_secret_enc`),非 hp_vendor
|
||||||
|
// postmeta。舊版誤註冊的兩個 postmeta 欄位全外掛零讀寫,已移除。
|
||||||
array(
|
array(
|
||||||
'post_type' => 'hp_vendor',
|
'post_type' => 'hp_vendor',
|
||||||
'meta_key' => 'tmeetic_ig_app_id',
|
'meta_key' => 'tmeetic_ig_access_token_enc',
|
||||||
'zone' => 'cold',
|
'zone' => 'cold',
|
||||||
'cache_group' => 'wpdo_cold_hp_vendor',
|
'cache_group' => 'wpdo_cold_hp_vendor',
|
||||||
'cache_ttl' => HOUR_IN_SECONDS,
|
'cache_ttl' => HOUR_IN_SECONDS,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'post_type' => 'hp_vendor',
|
'post_type' => 'hp_vendor',
|
||||||
'meta_key' => 'tmeetic_ig_app_secret_enc',
|
'meta_key' => 'tmeetic_ig_token_expiry',
|
||||||
'zone' => 'cold',
|
|
||||||
'cache_group' => 'wpdo_cold_hp_vendor',
|
|
||||||
'cache_ttl' => HOUR_IN_SECONDS,
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'post_type' => 'hp_vendor',
|
|
||||||
'meta_key' => 'tmeetic_ig_token_enc',
|
|
||||||
'zone' => 'cold',
|
|
||||||
'cache_group' => 'wpdo_cold_hp_vendor',
|
|
||||||
'cache_ttl' => HOUR_IN_SECONDS,
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'post_type' => 'hp_vendor',
|
|
||||||
'meta_key' => 'tmeetic_ig_token_expires_at',
|
|
||||||
'zone' => 'cold',
|
'zone' => 'cold',
|
||||||
'cache_group' => 'wpdo_cold_hp_vendor',
|
'cache_group' => 'wpdo_cold_hp_vendor',
|
||||||
'cache_ttl' => HOUR_IN_SECONDS,
|
'cache_ttl' => HOUR_IN_SECONDS,
|
||||||
@@ -116,6 +140,20 @@ final class TMDO_Infocards {
|
|||||||
'cache_group' => 'wpdo_cold_hp_vendor',
|
'cache_group' => 'wpdo_cold_hp_vendor',
|
||||||
'cache_ttl' => HOUR_IN_SECONDS,
|
'cache_ttl' => HOUR_IN_SECONDS,
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'post_type' => 'hp_vendor',
|
||||||
|
'meta_key' => 'tmeetic_ig_username',
|
||||||
|
'zone' => 'cold',
|
||||||
|
'cache_group' => 'wpdo_cold_hp_vendor',
|
||||||
|
'cache_ttl' => HOUR_IN_SECONDS,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'post_type' => 'hp_vendor',
|
||||||
|
'meta_key' => 'tmeetic_ig_feed_show',
|
||||||
|
'zone' => 'cold',
|
||||||
|
'cache_group' => 'wpdo_cold_hp_vendor',
|
||||||
|
'cache_ttl' => HOUR_IN_SECONDS,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -128,6 +166,9 @@ final class TMDO_Infocards {
|
|||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function register_custom_tables( TMDO_Custom_Table_Registry $registry ): void {
|
public static function register_custom_tables( TMDO_Custom_Table_Registry $registry ): void {
|
||||||
|
if ( ! self::partner_detected() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// CSS variable source — checked by WPDO doctor for index health.
|
// CSS variable source — checked by WPDO doctor for index health.
|
||||||
$registry->register(
|
$registry->register(
|
||||||
'2meet-infocards',
|
'2meet-infocards',
|
||||||
@@ -136,6 +177,27 @@ final class TMDO_Infocards {
|
|||||||
'primary_key' => 'vendor_id',
|
'primary_key' => 'vendor_id',
|
||||||
'post_type_link' => 'hp_vendor',
|
'post_type_link' => 'hp_vendor',
|
||||||
'doctor_callback' => array( __CLASS__, 'doctor_vendor_profiles' ),
|
'doctor_callback' => array( __CLASS__, 'doctor_vendor_profiles' ),
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'vendor_id' => 'BIGINT',
|
||||||
|
'primary_color' => 'VARCHAR',
|
||||||
|
'accent_color' => 'VARCHAR',
|
||||||
|
'bg_color' => 'VARCHAR',
|
||||||
|
'text_color' => 'VARCHAR',
|
||||||
|
'muted_color' => 'VARCHAR',
|
||||||
|
'font' => 'VARCHAR',
|
||||||
|
'radius_card' => 'INT',
|
||||||
|
'radius_btn' => 'INT',
|
||||||
|
'shadow_style' => 'VARCHAR',
|
||||||
|
'hero_image_id' => 'BIGINT',
|
||||||
|
'hero_fullwidth' => 'TINYINT',
|
||||||
|
'ig_feed_show' => 'TINYINT',
|
||||||
|
'theme_style_id' => 'BIGINT',
|
||||||
|
'updated_at' => 'DATETIME',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'vendor_id' => array( 'vendor_id' ),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$registry->register(
|
$registry->register(
|
||||||
@@ -144,6 +206,41 @@ final class TMDO_Infocards {
|
|||||||
'table_name' => '2meet_cards',
|
'table_name' => '2meet_cards',
|
||||||
'primary_key' => 'id',
|
'primary_key' => 'id',
|
||||||
'post_type_link' => 'hp_vendor',
|
'post_type_link' => 'hp_vendor',
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'page_id' => 'BIGINT',
|
||||||
|
'story_id' => 'BIGINT',
|
||||||
|
'epk_id' => 'BIGINT',
|
||||||
|
'card_type' => 'VARCHAR',
|
||||||
|
'title' => 'VARCHAR',
|
||||||
|
'description' => 'TEXT',
|
||||||
|
'image_id' => 'BIGINT',
|
||||||
|
'config' => 'TEXT',
|
||||||
|
'cta_text' => 'VARCHAR',
|
||||||
|
'cta_url' => 'VARCHAR',
|
||||||
|
'button_bg_color' => 'VARCHAR',
|
||||||
|
'button_text_color' => 'VARCHAR',
|
||||||
|
'sort_order' => 'INT',
|
||||||
|
'status' => 'VARCHAR',
|
||||||
|
'start_at' => 'DATETIME',
|
||||||
|
'end_at' => 'DATETIME',
|
||||||
|
'vendor_id' => 'BIGINT',
|
||||||
|
'show_click_count' => 'TINYINT',
|
||||||
|
'ab_enabled' => 'TINYINT',
|
||||||
|
'liff_enabled' => 'TINYINT',
|
||||||
|
'created_at' => 'DATETIME',
|
||||||
|
'updated_at' => 'DATETIME',
|
||||||
|
'click_count' => 'BIGINT',
|
||||||
|
'last_click_at' => 'DATETIME',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'page_id_status_sort' => array( 'page_id', 'status', 'sort_order' ),
|
||||||
|
'story_id_status_sort' => array( 'story_id', 'status', 'sort_order' ),
|
||||||
|
'epk_id_status_sort' => array( 'epk_id', 'status', 'sort_order' ),
|
||||||
|
'card_type' => array( 'card_type' ),
|
||||||
|
'vendor_status_sort' => array( 'vendor_id', 'status', 'sort_order' ),
|
||||||
|
'status_schedule' => array( 'status', 'start_at', 'end_at' ),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$registry->register(
|
$registry->register(
|
||||||
@@ -152,6 +249,19 @@ final class TMDO_Infocards {
|
|||||||
'table_name' => '2meet_theme_styles',
|
'table_name' => '2meet_theme_styles',
|
||||||
'primary_key' => 'id',
|
'primary_key' => 'id',
|
||||||
'post_type_link' => null,
|
'post_type_link' => null,
|
||||||
|
'expected_columns' => array(
|
||||||
|
'id' => 'BIGINT',
|
||||||
|
'name' => 'VARCHAR',
|
||||||
|
'slug' => 'VARCHAR',
|
||||||
|
'config' => 'TEXT',
|
||||||
|
'sort_order' => 'INT',
|
||||||
|
'is_active' => 'TINYINT',
|
||||||
|
'created_at' => 'DATETIME',
|
||||||
|
'updated_at' => 'DATETIME',
|
||||||
|
),
|
||||||
|
'indexes' => array(
|
||||||
|
'slug' => array( 'slug' ),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user