Skip to content
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ To confirm the ID for the site you want to query, you can use the `wp site list`
Exports the database to a file or to STDOUT.

~~~
wp db export [<file>] [--dbuser=<value>] [--dbpass=<value>] [--<field>=<value>] [--tables=<tables>] [--exclude_tables=<tables>] [--include-tablespaces] [--porcelain] [--defaults]
wp db export [<file>] [--dbuser=<value>] [--dbpass=<value>] [--<field>=<value>] [--tables=<tables>] [--exclude_tables=<tables>] [--exclude_tables_data=<tables>] [--include-tablespaces] [--porcelain] [--defaults]
~~~

**Alias:** `dump`
Expand Down Expand Up @@ -467,6 +467,10 @@ Runs `mysqldump` utility using `DB_HOST`, `DB_NAME`, `DB_USER` and
[--exclude_tables=<tables>]
The comma separated list of specific tables that should be skipped from exporting. Excluding this parameter will export all tables in the database.

[--exclude_tables_data=<tables>]
The comma separated list of specific tables for which only the structure will be exported. Excluding this parameter will export data for all tables in the export.
Note: currently only supported by MariaDB.

[--include-tablespaces]
Skips adding the default --no-tablespaces option to mysqldump.

Expand Down Expand Up @@ -514,6 +518,10 @@ Runs `mysqldump` utility using `DB_HOST`, `DB_NAME`, `DB_USER` and
$ wp db export --exclude_tables=$(wp db tables --all-tables-with-prefix --format=csv)
Success: Exported to 'wordpress_dbase-db72bb5.sql'.

# Skip data of certain tables from the exported database
$ wp db export --exclude_tables_data=wp_actionscheduler_logs
Success: Exported to 'wordpress_dbase-db72bb5.sql'.

# Export database to STDOUT.
$ wp db export -
-- MySQL dump 10.13 Distrib 5.7.19, for osx10.12 (x86_64)
Expand Down
27 changes: 27 additions & 0 deletions features/db-export.feature
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,33 @@ Feature: Export a WordPress database
PRAGMA foreign_keys=OFF
"""

@skip-mariadb @skip-sqlite
Scenario: Exclude data of certain tables is not supported by MySQL
Given a WP install

When I try `wp db export wp_cli_test.sql --exclude_tables_data=wp_users`
Then the return code should be 1
And STDERR should contain:
"""
Error: The --exclude_tables_data option is only supported by MariaDB.
"""

# Only MariaDB currently supports this feature.
@require-mariadb
Scenario: Exclude data of certain tables when exporting the database
Given a WP install

When I run `wp db export wp_cli_test.sql --exclude_tables_data=wp_users --porcelain`
Then the wp_cli_test.sql file should exist
And the wp_cli_test.sql file should contain:
"""
wp_users
"""
And the wp_cli_test.sql file should not contain:
"""
INSERT INTO `wp_users`
"""

@skip-sqlite
Scenario: Export database to STDOUT
Given a WP install
Expand Down
28 changes: 28 additions & 0 deletions src/DB_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,10 @@ public function query( $args, $assoc_args ) {
* [--exclude_tables=<tables>]
* : The comma separated list of specific tables that should be skipped from exporting. Excluding this parameter will export all tables in the database.
*
* [--exclude_tables_data=<tables>]
* : The comma separated list of specific tables for which only the structure will be exported. Excluding this parameter will export data for all tables in the export.
* Note: currently only supported by MariaDB.
*
Comment on lines +687 to +690

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate files =="
git ls-files | rg '(^|/)DB_Command\.php$|(^|/)README\.md$' || true

echo
echo "== relevant mentions of exclude_tables_data and MariaDB minimum/version =="
rg -n --hidden --glob '!vendor/**' --glob '!node_modules/**' \
  'exclude_tables_data|MariaDB|10\.1|10|11|version' \
  src/DB_Command.php README.md 2>/dev/null || true

echo
echo "== DB_Command.php context =="
sed -n '660,715p' src/DB_Command.php 2>/dev/null || true

echo
echo "== README.md context =="
sed -n '455,485p' README.md 2>/dev/null || true

Repository: wp-cli/db-command

Length of output: 8057


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== all repository references to MariaDB 10.1/10.1 minimum and export include/exclude =="
rg -n --hidden --glob '!vendor/**' --glob '!node_modules/**' \
  'MariaDB\s*(10\.1|10|11)|10\.1\s*MariaDB|mariadb|MariaDB \d+\.\d+|export|--include_tables|--exclude_tables' .

echo
echo "== DB_Command.php outline around DB export methods =="
ast-grep outline src/DB_Command.php --match 'export' --view expanded 2>/dev/null || true

Repository: wp-cli/db-command

Length of output: 16553


🌐 Web query:

MariaDB 10.1 SET export documentation --set-gtid-purged

💡 Result:

The MariaDB mysqldump utility does not support the --set-gtid-purged flag [1][2][3]. This flag is specific to the MySQL mysqldump implementation [1]. If you attempt to use --set-gtid-purged=OFF (or any other value) with MariaDB's mysqldump, the command will fail with an error stating that it is an "unknown variable" [4][2][3]. This incompatibility arises because MariaDB and MySQL use different, non-compatible implementations for Global Transaction IDs (GTIDs) [1][5][6]. Consequently, the options related to GTIDs in the MySQL version of mysqldump do not exist in the MariaDB version [1]. If you encounter this error in automation scripts or build tools (such as Laravel or custom shell scripts), the correct solution is to remove the --set-gtid-purged flag from your mysqldump command [1][7][2][3].

Citations:


🌐 Web query:

MariaDB server options documentation --set-gtid-purged --skip-set-gtid-purged MariaDB 10.1

💡 Result:

The command-line options --set-gtid-purged and --skip-set-gtid-purged do not exist in the MariaDB version of mysqldump, including in MariaDB 10.1 [1][2][3]. These options are specific to the MySQL implementation of mysqldump [4][1]. Because MariaDB's GTID implementation differs from MySQL's, MariaDB does not support these flags [1]. Attempting to use them with a MariaDB-provided mysqldump client will result in an "unknown variable" error and the command will fail [2][5][3][6]. If you encounter this error (common when using tools designed for MySQL against a MariaDB client environment), the correct solution is to remove these flags from your command-line arguments [1][7][3]. MariaDB uses its own methods and options for managing GTIDs during backups and replication, such as the --gtid option [8][9].

Citations:


🌐 Web query:

site:Mariadb.com mysqldump SET_SESSION_GTID_PRUNE MariaDB mysqldump options MariaDB 10.1 exclude tables data structure only

💡 Result:

The command formerly known as mysqldump is now called mariadb-dump in MariaDB, though mysqldump remains accessible as a symbolic link in many versions [1][2]. Regarding your specific queries: SET_SESSION_GTID_PRUNE There is no standard mysqldump or mariadb-dump option named SET_SESSION_GTID_PRUNE. MariaDB manages GTID-based replication using options like --gtid, which, when combined with --master-data or --dump-slave, automatically includes necessary SQL statements (such as setting gtid_slave_pos and executing CHANGE MASTER) to configure a replica [3][4][5]. If you encounter SET_SESSION_GTID_PRUNE, it is likely a non-standard or custom session variable; standard session variables are managed via the SET statement in SQL [6]. Exclude tables To exclude specific tables when using mariadb-dump (or mysqldump), use the --ignore-table option. You must specify the table in the format db_name.table_name. You can use this option multiple times to exclude multiple tables: mariadb-dump --ignore-table=database_name.table_name1 --ignore-table=database_name.table_name2 database_name > backup.sql Data structure only To export only the database structure (schema) without table data, use the --no-data option [7][8]: mariadb-dump --no-data database_name > schema_backup.sql Combining these, to dump the structure of a database while excluding specific tables: mariadb-dump --no-data --ignore-table=db.table1 --ignore-table=db.table2 db_name > schema_only_exclude_tables.sql

Citations:


🌐 Web query:

"exclude_tables_data" "MariaDB" "10.1" "10" "11"

💡 Result:

In MariaDB, the --ignore-table-data option is the specific command-line argument used to exclude the data (contents) of a table from a backup while still exporting its structure [1][2][3]. Usage Requirements The option requires the full format of database_name.table_name [1][2]. If you need to exclude data for multiple tables, you must repeat the --ignore-table-data option for each table [1][3]. Example To back up a database named my_database while excluding data from tables named table1 and table2: mariadb-dump my_database --ignore-table-data=my_database.table1 --ignore-table-data=my_database.table2 > backup.sql Version Compatibility This option is a feature specific to MariaDB's dump utility and is not available in standard MySQL mysqldump [4]. It was introduced in the following MariaDB releases: - MariaDB 10.1.46 and later [2][3] - MariaDB 10.2.33 and later [2][3] - MariaDB 10.3.24 and later [2][3] - MariaDB 10.4.14 and later [2][3] - MariaDB 10.5.3 and later [2][3] For versions of MariaDB newer than 10.5.3, including 10.11, this option remains available and is the standard way to perform this task [1][5]. If you encounter an error when using this command, ensure you are using the MariaDB-provided version of the dump utility (mariadb-dump or mysqldump) rather than a client bundled with a different MySQL distribution [4].

Citations:


Include the MariaDB 10.1 minimum for --exclude_tables_data.

Both src/DB_Command.php and README.md say the option is available only for MariaDB but omit the minimum version. Add the same MariaDB 10.1 and later wording to both references.

📍 Affects 2 files
  • src/DB_Command.php#L687-L690 (this comment)
  • README.md#L470-L472
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/DB_Command.php` around lines 687 - 690, Update the --exclude_tables_data
documentation in src/DB_Command.php lines 687-690 and README.md lines 470-472 to
state that the option is supported by MariaDB 10.1 and later, using consistent
wording in both references.

Source: Coding guidelines

* [--include-tablespaces]
* : Skips adding the default --no-tablespaces option to mysqldump.
*
Expand Down Expand Up @@ -731,6 +735,10 @@ public function query( $args, $assoc_args ) {
* $ wp db export --exclude_tables=$(wp db tables --all-tables-with-prefix --format=csv)
* Success: Exported to 'wordpress_dbase-db72bb5.sql'.
*
* # Skip data of certain tables from the exported database
* $ wp db export --exclude_tables_data=wp_actionscheduler_logs
* Success: Exported to 'wordpress_dbase-db72bb5.sql'.
*
* # Export database to STDOUT.
* $ wp db export -
* -- MySQL dump 10.13 Distrib 5.7.19, for osx10.12 (x86_64)
Expand Down Expand Up @@ -835,6 +843,26 @@ public function export( $args, $assoc_args ) {
}
}

$exclude_tables_data = Utils\get_flag_value( $assoc_args, 'exclude_tables_data', '' );
if ( ! empty( $exclude_tables_data ) ) {
unset( $assoc_args['exclude_tables_data'] );

if ( 'mariadb' !== Utils\get_db_type() ) {
WP_CLI::error( 'The --exclude_tables_data option is only supported by MariaDB.' );
}

$tables = explode( ',', trim( $exclude_tables_data, ',' ) );
foreach ( $tables as $table ) {
$table = trim( $table );
if ( '' === $table ) {
continue;
Comment on lines +846 to +858

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 8 'function\s+get_flag_value\b|\bget_flag_value\s*\(' \
  --glob '*.php' .

Repository: wp-cli/db-command

Length of output: 19796


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Locate Utils and get_flag_value definition.
fd -a 'Utils.*\.php|class Utils|function get_flag_value' . | sed 's#^\./##'

rg -n -C 12 'public static function get_flag_value|function get_flag_value|get_flag_value' vendor wp-includes wp-cli . 2>/dev/null | head -200

Repository: wp-cli/db-command

Length of output: 12383


🌐 Web query:

WP_CLI Utils get_flag_value implementation return type

💡 Result:

The WP-CLI function WP_CLI\Utils\get_flag_value returns a mixed type, specifically defined in its PHPDoc as string|bool|int|null [1][2][3]. The function is implemented as a simple conditional return that checks if a flag exists within the provided associative arguments array ($assoc_args); if the flag is present, it returns that value, and if not, it returns the provided $default value [1][4][3]: function get_flag_value( $assoc_args, $flag, $default = null) { return isset( $assoc_args[ $flag ])? $assoc_args[ $flag ]: $default; } Because the $default parameter defaults to null [1][3], the function effectively returns the type of the value stored in the arguments array (typically string, bool, or int) or the type of the $default value provided by the caller [1][2]. It is intended as a safer alternative to manual isset checks on arguments arrays, particularly because it helps handle negated flags (e.g., --no-quiet) [1][4].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Inspect the current export path around MariaDB handling and the SQL dump command.
sed -n '730,890p' src/DB_Command.php -n

# Behavioral probe for the current `empty()`/`trim()` decision table using PHP available in the sandbox.
php -r '
$values = [
  "missing" => null,
  "empty string" => "",
  "true flag" => true,
  "false flag" => false,
  "numeric" => 123,
  "empty array" => [],
];
echo "PHP version: ", PHP_VERSION, "\n";
foreach ( $values as $name => $value ) {
  $unset_called = false;
  if ( ! empty( $value ) ) {
    $unset_called = true;
    echo "SKIP ", $name, " (", gettype( $value ), ") has unset: ", var_export( $unset_called, true ), "\n";
  } else {
    echo "SKIP ", $name, " (", gettype( $value ), ") has unset: ", var_export( $unset_called, true ), "\n";
  }
  if ( ! empty( $value ) ) {
    try {
      echo "  trim result: ", var_export( trim( $value, "," ), true ), "\n";
    } catch ( \TypeError $e ) {
      echo "  trim type error: " . $e->getMessage() . "\n";
    }
  }
}
'

Repository: wp-cli/db-command

Length of output: 6086


🏁 Script executed:

#!/usr/bin/env bash
set- euo pipefail

# Inspect run() method and get_defaults_flag_string for remaining assoc_args forwarding.
rg -n -C 12 'self::run\s*\(|protected static function run|private static function run|\$assoc_args|get_defaults_flag_string' src/DB_Command.php

# Read relevant ranges if present.
sed -n '100,220p' src/DB_Command.php | cat -n
sed -n '2330,2395p' src/DB_Command.php | cat -n

Repository: wp-cli/db-command

Length of output: 50373


🌐 Web query:

WP_CLI run_mysql_command assoc_args implementation

💡 Result:

In WP-CLI, run_mysql_command is an internal utility function located in the php/utils.php file, designed to execute a MySQL command and handle the communication of arguments to the underlying process [1][2][3]. The function signature is: run_mysql_command( $cmd, $assoc_args, $_ = null, $send_to_shell = true, $interactive = false ) Implementation Details: 1. Associative Arguments Processing: The $assoc_args parameter is an associative array of key-value pairs representing the flags to be passed to the MySQL command (e.g., --host, --user, --password) [1][2]. 2. Handling Specific Arguments: - Host: If host is present in $assoc_args, the function merges it with specific CLI arguments using mysql_host_to_cli_args() [1][2]. - Password: If pass is present, the function securely sets the MYSQL_PWD environment variable for the process execution to avoid passing passwords directly in the command string, and restores the previous environment value afterward [1][2]. 3. Command Construction: The function uses assoc_args_to_str( $assoc_args ) to convert the associative array into a formatted string of CLI arguments, which is then appended to the base command $cmd [4][1][2]. 4. Process Execution: The constructed command is executed using proc_open_compat(). Depending on the parameters, it either redirects output to the shell ($send_to_shell) or captures it via pipes ($stdout, $stderr) [1][2]. In the context of WP-CLI command development, assoc_args typically refers to the associative array passed to your command callback, which contains flags parsed from the terminal (e.g., --key=value or --flag). This $assoc_args array is then passed to run_mysql_command to ensure the correct options are utilized when the database command is invoked [5][6].

Citations:


Remove and normalize exclude_tables_data before trimming.

Utils\get_flag_value() can return non-string values; non-empty flags or integers currently reach trim() and become numeric ignore-table values. An empty --exclude_tables_data or the SQLite return path also leaves the key in assoc_args until self::run(), where it can be forwarded to the dump command. Read and unset the key unconditionally, then reject non-string values before calling trim() on CSV content.

🧰 Tools
🪛 PHPStan (2.2.7)

[error] 854-854: Parameter #1 $string of function trim expects string, mixed given.

(argument.type)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/DB_Command.php` around lines 846 - 858, Update the exclude_tables_data
handling in the command method to read and unset
assoc_args['exclude_tables_data'] unconditionally before validation or trimming.
Reject non-string values, including empty or numeric inputs, before processing
CSV content; only trim and split valid strings, while preserving the MariaDB
support check and preventing the option from reaching self::run().

Source: Linters/SAST tools

}
$command .= ' --ignore-table-data';
$command .= ' %s';
$command_esc_args[] = DB_NAME . '.' . $table;
}
}

$escaped_command = Utils\esc_cmd( $command, ...$command_esc_args );

// Remove parameters not needed for SQL run.
Expand Down