Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ and the [CLI-first benchmark requirements](tests/bench/README.md#priorities-and-
MDI selects its backend in `wp-content/db.php` before plugins load:

- An explicit `MARKDOWN_DB_BACKEND` configuration always wins.
- Without one, an existing SQLite database (`FQDB`, when it names a file, or
`wp-content/database/.ht.sqlite`) keeps the SQLite backend so an upgrade does
not change an operating site's query engine.
- Without one, an existing SQLite database or managed `db-path.php` file keeps
the SQLite backend so an upgrade does not change an operating site's query
engine. Discovery honors `DB_PATH` before legacy settings and recognizes
legacy `.ht.sqlite` and `.ht.sqlite.php` files. It does not create or migrate
a database.
- Otherwise, MDI selects **`mdi-native`**, where canonical Markdown and JSON
files are the database.

Expand Down
153 changes: 103 additions & 50 deletions db.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,36 @@ function markdown_database_integration_configured_backend(): string {
if ( defined( 'MARKDOWN_DB_BACKEND' ) ) {
return (string) MARKDOWN_DB_BACKEND;
}
if ( defined( 'FQDB' ) && is_file( FQDB ) ) {
if ( defined( 'DB_PATH' ) || defined( 'FQDB' ) ) {
$path = defined( 'DB_PATH' ) ? DB_PATH : FQDB;
return is_string( $path ) && is_file( $path ) ? 'sqlite' : 'mdi-native';
}

$directory = markdown_database_integration_sqlite_directory();
if ( defined( 'DB_FILE' ) ) {
return is_file( $directory . DB_FILE ) ? 'sqlite' : 'mdi-native';
}

// Handle the randomized secret database path.
if ( is_file( $directory . 'db-path.php' ) ) {
return 'sqlite';
}
return is_file( __DIR__ . '/database/.ht.sqlite' ) ? 'sqlite' : 'mdi-native';
return is_file( $directory . '.ht.sqlite' ) || is_file( $directory . '.ht.sqlite.php' ) ? 'sqlite' : 'mdi-native';
}
}

if ( ! function_exists( 'markdown_database_integration_sqlite_directory' ) ) {
/** Resolve the SQLite storage directory before integration constants load. */
function markdown_database_integration_sqlite_directory(): string {
if ( defined( 'FQDBDIR' ) ) {
$directory = FQDBDIR;
} elseif ( defined( 'DB_DIR' ) ) {
$directory = DB_DIR;
} else {
$directory = defined( 'WP_CONTENT_DIR' ) ? WP_CONTENT_DIR : __DIR__;
$directory .= '/database';
}
return rtrim( $directory, '/\\' ) . '/';
}
}

Expand Down Expand Up @@ -326,12 +352,13 @@ function markdown_database_integration_primary_index_path( string $content_dir,
define( 'WP_SQLITE_AST_DRIVER', true );
}

// Primary mode uses markdown-index.sqlite as the active query engine. The
// SQLite Integration install shim opens FQDB directly during wp_install(). Only
// point FQDB at the markdown index when the markdown store already represents an
// Primary mode uses markdown-index.sqlite as the active query engine.
// Only point the SQLite installation shim at the index when the store represents an
// installed site. Partial seed stores fall back to the existing SQLite database
// so already-installed Playground sites do not reset to the install screen.
if ( defined( 'MARKDOWN_DB_MODE' ) && 'primary' === MARKDOWN_DB_MODE ) {
$markdown_db_primary = defined( 'MARKDOWN_DB_MODE' ) && 'primary' === MARKDOWN_DB_MODE;
$markdown_db_install_fallback = false;
if ( $markdown_db_primary ) {
$markdown_db_content_dir = defined( 'MARKDOWN_DB_CONTENT_DIR' )
? MARKDOWN_DB_CONTENT_DIR
: markdown_db_default_content_dir();
Expand All @@ -353,6 +380,37 @@ function markdown_database_integration_primary_index_path( string $content_dir,
if ( ! defined( 'FQDB' ) ) {
define( 'FQDB', MARKDOWN_DB_INDEX_PATH );
}
} else {
$markdown_db_install_fallback = true;
if ( ! defined( 'MARKDOWN_DB_INSTALL_FALLBACK' ) ) {
define( 'MARKDOWN_DB_INSTALL_FALLBACK', true );
}
}
}

// Select configured paths before older integrations define FQDB by default.
$markdown_db_sqlite_storage_file = $sqlite_plugin_implementation_folder_path . '/wp-includes/sqlite/class-wp-sqlite-storage.php';
$markdown_db_sqlite_path = null;
if ( defined( 'DB_PATH' ) ) {
$markdown_db_sqlite_path = DB_PATH;
} elseif ( defined( 'FQDB' ) ) {
$markdown_db_sqlite_path = FQDB;
} elseif ( defined( 'DB_FILE' ) ) {
$markdown_db_sqlite_path = markdown_database_integration_sqlite_directory() . DB_FILE;
} elseif ( ! is_file( $markdown_db_sqlite_storage_file ) ) {
$markdown_db_sqlite_path = markdown_database_integration_sqlite_directory() . '.ht.sqlite';
if ( ! is_file( $markdown_db_sqlite_path ) && is_file( $markdown_db_sqlite_path . '.php' ) ) {
$markdown_db_sqlite_path .= '.php';
}
}

// Older integrations read the legacy constants instead of DB_PATH.
if ( null !== $markdown_db_sqlite_path ) {
if ( ! defined( 'FQDB' ) ) {
define( 'FQDB', $markdown_db_sqlite_path );
}
if ( ! defined( 'FQDBDIR' ) && ':memory:' !== $markdown_db_sqlite_path ) {
define( 'FQDBDIR', rtrim( dirname( $markdown_db_sqlite_path ), '/\\' ) . '/' );
}
}

Expand All @@ -368,6 +426,11 @@ function markdown_database_integration_primary_index_path( string $content_dir,
// Load the SQLite v2 driver stack (parser, lexer, connection, driver).
require_once $sqlite_plugin_implementation_folder_path . '/wp-includes/database/load.php';

// Load SQLite storage support when available.
if ( is_file( $markdown_db_sqlite_storage_file ) ) {
require_once $markdown_db_sqlite_storage_file;
}

// SQLite Integration renamed the canonical PDO driver after its latest release.
if ( ! class_exists( 'WP_MySQL_On_SQLite', false ) ) {
if ( class_exists( 'WP_PDO_MySQL_On_SQLite', false ) ) {
Expand All @@ -386,24 +449,6 @@ class_alias( 'WP_PDO_MySQL_On_SQLite', 'WP_MySQL_On_SQLite' );
require_once $sqlite_plugin_implementation_folder_path . '/wp-includes/sqlite/class-wp-sqlite-db.php';
require_once $sqlite_plugin_implementation_folder_path . '/wp-includes/sqlite/install-functions.php';

if ( defined( 'MARKDOWN_DB_MODE' ) && 'primary' === MARKDOWN_DB_MODE ) {
$markdown_db_content_dir = defined( 'MARKDOWN_DB_CONTENT_DIR' )
? MARKDOWN_DB_CONTENT_DIR
: markdown_db_default_content_dir();
$markdown_db_state_dir = defined( 'MARKDOWN_DB_STATE_DIR' )
? MARKDOWN_DB_STATE_DIR
: $markdown_db_content_dir;

if ( ! markdown_database_integration_store_has_siteurl( $markdown_db_state_dir ) ) {
if ( ! defined( 'MARKDOWN_DB_INSTALL_FALLBACK' ) ) {
define( 'MARKDOWN_DB_INSTALL_FALLBACK', true );
}
$db_name = defined( 'DB_NAME' ) && '' !== DB_NAME ? DB_NAME : 'database_name_here';
$GLOBALS['wpdb'] = new WP_SQLite_DB( $db_name );
return;
}
}

// Load our markdown classes.
$markdown_plugin_dir = null;

Expand All @@ -420,32 +465,46 @@ class_alias( 'WP_PDO_MySQL_On_SQLite', 'WP_MySQL_On_SQLite' );
}
}

// If the markdown plugin isn't installed yet, fall back to standard SQLite.
if ( ! $markdown_plugin_dir ) {
// Fallback: standard SQLite behavior.
if ( defined( 'DB_NAME' ) && '' !== DB_NAME ) {
$db_name = DB_NAME;
} else {
$db_name = 'database_name_here';
$markdown_db_sqlite_fallback = $markdown_db_install_fallback || ! $markdown_plugin_dir;

if ( ! $markdown_db_sqlite_fallback ) {
// MDI is storage-only; content-format dependencies belong to the application.
$composer_autoload = $markdown_plugin_dir . '/vendor/autoload.php';
if ( file_exists( $composer_autoload ) ) {
require_once $composer_autoload;
}
$GLOBALS['wpdb'] = new WP_SQLite_DB( $db_name );
return;

require_once $markdown_plugin_dir . '/inc/class-wp-markdown-backend-capabilities.php';
$markdown_db_backend = WP_Markdown_Backend_Resolver::configure_from_globals();
WP_Markdown_Backend_Resolver::require_runtime_capabilities(
$markdown_db_backend,
defined( 'MARKDOWN_DB_MODE' ) ? (string) MARKDOWN_DB_MODE : 'mirror'
);
}

// Primary mode creates its index during reconstruction, after storage is loaded.
if ( class_exists( 'WP_SQLite_Storage' ) && ( ! $markdown_db_primary || $markdown_db_sqlite_fallback ) ) {
$storage = null !== $markdown_db_sqlite_path
? WP_SQLite_Storage::with_explicit_path( $markdown_db_sqlite_path )
: WP_SQLite_Storage::with_secret_path( FQDBDIR );
$markdown_db_sqlite_path = $storage->initialize();
if ( ! defined( 'FQDB' ) ) {
define( 'FQDB', $markdown_db_sqlite_path );
}
}
if ( ! defined( 'DB_PATH' ) ) {
define( 'DB_PATH', $markdown_db_sqlite_path );
}

// Load composer autoloader if present. MDI is storage-only; content-format
// dependencies belong to the application layer above this drop-in.
$composer_autoload = $markdown_plugin_dir . '/vendor/autoload.php';
if ( file_exists( $composer_autoload ) ) {
require_once $composer_autoload;
$db_name = defined( 'DB_NAME' ) && '' !== DB_NAME ? DB_NAME : 'database_name_here';

// Use standard SQLite for installation or when the markdown plugin is missing.
if ( $markdown_db_sqlite_fallback ) {
$GLOBALS['wpdb'] = new WP_SQLite_DB( $db_name );
return;
}

// Load markdown integration classes.
require_once $markdown_plugin_dir . '/inc/class-wp-markdown-backend-capabilities.php';
$markdown_db_backend = WP_Markdown_Backend_Resolver::configure_from_globals();
WP_Markdown_Backend_Resolver::require_runtime_capabilities(
$markdown_db_backend,
defined( 'MARKDOWN_DB_MODE' ) ? (string) MARKDOWN_DB_MODE : 'mirror'
);
require_once $markdown_plugin_dir . '/inc/class-wp-markdown-frontmatter-profiles.php';
require_once $markdown_plugin_dir . '/inc/class-wp-markdown-content-layout-profiles.php';
if ( defined( 'MARKDOWN_DB_CONTENT_LAYOUT_PROFILE_BOOTSTRAP' ) && is_file( MARKDOWN_DB_CONTENT_LAYOUT_PROFILE_BOOTSTRAP ) ) {
Expand All @@ -466,12 +525,6 @@ class_alias( 'WP_PDO_MySQL_On_SQLite', 'WP_MySQL_On_SQLite' );
}

// Create the database connection — our WP_Markdown_DB extends WP_SQLite_DB.
if ( defined( 'DB_NAME' ) && '' !== DB_NAME ) {
$db_name = DB_NAME;
} else {
$db_name = 'database_name_here';
}

$GLOBALS['wpdb'] = new WP_Markdown_DB( $db_name );
markdown_database_integration_enable_native_shadow( $GLOBALS['wpdb'], $markdown_plugin_dir );

Expand Down
11 changes: 7 additions & 4 deletions inc/class-wp-markdown-db.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ public function db_connect( $allow_bail = true ) {
$pdo = null;
} else {
// Phase 1 / mirror: use on-disk SQLite file.
$db_path = FQDB;
$this->ensure_database_directory_exists();
$db_path = defined( 'DB_PATH' ) ? DB_PATH : FQDB;
$this->ensure_database_directory_exists( $db_path );
}

// Create the markdown storage engine.
Expand Down Expand Up @@ -674,8 +674,11 @@ private function ensure_directory_exists( string $dir ): void {
/**
* Ensure the SQLite database directory exists with protections.
*/
private function ensure_database_directory_exists(): void {
$dir = dirname( FQDB );
private function ensure_database_directory_exists( string $db_path ): void {
if ( ':memory:' === $db_path ) {
return;
}
$dir = dirname( $db_path );
$this->ensure_directory_exists( $dir );

// .htaccess protection.
Expand Down
5 changes: 3 additions & 2 deletions inc/sqlite/class-wp-markdown-sqlite-runtime-adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,14 @@ public function __construct(
WP_Markdown_Storage $storage,
?WP_Markdown_Backend_Capabilities $backend_capabilities = null
) {
$pdo_option = defined( 'MARKDOWN_DB_SQLITE_LEGACY_RESULT_API' ) && MARKDOWN_DB_SQLITE_LEGACY_RESULT_API ? 'pdo' : 'sqlite_pdo';
parent::__construct(
sprintf( 'mysql-on-sqlite:dbname=%s', $database ),
null,
null,
array(
'pdo' => $connection->get_pdo(),
'journal_mode' => $connection->get_pdo()->query( 'PRAGMA journal_mode' )->fetchColumn(),
$pdo_option => $connection->get_pdo(),
'sqlite_journal_mode' => $connection->get_pdo()->query( 'PRAGMA journal_mode' )->fetchColumn(),
)
);
$connection->get_pdo()->setAttribute( PDO::ATTR_STRINGIFY_FETCHES, true );
Expand Down
Loading