* : The new permalink structure to apply. * * [--category-base=] * : Set the base for category permalinks, i.e. '/category/'. * * [--tag-base=] * : Set the base for tag permalinks, i.e. '/tag/'. * * [--hard] * : Perform a hard flush - update `.htaccess` rules as well as rewrite rules in database. * * ## EXAMPLES * * $ wp rewrite structure '/%year%/%monthnum%/%postname%/' * Success: Rewrite structure set. */ public function structure( $args, $assoc_args ) { global $wp_rewrite; // copypasta from /wp-admin/options-permalink.php $blog_prefix = ''; $prefix = $blog_prefix; if ( is_multisite() && ! is_subdomain_install() && is_main_site() ) { $blog_prefix = '/blog'; } $permalink_structure = ( 'default' === $args[0] ) ? '' : $args[0]; if ( ! empty( $permalink_structure ) ) { $permalink_structure = preg_replace( '#/+#', '/', '/' . str_replace( '#', '', $permalink_structure ) ); if ( $prefix && $blog_prefix ) { $permalink_structure = $prefix . preg_replace( '#^/?index\.php#', '', $permalink_structure ); } else { $permalink_structure = $blog_prefix . $permalink_structure; } } $wp_rewrite->set_permalink_structure( $permalink_structure ); // Update category or tag bases if ( isset( $assoc_args['category-base'] ) ) { $category_base = $assoc_args['category-base']; if ( ! empty( $category_base ) ) { $category_base = $blog_prefix . preg_replace( '#/+#', '/', '/' . str_replace( '#', '', $category_base ) ); } $wp_rewrite->set_category_base( $category_base ); } if ( isset( $assoc_args['tag-base'] ) ) { $tag_base = $assoc_args['tag-base']; if ( ! empty( $tag_base ) ) { $tag_base = $blog_prefix . preg_replace( '#/+#', '/', '/' . str_replace( '#', '', $tag_base ) ); } $wp_rewrite->set_tag_base( $tag_base ); } // make sure we detect mod_rewrite if configured in apache_modules in config self::apache_modules(); WP_CLI::success( 'Rewrite structure set.' ); // Launch a new process to flush rewrites because core expects flush // to happen after rewrites are set $new_assoc_args = []; $cmd = 'rewrite flush'; if ( Utils\get_flag_value( $assoc_args, 'hard' ) ) { $cmd .= ' --hard'; $new_assoc_args['hard'] = true; if ( ! in_array( 'mod_rewrite', (array) WP_CLI::get_config( 'apache_modules' ), true ) ) { WP_CLI::warning( 'Regenerating a .htaccess file requires special configuration. See usage docs.' ); } } $process_run = WP_CLI::runcommand( $cmd ); if ( ! empty( $process_run->stderr ) ) { // Strip "Warning: " WP_CLI::warning( substr( $process_run->stderr, 9 ) ); } } /** * Gets a list of the current rewrite rules. * * ## OPTIONS * * [--match=] * : Show rewrite rules matching a particular URL. * * [--source=] * : Show rewrite rules from a particular source. * * [--fields=] * : Limit the output to specific fields. Defaults to match,query,source. * * [--format=] * : Render output in a particular format. * --- * default: table * options: * - table * - csv * - json * - count * - yaml * --- * * ## EXAMPLES * * $ wp rewrite list --format=csv * match,query,source * ^wp-json/?$,index.php?rest_route=/,other * ^wp-json/(.*)?,index.php?rest_route=/$matches[1],other * category/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category * category/(.+?)/(feed|rdf|rss|rss2|atom)/?$,index.php?category_name=$matches[1]&feed=$matches[2],category * category/(.+?)/embed/?$,index.php?category_name=$matches[1]&embed=true,category * * @subcommand list */ public function list_( $args, $assoc_args ) { global $wp_rewrite; $rules = get_option( 'rewrite_rules' ); if ( ! $rules ) { $rules = []; WP_CLI::warning( 'No rewrite rules.' ); } self::check_skip_plugins_themes(); $defaults = [ 'source' => '', 'match' => '', 'format' => 'table', 'fields' => 'match,query,source', ]; $assoc_args = array_merge( $defaults, $assoc_args ); if ( ! empty( $assoc_args['match'] ) ) { if ( 0 === stripos( $assoc_args['match'], 'http://' ) || 0 === stripos( $assoc_args['match'], 'https://' ) ) { $bits = WP_CLI\Utils\parse_url( $assoc_args['match'] ); $assoc_args['match'] = ( isset( $bits['path'] ) ? $bits['path'] : '' ) . ( isset( $bits['query'] ) ? '?' . $bits['query'] : '' ); } } $rewrite_rules_by_source = []; $rewrite_rules_by_source['post'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->permalink_structure, EP_PERMALINK ); $rewrite_rules_by_source['date'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->get_date_permastruct(), EP_DATE ); $rewrite_rules_by_source['root'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->root . '/', EP_ROOT ); $rewrite_rules_by_source['comments'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->root . $wp_rewrite->comments_base, EP_COMMENTS, true, true, true, false ); $rewrite_rules_by_source['search'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->get_search_permastruct(), EP_SEARCH ); $rewrite_rules_by_source['author'] = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->get_author_permastruct(), EP_AUTHORS ); $rewrite_rules_by_source['page'] = $wp_rewrite->page_rewrite_rules(); // Extra permastructs including tags, categories, etc. foreach ( $wp_rewrite->extra_permastructs as $permastructname => $permastruct ) { if ( is_array( $permastruct ) ) { $rewrite_rules_by_source[ $permastructname ] = $wp_rewrite->generate_rewrite_rules( $permastruct['struct'], $permastruct['ep_mask'], $permastruct['paged'], $permastruct['feed'], $permastruct['forcomments'], $permastruct['walk_dirs'], $permastruct['endpoints'] ); } else { $rewrite_rules_by_source[ $permastructname ] = $wp_rewrite->generate_rewrite_rules( $permastruct, EP_NONE ); } } // Apply the filters used in core just in case foreach ( $rewrite_rules_by_source as $source => $source_rules ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Can't prefix dynamic hooks here, calling hooks for custom permastructs. $rewrite_rules_by_source[ $source ] = apply_filters( $source . '_rewrite_rules', $source_rules ); if ( 'post_tag' === $source ) { if ( Utils\wp_version_compare( '3.1.0', '>=' ) ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling native WordPress hook. $rewrite_rules_by_source[ $source ] = apply_filters( 'post_tag_rewrite_rules', $source_rules ); } else { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling native WordPress hook. $rewrite_rules_by_source[ $source ] = apply_filters( 'tag_rewrite_rules', $source_rules ); } } } $rule_list = []; foreach ( $rules as $match => $query ) { if ( ! empty( $assoc_args['match'] ) && ! preg_match( "!^$match!", trim( $assoc_args['match'], '/' ) ) ) { continue; } $source = 'other'; foreach ( $rewrite_rules_by_source as $rules_source => $source_rules ) { if ( array_key_exists( $match, $source_rules ) ) { $source = $rules_source; } } if ( ! empty( $assoc_args['source'] ) && $source !== $assoc_args['source'] ) { continue; } $rule_list[] = compact( 'match', 'query', 'source' ); } Utils\format_items( $assoc_args['format'], $rule_list, explode( ',', $assoc_args['fields'] ) ); } /** * Exposes apache modules if present in config * * Implementation Notes: This function exposes a global function * apache_get_modules and also sets the $is_apache global variable. * * This is so that flush_rewrite_rules will actually write out the * .htaccess file for apache WordPress installations. There is a check * to see: * * 1. if the $is_apache variable is set. * 2. if the mod_rewrite module is returned from the apache_get_modules * function. * * To get this to work with wp-cli you'll need to add the mod_rewrite module * to your config.yml. For example * * ``` * apache_modules: * - mod_rewrite * ``` * * If this isn't done then the .htaccess rewrite rules won't be flushed out * to disk. */ private static function apache_modules() { $mods = WP_CLI::get_config( 'apache_modules' ); if ( ! empty( $mods ) && ! function_exists( 'apache_get_modules' ) ) { global $is_apache; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited $is_apache = true; // needed for get_home_path() and .htaccess location $_SERVER['SCRIPT_FILENAME'] = ABSPATH; function apache_get_modules() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals return WP_CLI::get_config( 'apache_modules' ); } } } /** * Displays a warning if --skip-plugins or --skip-themes are in use. * * Skipping the loading of plugins or themes can mean some rewrite rules * are unregistered, which may cause erroneous behavior. */ private static function check_skip_plugins_themes() { $skipped = []; if ( WP_CLI::get_config( 'skip-plugins' ) ) { $skipped[] = 'plugins'; } if ( WP_CLI::get_config( 'skip-themes' ) ) { $skipped[] = 'themes'; } if ( empty( $skipped ) ) { return; } $skipped = implode( ' and ', $skipped ); WP_CLI::warning( sprintf( "Some rewrite rules may be missing because %s weren't loaded.", $skipped ) ); } } WP_CLI::add_command( 'rewrite', 'Rewrite_Command' );