WordPress分类自定义URL结构配置及Yoast SEO站点地图子分类重定向需求
Got it, let's break this down step by step. You want to swap WordPress's default nested category URLs (like /category/cat1/cat2/cat3/) for a flat structure with query params (/category/cat1/?l2cat=cat2&l3cat=cat3), redirect any existing nested URLs to this new format, and make sure Yoast SEO's sitemap uses the updated URLs too. Here's how to implement this:
1. Generate Custom Category URLs
First, we'll hook into WordPress's term_link filter to override the default category URL generation. This will create the flat URL with query parameters for child categories.
Add this code to your theme's functions.php file (or a custom plugin—safer for avoiding lost changes during theme updates):
add_filter( 'term_link', 'custom_category_permalink', 10, 3 ); function custom_category_permalink( $url, $term, $taxonomy ) { // Only target category taxonomy if ( $taxonomy !== 'category' ) { return $url; } // Get the top-level parent category $top_parent = get_top_level_category( $term->term_id ); if ( ! $top_parent ) { return $url; } // Build base URL using top-level category $base_url = get_term_link( $top_parent, 'category' ); // Remove trailing slash for clean param appending $base_url = untrailingslashit( $base_url ); // Collect child category slugs (level 2 and 3) $child_slugs = array(); $current_term = $term; while ( $current_term->parent !== $top_parent->term_id && $current_term->parent !== 0 ) { array_unshift( $child_slugs, $current_term->slug ); $current_term = get_term( $current_term->parent, 'category' ); } // Add the direct child of top-level if exists if ( $current_term->parent === $top_parent->term_id ) { array_unshift( $child_slugs, $current_term->slug ); } // Build query params $query_params = array(); if ( isset( $child_slugs[0] ) ) { $query_params['l2cat'] = $child_slugs[0]; } if ( isset( $child_slugs[1] ) ) { $query_params['l3cat'] = $child_slugs[1]; } // If no child params, return base URL if ( empty( $query_params ) ) { return $base_url . '/'; } // Combine base URL with query params return add_query_arg( $query_params, $base_url ) . '/'; } // Helper function to get top-level parent category function get_top_level_category( $term_id ) { $term = get_term( $term_id, 'category' ); if ( ! $term || is_wp_error( $term ) ) { return false; } while ( $term->parent !== 0 ) { $term = get_term( $term->parent, 'category' ); if ( is_wp_error( $term ) ) { return false; } } return $term; }
How this works:
- The
custom_category_permalinkfunction checks if we're dealing with a category, then finds its top-level parent. - It collects slugs for level 2 and 3 child categories, then builds the URL with
l2catandl3catquery params. - The helper function
get_top_level_categorytraverses up the category hierarchy to find the root parent.
2. Redirect Nested Category URLs to the New Format
Next, we need to redirect any existing nested URLs (like /category/cat1/cat2/cat3/) to the new query param structure. We'll use the template_redirect hook for this:
Add this to your functions.php or custom plugin:
add_action( 'template_redirect', 'redirect_nested_categories' ); function redirect_nested_categories() { // Only run on category archive pages if ( ! is_category() ) { return; } $current_term = get_queried_object(); $top_parent = get_top_level_category( $current_term->term_id ); if ( ! $top_parent || $current_term->term_id === $top_parent->term_id ) { // No redirect needed for top-level categories return; } // Build the target URL using our custom permalink function $target_url = custom_category_permalink( '', $current_term, 'category' ); // Check if we're already on the target URL to avoid redirect loops if ( untrailingslashit( $_SERVER['REQUEST_URI'] ) === untrailingslashit( parse_url( $target_url, PHP_URL_PATH ) . '?' . parse_url( $target_url, PHP_URL_QUERY ) ) ) { return; } // Perform 301 permanent redirect (preserves SEO value) wp_redirect( $target_url, 301 ); exit; }
Key notes:
- This checks if the current page is a category archive, then verifies if it's a child category that needs redirecting.
- It uses our existing
custom_category_permalinkfunction to generate the target URL, ensuring consistency. - We use a 301 redirect to preserve SEO value from the old URLs.
3. Update Yoast SEO Sitemap to Use Custom URLs
Yoast SEO generates sitemaps using its own logic, so we need to hook into its sitemap term link filter to make sure it uses our custom URLs instead of the default nested ones:
Add this code snippet:
add_filter( 'wpseo_xml_sitemap_term_link', 'yoast_custom_category_sitemap_link', 10, 2 ); function yoast_custom_category_sitemap_link( $url, $term ) { if ( $term->taxonomy === 'category' ) { return custom_category_permalink( $url, $term, 'category' ); } return $url; }
This tells Yoast to use our custom permalink function when generating category links in the sitemap, so your sitemap will show the updated ?l2cat=... URLs instead of nested paths.
Final Checks
- After adding these snippets, flush your WordPress permalinks (go to Settings > Permalinks and click "Save Changes"—no need to edit anything). This ensures WordPress picks up the new URL structure.
- Test a few category pages: visit a nested category URL (like
/category/cat1/cat2/) and confirm it redirects to/category/cat1/?l2cat=cat2/. - Check your Yoast sitemap (usually at
/sitemap_index.xml) to verify category links are using the new format.
内容的提问来源于stack exchange,提问作者Luka Juras

