File: //usr/local/wp/vendor/wp-cli/entity-command/src/Site_Option_Command.php
<?php
use WP_CLI\Formatter;
use WP_CLI\Traverser\RecursiveDataStructureTraverser;
use WP_CLI\Utils;
/**
* Adds, updates, deletes, and lists site options in a multisite installation.
*
* ## EXAMPLES
*
* # Get site registration
* $ wp site option get registration
* none
*
* # Add site option
* $ wp site option add my_option foobar
* Success: Added 'my_option' site option.
*
* # Update site option
* $ wp site option update my_option '{"foo": "bar"}' --format=json
* Success: Updated 'my_option' site option.
*
* # Delete site option
* $ wp site option delete my_option
* Success: Deleted 'my_option' site option.
*/
class Site_Option_Command extends WP_CLI_Command {
/**
* Gets a site option.
*
* ## OPTIONS
*
* <key>
* : Key for the site option.
*
* [--format=<format>]
* : Get value in a particular format.
* ---
* default: var_export
* options:
* - var_export
* - json
* - yaml
* ---
*
* ## EXAMPLES
*
* # Get site upload filetypes
* $ wp site option get upload_filetypes
* jpg jpeg png gif mov avi mpg
*/
public function get( $args, $assoc_args ) {
list( $key ) = $args;
$value = get_site_option( $key );
if ( false === $value ) {
WP_CLI::halt( 1 );
}
WP_CLI::print_value( $value, $assoc_args );
}
/**
* Adds a site option.
*
* ## OPTIONS
*
* <key>
* : The name of the site option to add.
*
* [<value>]
* : The value of the site option to add. If omitted, the value is read from STDIN.
*
* [--format=<format>]
* : The serialization format for the value.
* ---
* default: plaintext
* options:
* - plaintext
* - json
* ---
*
* ## EXAMPLES
*
* # Create a site option by reading a JSON file
* $ wp site option add my_option --format=json < config.json
* Success: Added 'my_option' site option.
*/
public function add( $args, $assoc_args ) {
$key = $args[0];
$value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 );
$value = WP_CLI::read_value( $value, $assoc_args );
if ( ! add_site_option( $key, $value ) ) {
WP_CLI::error( "Could not add site option '{$key}'. Does it already exist?" );
} else {
WP_CLI::success( "Added '{$key}' site option." );
}
}
/**
* Lists site options.
*
* ## OPTIONS
*
* [--search=<pattern>]
* : Use wildcards ( * and ? ) to match option name.
*
* [--site_id=<id>]
* : Limit options to those of a particular site id.
*
* [--field=<field>]
* : Prints the value of a single field.
*
* [--fields=<fields>]
* : Limit the output to specific object fields.
*
* [--format=<format>]
* : The serialization format for the value. total_bytes displays the total size of matching options in bytes.
* ---
* default: table
* options:
* - table
* - json
* - csv
* - count
* - yaml
* - total_bytes
* ---
*
* ## AVAILABLE FIELDS
*
* This field will be displayed by default for each matching option:
*
* * meta_key
* * meta_value
*
* These fields are optionally available:
*
* * meta_id
* * site_id
* * size_bytes
*
* ## EXAMPLES
*
* # List all site options beginning with "i2f_"
* $ wp site option list --search="i2f_*"
* +-------------+--------------+
* | meta_key | meta_value |
* +-------------+--------------+
* | i2f_version | 0.1.0 |
* +-------------+--------------+
*
* @subcommand list
*/
public function list_( $args, $assoc_args ) {
global $wpdb;
$pattern = '%';
$fields = [ 'meta_key', 'meta_value' ];
$size_query = ',LENGTH(meta_value) AS `size_bytes`';
if ( isset( $assoc_args['search'] ) ) {
$pattern = self::esc_like( $assoc_args['search'] );
// substitute wildcards
$pattern = str_replace( '*', '%', $pattern );
$pattern = str_replace( '?', '_', $pattern );
}
if ( isset( $assoc_args['fields'] ) ) {
$fields = explode( ',', $assoc_args['fields'] );
}
if ( Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) {
$fields = [ 'size_bytes' ];
$size_query = ',SUM(LENGTH(meta_value)) AS `size_bytes`';
}
$query = $wpdb->prepare(
'SELECT `meta_id`, `site_id`, `meta_key`,`meta_value`'
. $size_query // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Hard-coded partial query without user input.
. " FROM `$wpdb->sitemeta` WHERE `meta_key` LIKE %s",
$pattern
);
$site_id = Utils\get_flag_value( $assoc_args, 'site_id' );
if ( $site_id ) {
$query .= $wpdb->prepare( ' AND site_id=%d', $site_id );
}
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $query is already prepared above.
$results = $wpdb->get_results( $query );
if ( Utils\get_flag_value( $assoc_args, 'format' ) === 'total_bytes' ) {
WP_CLI::line( $results[0]->size_bytes );
} else {
$formatter = new Formatter(
$assoc_args,
$fields
);
$formatter->display_items( $results );
}
}
/**
* Updates a site option.
*
* ## OPTIONS
*
* <key>
* : The name of the site option to update.
*
* [<value>]
* : The new value. If omitted, the value is read from STDIN.
*
* [--format=<format>]
* : The serialization format for the value.
* ---
* default: plaintext
* options:
* - plaintext
* - json
* ---
*
* ## EXAMPLES
*
* # Update a site option by reading from a file
* $ wp site option update my_option < value.txt
* Success: Updated 'my_option' site option.
*
* @alias set
*/
public function update( $args, $assoc_args ) {
$key = $args[0];
$value = WP_CLI::get_value_from_arg_or_stdin( $args, 1 );
$value = WP_CLI::read_value( $value, $assoc_args );
$value = sanitize_option( $key, $value );
$old_value = sanitize_option( $key, get_site_option( $key ) );
if ( $value === $old_value ) {
WP_CLI::success( "Value passed for '{$key}' site option is unchanged." );
} elseif ( update_site_option( $key, $value ) ) {
WP_CLI::success( "Updated '{$key}' site option." );
} else {
WP_CLI::error( "Could not update site option '{$key}'." );
}
}
/**
* Deletes a site option.
*
* ## OPTIONS
*
* <key>
* : Key for the site option.
*
* ## EXAMPLES
*
* $ wp site option delete my_option
* Success: Deleted 'my_option' site option.
*/
public function delete( $args ) {
list( $key ) = $args;
if ( ! delete_site_option( $key ) ) {
WP_CLI::error( "Could not delete '{$key}' site option. Does it exist?" );
} else {
WP_CLI::success( "Deleted '{$key}' site option." );
}
}
/**
* Gets a nested value from an option.
*
* ## OPTIONS
*
* <key>
* : The option name.
*
* <key-path>...
* : The name(s) of the keys within the value to locate the value to pluck.
*
* [--format=<format>]
* : The output format of the value.
* ---
* default: plaintext
* options:
* - plaintext
* - json
* - yaml
*/
public function pluck( $args, $assoc_args ) {
list( $key ) = $args;
$value = get_site_option( $key );
if ( false === $value ) {
WP_CLI::halt( 1 );
}
$key_path = array_map(
function ( $key ) {
if ( is_numeric( $key ) && ( (string) intval( $key ) === $key ) ) {
return (int) $key;
}
return $key;
},
array_slice( $args, 1 )
);
$traverser = new RecursiveDataStructureTraverser( $value );
try {
$value = $traverser->get( $key_path );
} catch ( Exception $exception ) {
die( 1 );
}
WP_CLI::print_value( $value, $assoc_args );
}
/**
* Updates a nested value in an option.
*
* ## OPTIONS
*
* <action>
* : Patch action to perform.
* ---
* options:
* - insert
* - update
* - delete
* ---
*
* <key>
* : The option name.
*
* <key-path>...
* : The name(s) of the keys within the value to locate the value to patch.
*
* [<value>]
* : The new value. If omitted, the value is read from STDIN.
*
* [--format=<format>]
* : The serialization format for the value.
* ---
* default: plaintext
* options:
* - plaintext
* - json
* ---
*/
public function patch( $args, $assoc_args ) {
list( $action, $key ) = $args;
$key_path = array_map(
function ( $key ) {
if ( is_numeric( $key ) && ( (string) intval( $key ) === $key ) ) {
return (int) $key;
}
return $key;
},
array_slice( $args, 2 )
);
if ( 'delete' === $action ) {
$patch_value = null;
} else {
$stdin_value = Utils\has_stdin()
? trim( WP_CLI::get_value_from_arg_or_stdin( $args, -1 ) )
: null;
$patch_value = ! empty( $stdin_value )
? WP_CLI::read_value( $stdin_value, $assoc_args )
: WP_CLI::read_value( array_pop( $key_path ), $assoc_args );
}
/* Need to make a copy of $current_value here as it is modified by reference */
$old_value = sanitize_option( $key, get_site_option( $key ) );
$current_value = $old_value;
if ( is_object( $current_value ) ) {
$old_value = clone $current_value;
}
$traverser = new RecursiveDataStructureTraverser( $current_value );
try {
$traverser->$action( $key_path, $patch_value );
} catch ( Exception $exception ) {
WP_CLI::error( $exception->getMessage() );
}
$patched_value = sanitize_option( $key, $traverser->value() );
if ( $patched_value === $old_value ) {
WP_CLI::success( "Value passed for '{$key}' site option is unchanged." );
} elseif ( update_site_option( $key, $patched_value ) ) {
WP_CLI::success( "Updated '{$key}' site option." );
} else {
WP_CLI::error( "Could not update site option '{$key}'." );
}
}
private static function esc_like( $old ) {
global $wpdb;
// Remove notices in 4.0 and support backwards compatibility
if ( method_exists( $wpdb, 'esc_like' ) ) {
// 4.0
$old = $wpdb->esc_like( $old );
} else {
// phpcs:ignore WordPress.WP.DeprecatedFunctions.like_escapeFound -- called in WordPress 3.9 or less.
$old = like_escape( esc_sql( $old ) );
}
return $old;
}
}