hardening 2.0: 2meet-data-optimizer (staged rollout, dev22 first) #3
@@ -54,7 +54,7 @@ final class TMDO_Hook_Bus_Bridge {
|
|||||||
if ( null !== self::$cache ) {
|
if ( null !== self::$cache ) {
|
||||||
return self::$cache;
|
return self::$cache;
|
||||||
}
|
}
|
||||||
$value = get_option( self::OPTION, '1' ); // Default ON as of v2.5.4.
|
$value = get_option( self::OPTION, '0' );
|
||||||
self::$cache = ( '1' === (string) $value || true === $value );
|
self::$cache = ( '1' === (string) $value || true === $value );
|
||||||
return self::$cache;
|
return self::$cache;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,47 +224,12 @@ class TMDO_Installer {
|
|||||||
add_option( 'wpdo_features', array(), '', 'no' );
|
add_option( 'wpdo_features', array(), '', 'no' );
|
||||||
}
|
}
|
||||||
|
|
||||||
// v2.5.4: one-time migration — enable Hook Bus + activate user/term/comment bridge.
|
|
||||||
self::maybe_autoactivate_entity_bridge();
|
|
||||||
|
|
||||||
// v2.15.0: one-time crypto migration — re-encrypt v1 CBC ciphertext as
|
// v2.15.0: one-time crypto migration — re-encrypt v1 CBC ciphertext as
|
||||||
// v2 GCM. Idempotent best-effort: skipped if no v1 ciphertext present
|
// v2 GCM. Idempotent best-effort: skipped if no v1 ciphertext present
|
||||||
// or if the migration flag is already set.
|
// or if the migration flag is already set.
|
||||||
self::maybe_migrate_crypto_v1_to_v2();
|
self::maybe_migrate_crypto_v1_to_v2();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* One-time migration: enable Hook Bus and set user/term/comment to dual_write.
|
|
||||||
*
|
|
||||||
* Runs once per site (guarded by wpdo_entity_bridge_autoactivated_v2 flag).
|
|
||||||
* Safe: dual_write still writes native EAV — zero data-loss risk.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private static function maybe_autoactivate_entity_bridge(): void {
|
|
||||||
if ( get_option( 'wpdo_entity_bridge_autoactivated_v2' ) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable Hook Bus.
|
|
||||||
update_option( 'wpdo_hook_bus_enabled', '1', false );
|
|
||||||
|
|
||||||
// Upgrade user/term/comment from disabled → dual_write.
|
|
||||||
$modes = get_option( 'wpdo_bridge_modes', array() );
|
|
||||||
if ( ! is_array( $modes ) ) {
|
|
||||||
$modes = array();
|
|
||||||
}
|
|
||||||
foreach ( array( 'user', 'term', 'comment' ) as $type ) {
|
|
||||||
if ( ! isset( $modes[ $type ] ) || 'disabled' === $modes[ $type ] ) {
|
|
||||||
$modes[ $type ] = 'dual_write';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// post entity is intentionally left alone — it uses the legacy Feature_Flags FSM.
|
|
||||||
update_option( 'wpdo_bridge_modes', $modes, false );
|
|
||||||
|
|
||||||
update_option( 'wpdo_entity_bridge_autoactivated_v2', '1', false );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One-time best-effort crypto migration v1 (CBC) → v2 (GCM) (v2.15.0).
|
* One-time best-effort crypto migration v1 (CBC) → v2 (GCM) (v2.15.0).
|
||||||
*
|
*
|
||||||
@@ -1303,7 +1268,10 @@ class TMDO_Installer {
|
|||||||
*/
|
*/
|
||||||
private static function run_dbdelta(): void {
|
private static function run_dbdelta(): void {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
// Same guard as install_v2_tables(): integration tests provide a stub dbDelta().
|
||||||
|
if ( ! function_exists( 'dbDelta' ) ) {
|
||||||
|
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
||||||
|
}
|
||||||
|
|
||||||
$charset = $wpdb->get_charset_collate();
|
$charset = $wpdb->get_charset_collate();
|
||||||
$p = $wpdb->prefix;
|
$p = $wpdb->prefix;
|
||||||
|
|||||||
@@ -65,16 +65,15 @@ final class TMDO_Mode_Manager {
|
|||||||
private static ?array $cache = null;
|
private static ?array $cache = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 預設模式(v2.5.4 起):
|
* 預設模式:全部 disabled,由管理者明確選擇後才啟用 entity bridge。
|
||||||
* post → disabled(由 Legacy Feature_Flags FSM 管理,不由 Mode_Manager 控制)
|
* 已存在 wpdo_bridge_modes 的站台(包含 aeav_only)以儲存值為準,不受影響。
|
||||||
* user / term / comment → dual_write(安全雙寫:寫入 flat table + 原生 EAV,讀取仍走 EAV)
|
|
||||||
*/
|
*/
|
||||||
private static function defaults(): array {
|
private static function defaults(): array {
|
||||||
return array(
|
return array(
|
||||||
'post' => self::MODE_DISABLED,
|
'post' => self::MODE_DISABLED,
|
||||||
'user' => self::MODE_DUAL_WRITE,
|
'user' => self::MODE_DISABLED,
|
||||||
'term' => self::MODE_DUAL_WRITE,
|
'term' => self::MODE_DISABLED,
|
||||||
'comment' => self::MODE_DUAL_WRITE,
|
'comment' => self::MODE_DISABLED,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,19 @@ class InstallerV2Test extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_install_does_not_enable_entity_bridge(): void {
|
||||||
|
delete_option( 'wpdo_hook_bus_enabled' );
|
||||||
|
delete_option( 'wpdo_bridge_modes' );
|
||||||
|
delete_option( 'wpdo_entity_bridge_autoactivated_v2' );
|
||||||
|
// Skip the crypto step: it queries $wpdb->options, which InstallerCleanupTest leaves pointing at its own prefix.
|
||||||
|
update_option( 'wpdo_crypto_migrated_v2', '1' );
|
||||||
|
|
||||||
|
TMDO_Installer::install();
|
||||||
|
|
||||||
|
$this->assertFalse( get_option( 'wpdo_hook_bus_enabled' ), 'install() must not switch the Hook Bus on' );
|
||||||
|
$this->assertFalse( get_option( 'wpdo_bridge_modes' ), 'install() must not write bridge modes' );
|
||||||
|
}
|
||||||
|
|
||||||
public static function tearDownAfterClass(): void {
|
public static function tearDownAfterClass(): void {
|
||||||
// Leave v2 tables in place for subsequent tests / dev convenience.
|
// Leave v2 tables in place for subsequent tests / dev convenience.
|
||||||
// Cleanup happens via wp wpdo cleanup-uae-tables --confirm in real upgrades.
|
// Cleanup happens via wp wpdo cleanup-uae-tables --confirm in real upgrades.
|
||||||
|
|||||||
@@ -302,6 +302,7 @@ if ( ! function_exists( 'wp_strip_all_tags' ) ) { function wp_strip_all_tags( st
|
|||||||
if ( ! function_exists( 'get_option' ) ) { function get_option( string $key, $default = false ) { return $GLOBALS['_wp_options'][ $key ] ?? $default; } }
|
if ( ! function_exists( 'get_option' ) ) { function get_option( string $key, $default = false ) { return $GLOBALS['_wp_options'][ $key ] ?? $default; } }
|
||||||
if ( ! function_exists( 'update_option' ) ) { function update_option( string $key, $value ): bool { $GLOBALS['_wp_options'][ $key ] = $value; return true; } }
|
if ( ! function_exists( 'update_option' ) ) { function update_option( string $key, $value ): bool { $GLOBALS['_wp_options'][ $key ] = $value; return true; } }
|
||||||
if ( ! function_exists( 'delete_option' ) ) { function delete_option( string $key ): bool { unset( $GLOBALS['_wp_options'][ $key ] ); return true; } }
|
if ( ! function_exists( 'delete_option' ) ) { function delete_option( string $key ): bool { unset( $GLOBALS['_wp_options'][ $key ] ); return true; } }
|
||||||
|
if ( ! function_exists( 'add_option' ) ) { function add_option( string $key, $value = '', $deprecated = '', $autoload = null ): bool { if ( array_key_exists( $key, $GLOBALS['_wp_options'] ?? array() ) ) { return false; } $GLOBALS['_wp_options'][ $key ] = $value; return true; } }
|
||||||
if ( ! function_exists( 'get_transient' ) ) { function get_transient( string $key ) { return $GLOBALS['_wp_transients'][ $key ] ?? false; } }
|
if ( ! function_exists( 'get_transient' ) ) { function get_transient( string $key ) { return $GLOBALS['_wp_transients'][ $key ] ?? false; } }
|
||||||
if ( ! function_exists( 'set_transient' ) ) { function set_transient( string $key, $value, int $exp = 0 ): bool { $GLOBALS['_wp_transients'][ $key ] = $value; return true; } }
|
if ( ! function_exists( 'set_transient' ) ) { function set_transient( string $key, $value, int $exp = 0 ): bool { $GLOBALS['_wp_transients'][ $key ] = $value; return true; } }
|
||||||
if ( ! function_exists( 'delete_transient' ) ) { function delete_transient( string $key ): bool { unset( $GLOBALS['_wp_transients'][ $key ] ); return true; } }
|
if ( ! function_exists( 'delete_transient' ) ) { function delete_transient( string $key ): bool { unset( $GLOBALS['_wp_transients'][ $key ] ); return true; } }
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ class HookBusBridgeTest extends TestCase {
|
|||||||
|
|
||||||
// ── is_enabled() ────────────────────────────────────────────────────────
|
// ── is_enabled() ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
public function test_is_enabled_default_true(): void {
|
public function test_is_enabled_default_false(): void {
|
||||||
// v2.5.4: Hook Bus is ON by default; option not set → true.
|
// Hook Bus is opt-in; option not set → false. Existing sites store '1' explicitly.
|
||||||
$this->assertTrue( WPDO_Hook_Bus_Bridge::is_enabled() );
|
$this->assertFalse( WPDO_Hook_Bus_Bridge::is_enabled() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_is_enabled_when_option_set_to_string_one(): void {
|
public function test_is_enabled_when_option_set_to_string_one(): void {
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test: TMDO_Mode_Manager defaults.
|
||||||
|
*
|
||||||
|
* A fresh install must not route any entity through the flat tables until an
|
||||||
|
* admin opts in; stored modes (e.g. aeav_only on live sites) must be kept as-is.
|
||||||
|
*/
|
||||||
|
class ModeManagerDefaultsTest extends TestCase {
|
||||||
|
|
||||||
|
protected function setUp(): void {
|
||||||
|
$GLOBALS['_wp_options'] = array();
|
||||||
|
TMDO_Mode_Manager::reset_cache();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void {
|
||||||
|
TMDO_Mode_Manager::reset_cache();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_all_entities_default_to_disabled(): void {
|
||||||
|
$this->assertSame(
|
||||||
|
array(
|
||||||
|
'post' => TMDO_Mode_Manager::MODE_DISABLED,
|
||||||
|
'user' => TMDO_Mode_Manager::MODE_DISABLED,
|
||||||
|
'term' => TMDO_Mode_Manager::MODE_DISABLED,
|
||||||
|
'comment' => TMDO_Mode_Manager::MODE_DISABLED,
|
||||||
|
),
|
||||||
|
TMDO_Mode_Manager::all()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_stored_modes_are_kept(): void {
|
||||||
|
update_option(
|
||||||
|
'wpdo_bridge_modes',
|
||||||
|
array(
|
||||||
|
'post' => 'aeav_only',
|
||||||
|
'user' => 'dual_write',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$modes = TMDO_Mode_Manager::all();
|
||||||
|
|
||||||
|
$this->assertSame( 'aeav_only', $modes['post'] );
|
||||||
|
$this->assertSame( 'dual_write', $modes['user'] );
|
||||||
|
$this->assertSame( TMDO_Mode_Manager::MODE_DISABLED, $modes['term'] );
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user