/** * Canonical API to handle WordPress Redirecting * * Based on "Permalink Redirect" from Scott Yang and "Enforce www. Preference" * by Mark Jaquith * * @package WordPress * @since 2.3.0 */ /** * Redirects incoming links to the proper URL based on the site url. * * Search engines consider www.somedomain.com and somedomain.com to be two * different URLs when they both go to the same location. This SEO enhancement * prevents penalty for duplicate content by redirecting all incoming links to * one or the other. * * Prevents redirection for feeds, trackbacks, searches, and * admin URLs. Does not redirect on non-pretty-permalink-supporting IIS 7+, * page/post previews, WP admin, Trackbacks, robots.txt, searches, or on POST * requests. * * Will also attempt to find the correct link when a user enters a URL that does * not exist based on exact WordPress query. Will instead try to parse the URL * or query in an attempt to figure the correct page to go to. * * @since 2.3.0 * * @global WP_Rewrite $wp_rewrite * @global bool $is_IIS * @global WP_Query $wp_query * @global wpdb $wpdb WordPress database abstraction object. * @global WP $wp Current WordPress environment instance. * * @param string $requested_url Optional. The URL that was requested, used to * figure if redirect is needed. * @param bool $do_redirect Optional. Redirect to the new URL. * @return string|void The string of the URL, if redirect needed. */ function redirect_canonical( $requested_url = null, $do_redirect = true ) { global $wp_rewrite, $is_IIS, $wp_query, $wpdb, $wp; if ( isset( $_SERVER['REQUEST_METHOD'] ) && ! in_array( strtoupper( $_SERVER['REQUEST_METHOD'] ), array( 'GET', 'HEAD' ) ) ) { return; } // If we're not in wp-admin and the post has been published and preview nonce // is non-existent or invalid then no need for preview in query if ( is_preview() && get_query_var( 'p' ) && 'publish' == get_post_status( get_query_var( 'p' ) ) ) { if ( ! isset( $_GET['preview_id'] ) || ! isset( $_GET['preview_nonce'] ) || ! wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . (int) $_GET['preview_id'] ) ) { $wp_query->is_preview = false; } } if ( is_trackback() || is_search() || is_admin() || is_preview() || is_robots() || ( $is_IIS && ! iis7_supports_permalinks() ) ) { return; } if ( ! $requested_url && isset( $_SERVER['HTTP_HOST'] ) ) { // build the URL in the address bar $requested_url = is_ssl() ? 'https://' : 'http://'; $requested_url .= $_SERVER['HTTP_HOST']; $requested_url .= $_SERVER['REQUEST_URI']; } $original = @parse_url( $requested_url ); if ( false === $original ) { return; } $redirect = $original; $redirect_url = false; // Notice fixing if ( ! isset( $redirect['path'] ) ) { $redirect['path'] = ''; } if ( ! isset( $redirect['query'] ) ) { $redirect['query'] = ''; } // If the original URL ended with non-breaking spaces, they were almost // certainly inserted by accident. Let's remove them, so the reader doesn't // see a 404 error with no obvious cause. $redirect['path'] = preg_replace( '|(%C2%A0)+$|i', '', $redirect['path'] ); // It's not a preview, so remove it from URL if ( get_query_var( 'preview' ) ) { $redirect['query'] = remove_query_arg( 'preview', $redirect['query'] ); } if ( is_feed() && ( $id = get_query_var( 'p' ) ) ) { if ( $redirect_url = get_post_comments_feed_link( $id, get_query_var( 'feed' ) ) ) { $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type', 'feed' ), $redirect_url ); $redirect['path'] = parse_url( $redirect_url, PHP_URL_PATH ); } } if ( is_singular() && 1 > $wp_query->post_count && ( $id = get_query_var( 'p' ) ) ) { $vars = $wpdb->get_results( $wpdb->prepare( "SELECT post_type, post_parent FROM $wpdb->posts WHERE ID = %d", $id ) ); if ( isset( $vars[0] ) && $vars = $vars[0] ) { if ( 'revision' == $vars->post_type && $vars->post_parent > 0 ) { $id = $vars->post_parent; } if ( $redirect_url = get_permalink( $id ) ) { $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url ); } } } // These tests give us a WP-generated permalink if ( is_404() ) { // Redirect ?page_id, ?p=, ?attachment_id= to their respective url's $id = max( get_query_var( 'p' ), get_query_var( 'page_id' ), get_query_var( 'attachment_id' ) ); if ( $id && $redirect_post = get_post( $id ) ) { $post_type_obj = get_post_type_object( $redirect_post->post_type ); if ( $post_type_obj->public && 'auto-draft' != $redirect_post->post_status ) { $redirect_url = get_permalink( $redirect_post ); $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url ); } } if ( get_query_var( 'day' ) && get_query_var( 'monthnum' ) && get_query_var( 'year' ) ) { $year = get_query_var( 'year' ); $month = get_query_var( 'monthnum' ); $day = get_query_var( 'day' ); $date = sprintf( '%04d-%02d-%02d', $year, $month, $day ); if ( ! wp_checkdate( $month, $day, $year, $date ) ) { $redirect_url = get_month_link( $year, $month ); $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'year', 'monthnum', 'day' ), $redirect_url ); } } elseif ( get_query_var( 'monthnum' ) && get_query_var( 'year' ) && 12 < get_query_var( 'monthnum' ) ) { $redirect_url = get_year_link( get_query_var( 'year' ) ); $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'year', 'monthnum' ), $redirect_url ); } if ( ! $redirect_url ) { if ( $redirect_url = redirect_guess_404_permalink() ) { $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'page', 'feed', 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url ); } } if ( get_query_var( 'page' ) && $wp_query->post && false !== strpos( $wp_query->post->post_content, '' ) ) { $redirect['path'] = rtrim( $redirect['path'], (int) get_query_var( 'page' ) . '/' ); $redirect['query'] = remove_query_arg( 'page', $redirect['query'] ); $redirect_url = get_permalink( $wp_query->post->ID ); } } elseif ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() ) { // rewriting of old ?p=X, ?m=2004, ?m=200401, ?m=20040101 if ( is_attachment() && ! array_diff( array_keys( $wp->query_vars ), array( 'attachment', 'attachment_id' ) ) && ! $redirect_url ) { if ( ! empty( $_GET['attachment_id'] ) ) { $redirect_url = get_attachment_link( get_query_var( 'attachment_id' ) ); if ( $redirect_url ) { $redirect['query'] = remove_query_arg( 'attachment_id', $redirect['query'] ); } } else { $redirect_url = get_attachment_link(); } } elseif ( is_single() && ! empty( $_GET['p'] ) && ! $redirect_url ) { if ( $redirect_url = get_permalink( get_query_var( 'p' ) ) ) { $redirect['query'] = remove_query_arg( array( 'p', 'post_type' ), $redirect['query'] ); } } elseif ( is_single() && ! empty( $_GET['name'] ) && ! $redirect_url ) { if ( $redirect_url = get_permalink( $wp_query->get_queried_object_id() ) ) { $redirect['query'] = remove_query_arg( 'name', $redirect['query'] ); } } elseif ( is_page() && ! empty( $_GET['page_id'] ) && ! $redirect_url ) { if ( $redirect_url = get_permalink( get_query_var( 'page_id' ) ) ) { $redirect['query'] = remove_query_arg( 'page_id', $redirect['query'] ); } } elseif ( is_page() && ! is_feed() && 'page' == get_option( 'show_on_front' ) && get_queried_object_id() == get_option( 'page_on_front' ) && ! $redirect_url ) { $redirect_url = home_url( '/' ); } elseif ( is_home() && ! empty( $_GET['page_id'] ) && 'page' == get_option( 'show_on_front' ) && get_query_var( 'page_id' ) == get_option( 'page_for_posts' ) && ! $redirect_url ) { if ( $redirect_url = get_permalink( get_option( 'page_for_posts' ) ) ) { $redirect['query'] = remove_query_arg( 'page_id', $redirect['query'] ); } } elseif ( ! empty( $_GET['m'] ) && ( is_year() || is_month() || is_day() ) ) { $m = get_query_var( 'm' ); switch ( strlen( $m ) ) { case 4: // Yearly $redirect_url = get_year_link( $m ); break; case 6: // Monthly $redirect_url = get_month_link( substr( $m, 0, 4 ), substr( $m, 4, 2 ) ); break; case 8: // Daily $redirect_url = get_day_link( substr( $m, 0, 4 ), substr( $m, 4, 2 ), substr( $m, 6, 2 ) ); break; } if ( $redirect_url ) { $redirect['query'] = remove_query_arg( 'm', $redirect['query'] ); } // now moving on to non ?m=X year/month/day links } elseif ( is_day() && get_query_var( 'year' ) && get_query_var( 'monthnum' ) && ! empty( $_GET['day'] ) ) { if ( $redirect_url = get_day_link( get_query_var( 'year' ), get_query_var( 'monthnum' ), get_query_var( 'day' ) ) ) { $redirect['query'] = remove_query_arg( array( 'year', 'monthnum', 'day' ), $redirect['query'] ); } } elseif ( is_month() && get_query_var( 'year' ) && ! empty( $_GET['monthnum'] ) ) { if ( $redirect_url = get_month_link( get_query_var( 'year' ), get_query_var( 'monthnum' ) ) ) { $redirect['query'] = remove_query_arg( array( 'year', 'monthnum' ), $redirect['query'] ); } } elseif ( is_year() && ! empty( $_GET['year'] ) ) { if ( $redirect_url = get_year_link( get_query_var( 'year' ) ) ) { $redirect['query'] = remove_query_arg( 'year', $redirect['query'] ); } } elseif ( is_author() && ! empty( $_GET['author'] ) && preg_match( '|^[0-9]+$|', $_GET['author'] ) ) { $author = get_userdata( get_query_var( 'author' ) ); if ( ( false !== $author ) && $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE $wpdb->posts.post_author = %d AND $wpdb->posts.post_status = 'publish' LIMIT 1", $author->ID ) ) ) { if ( $redirect_url = get_author_posts_url( $author->ID, $author->user_nicename ) ) { $redirect['query'] = remove_query_arg( 'author', $redirect['query'] ); } } } elseif ( is_category() || is_tag() || is_tax() ) { // Terms (Tags/categories) $term_count = 0; foreach ( $wp_query->tax_query->queried_terms as $tax_query ) { $term_count += count( $tax_query['terms'] ); } $obj = $wp_query->get_queried_object(); if ( $term_count <= 1 && ! empty( $obj->term_id ) && ( $tax_url = get_term_link( (int) $obj->term_id, $obj->taxonomy ) ) && ! is_wp_error( $tax_url ) ) { if ( ! empty( $redirect['query'] ) ) { // Strip taxonomy query vars off the url. $qv_remove = array( 'term', 'taxonomy' ); if ( is_category() ) { $qv_remove[] = 'category_name'; $qv_remove[] = 'cat'; } elseif ( is_tag() ) { $qv_remove[] = 'tag'; $qv_remove[] = 'tag_id'; } else { // Custom taxonomies will have a custom query var, remove those too: $tax_obj = get_taxonomy( $obj->taxonomy ); if ( false !== $tax_obj->query_var ) { $qv_remove[] = $tax_obj->query_var; } } $rewrite_vars = array_diff( array_keys( $wp_query->query ), array_keys( $_GET ) ); if ( ! array_diff( $rewrite_vars, array_keys( $_GET ) ) ) { // Check to see if all the Query vars are coming from the rewrite, none are set via $_GET $redirect['query'] = remove_query_arg( $qv_remove, $redirect['query'] ); //Remove all of the per-tax qv's // Create the destination url for this taxonomy $tax_url = parse_url( $tax_url ); if ( ! empty( $tax_url['query'] ) ) { // Taxonomy accessible via ?taxonomy=..&term=.. or any custom qv.. parse_str( $tax_url['query'], $query_vars ); $redirect['query'] = add_query_arg( $query_vars, $redirect['query'] ); } else { // Taxonomy is accessible via a "pretty-URL" $redirect['path'] = $tax_url['path']; } } else { // Some query vars are set via $_GET. Unset those from $_GET that exist via the rewrite foreach ( $qv_remove as $_qv ) { if ( isset( $rewrite_vars[ $_qv ] ) ) { $redirect['query'] = remove_query_arg( $_qv, $redirect['query'] ); } } } } } } elseif ( is_single() && strpos( $wp_rewrite->permalink_structure, '%category%' ) !== false && $cat = get_query_var( 'category_name' ) ) { $category = get_category_by_path( $cat ); if ( ( ! $category || is_wp_error( $category ) ) || ! has_term( $category->term_id, 'category', $wp_query->get_queried_object_id() ) ) { $redirect_url = get_permalink( $wp_query->get_queried_object_id() ); } } // Post Paging if ( is_singular() && get_query_var( 'page' ) ) { if ( ! $redirect_url ) { $redirect_url = get_permalink( get_queried_object_id() ); } $page = get_query_var( 'page' ); if ( $page > 1 ) { if ( is_front_page() ) { $redirect_url = trailingslashit( $redirect_url ) . user_trailingslashit( "$wp_rewrite->pagination_base/$page", 'paged' ); } else { $redirect_url = trailingslashit( $redirect_url ) . user_trailingslashit( $page, 'single_paged' ); } } $redirect['query'] = remove_query_arg( 'page', $redirect['query'] ); } // paging and feeds if ( get_query_var( 'paged' ) || is_feed() || get_query_var( 'cpage' ) ) { while ( preg_match( "#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", $redirect['path'] ) || preg_match( '#/(comments/?)?(feed|rss|rdf|atom|rss2)(/+)?$#', $redirect['path'] ) || preg_match( "#/{$wp_rewrite->comments_pagination_base}-[0-9]+(/+)?$#", $redirect['path'] ) ) { // Strip off paging and feed $redirect['path'] = preg_replace( "#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", '/', $redirect['path'] ); // strip off any existing paging $redirect['path'] = preg_replace( '#/(comments/?)?(feed|rss2?|rdf|atom)(/+|$)#', '/', $redirect['path'] ); // strip off feed endings $redirect['path'] = preg_replace( "#/{$wp_rewrite->comments_pagination_base}-[0-9]+?(/+)?$#", '/', $redirect['path'] ); // strip off any existing comment paging } $addl_path = ''; if ( is_feed() && in_array( get_query_var( 'feed' ), $wp_rewrite->feeds ) ) { $addl_path = ! empty( $addl_path ) ? trailingslashit( $addl_path ) : ''; if ( ! is_singular() && get_query_var( 'withcomments' ) ) { $addl_path .= 'comments/'; } if ( ( 'rss' == get_default_feed() && 'feed' == get_query_var( 'feed' ) ) || 'rss' == get_query_var( 'feed' ) ) { $addl_path .= user_trailingslashit( 'feed/' . ( ( get_default_feed() == 'rss2' ) ? '' : 'rss2' ), 'feed' ); } else { $addl_path .= user_trailingslashit( 'feed/' . ( ( get_default_feed() == get_query_var( 'feed' ) || 'feed' == get_query_var( 'feed' ) ) ? '' : get_query_var( 'feed' ) ), 'feed' ); } $redirect['query'] = remove_query_arg( 'feed', $redirect['query'] ); } elseif ( is_feed() && 'old' == get_query_var( 'feed' ) ) { $old_feed_files = array( 'wp-atom.php' => 'atom', 'wp-commentsrss2.php' => 'comments_rss2', 'wp-feed.php' => get_default_feed(), 'wp-rdf.php' => 'rdf', 'wp-rss.php' => 'rss2', 'wp-rss2.php' => 'rss2', ); if ( isset( $old_feed_files[ basename( $redirect['path'] ) ] ) ) { $redirect_url = get_feed_link( $old_feed_files[ basename( $redirect['path'] ) ] ); wp_redirect( $redirect_url, 301 ); die(); } } if ( get_query_var( 'paged' ) > 0 ) { $paged = get_query_var( 'paged' ); $redirect['query'] = remove_query_arg( 'paged', $redirect['query'] ); if ( ! is_feed() ) { if ( $paged > 1 && ! is_single() ) { $addl_path = ( ! empty( $addl_path ) ? trailingslashit( $addl_path ) : '' ) . user_trailingslashit( "$wp_rewrite->pagination_base/$paged", 'paged' ); } elseif ( ! is_single() ) { $addl_path = ! empty( $addl_path ) ? trailingslashit( $addl_path ) : ''; } } elseif ( $paged > 1 ) { $redirect['query'] = add_query_arg( 'paged', $paged, $redirect['query'] ); } } if ( get_option( 'page_comments' ) && ( ( 'newest' == get_option( 'default_comments_page' ) && get_query_var( 'cpage' ) > 0 ) || ( 'newest' != get_option( 'default_comments_page' ) && get_query_var( 'cpage' ) > 1 ) ) ) { $addl_path = ( ! empty( $addl_path ) ? trailingslashit( $addl_path ) : '' ) . user_trailingslashit( $wp_rewrite->comments_pagination_base . '-' . get_query_var( 'cpage' ), 'commentpaged' ); $redirect['query'] = remove_query_arg( 'cpage', $redirect['query'] ); } $redirect['path'] = user_trailingslashit( preg_replace( '|/' . preg_quote( $wp_rewrite->index, '|' ) . '/?$|', '/', $redirect['path'] ) ); // strip off trailing /index.php/ if ( ! empty( $addl_path ) && $wp_rewrite->using_index_permalinks() && strpos( $redirect['path'], '/' . $wp_rewrite->index . '/' ) === false ) { $redirect['path'] = trailingslashit( $redirect['path'] ) . $wp_rewrite->index . '/'; } if ( ! empty( $addl_path ) ) { $redirect['path'] = trailingslashit( $redirect['path'] ) . $addl_path; } $redirect_url = $redirect['scheme'] . '://' . $redirect['host'] . $redirect['path']; } if ( 'wp-register.php' == basename( $redirect['path'] ) ) { if ( is_multisite() ) { /** This filter is documented in wp-login.php */ $redirect_url = apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) ); } else { $redirect_url = wp_registration_url(); } wp_redirect( $redirect_url, 301 ); die(); } } // tack on any additional query vars $redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] ); if ( $redirect_url && ! empty( $redirect['query'] ) ) { parse_str( $redirect['query'], $_parsed_query ); $redirect = @parse_url( $redirect_url ); if ( ! empty( $_parsed_query['name'] ) && ! empty( $redirect['query'] ) ) { parse_str( $redirect['query'], $_parsed_redirect_query ); if ( empty( $_parsed_redirect_query['name'] ) ) { unset( $_parsed_query['name'] ); } } $_parsed_query = array_combine( rawurlencode_deep( array_keys( $_parsed_query ) ), rawurlencode_deep( array_values( $_parsed_query ) ) ); $redirect_url = add_query_arg( $_parsed_query, $redirect_url ); } if ( $redirect_url ) { $redirect = @parse_url( $redirect_url ); } // www.example.com vs example.com $user_home = @parse_url( home_url() ); if ( ! empty( $user_home['host'] ) ) { $redirect['host'] = $user_home['host']; } if ( empty( $user_home['path'] ) ) { $user_home['path'] = '/'; } // Handle ports if ( ! empty( $user_home['port'] ) ) { $redirect['port'] = $user_home['port']; } else { unset( $redirect['port'] ); } // trailing /index.php $redirect['path'] = preg_replace( '|/' . preg_quote( $wp_rewrite->index, '|' ) . '/*?$|', '/', $redirect['path'] ); $punctuation_pattern = implode( '|', array_map( 'preg_quote', array( ' ', '%20', // space '!', '%21', // exclamation mark '"', '%22', // double quote "'", '%27', // single quote '(', '%28', // opening bracket ')', '%29', // closing bracket ',', '%2C', // comma '.', '%2E', // period ';', '%3B', // semicolon '{', '%7B', // opening curly bracket '}', '%7D', // closing curly bracket '%E2%80%9C', // opening curly quote '%E2%80%9D', // closing curly quote ) ) ); // Remove trailing spaces and end punctuation from the path. $redirect['path'] = preg_replace( "#($punctuation_pattern)+$#", '', $redirect['path'] ); if ( ! empty( $redirect['query'] ) ) { // Remove trailing spaces and end punctuation from certain terminating query string args. $redirect['query'] = preg_replace( "#((p|page_id|cat|tag)=[^&]*?)($punctuation_pattern)+$#", '$1', $redirect['query'] ); // Clean up empty query strings $redirect['query'] = trim( preg_replace( '#(^|&)(p|page_id|cat|tag)=?(&|$)#', '&', $redirect['query'] ), '&' ); // Redirect obsolete feeds $redirect['query'] = preg_replace( '#(^|&)feed=rss(&|$)#', '$1feed=rss2$2', $redirect['query'] ); // Remove redundant leading ampersands $redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] ); } // strip /index.php/ when we're not using PATHINFO permalinks if ( ! $wp_rewrite->using_index_permalinks() ) { $redirect['path'] = str_replace( '/' . $wp_rewrite->index . '/', '/', $redirect['path'] ); } // trailing slashes if ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() && ! is_404() && ( ! is_front_page() || ( is_front_page() && ( get_query_var( 'paged' ) > 1 ) ) ) ) { $user_ts_type = ''; if ( get_query_var( 'paged' ) > 0 ) { $user_ts_type = 'paged'; } else { foreach ( array( 'single', 'category', 'page', 'day', 'month', 'year', 'home' ) as $type ) { $func = 'is_' . $type; if ( call_user_func( $func ) ) { $user_ts_type = $type; break; } } } $redirect['path'] = user_trailingslashit( $redirect['path'], $user_ts_type ); } elseif ( is_front_page() ) { $redirect['path'] = trailingslashit( $redirect['path'] ); } // Strip multiple slashes out of the URL if ( strpos( $redirect['path'], '//' ) > -1 ) { $redirect['path'] = preg_replace( '|/+|', '/', $redirect['path'] ); } // Always trailing slash the Front Page URL if ( trailingslashit( $redirect['path'] ) == trailingslashit( $user_home['path'] ) ) { $redirect['path'] = trailingslashit( $redirect['path'] ); } // Ignore differences in host capitalization, as this can lead to infinite redirects // Only redirect no-www <=> yes-www if ( strtolower( $original['host'] ) == strtolower( $redirect['host'] ) || ( strtolower( $original['host'] ) != 'www.' . strtolower( $redirect['host'] ) && 'www.' . strtolower( $original['host'] ) != strtolower( $redirect['host'] ) ) ) { $redirect['host'] = $original['host']; } $compare_original = array( $original['host'], $original['path'] ); if ( ! empty( $original['port'] ) ) { $compare_original[] = $original['port']; } if ( ! empty( $original['query'] ) ) { $compare_original[] = $original['query']; } $compare_redirect = array( $redirect['host'], $redirect['path'] ); if ( ! empty( $redirect['port'] ) ) { $compare_redirect[] = $redirect['port']; } if ( ! empty( $redirect['query'] ) ) { $compare_redirect[] = $redirect['query']; } if ( $compare_original !== $compare_redirect ) { $redirect_url = $redirect['scheme'] . '://' . $redirect['host']; if ( ! empty( $redirect['port'] ) ) { $redirect_url .= ':' . $redirect['port']; } $redirect_url .= $redirect['path']; if ( ! empty( $redirect['query'] ) ) { $redirect_url .= '?' . $redirect['query']; } } if ( ! $redirect_url || $redirect_url == $requested_url ) { return; } // Hex encoded octets are case-insensitive. if ( false !== strpos( $requested_url, '%' ) ) { if ( ! function_exists( 'lowercase_octets' ) ) { /** * Converts the first hex-encoded octet match to lowercase. * * @since 3.1.0 * @ignore * * @param array $matches Hex-encoded octet matches for the requested URL. * @return string Lowercased version of the first match. */ function lowercase_octets( $matches ) { return strtolower( $matches[0] ); } } $requested_url = preg_replace_callback( '|%[a-fA-F0-9][a-fA-F0-9]|', 'lowercase_octets', $requested_url ); } /** * Filters the canonical redirect URL. * * Returning false to this filter will cancel the redirect. * * @since 2.3.0 * * @param string $redirect_url The redirect URL. * @param string $requested_url The requested URL. */ $redirect_url = apply_filters( 'redirect_canonical', $redirect_url, $requested_url ); // yes, again -- in case the filter aborted the request if ( ! $redirect_url || strip_fragment_from_url( $redirect_url ) == strip_fragment_from_url( $requested_url ) ) { return; } if ( $do_redirect ) { // protect against chained redirects if ( ! redirect_canonical( $redirect_url, false ) ) { wp_redirect( $redirect_url, 301 ); exit(); } else { // Debug // die("1: $redirect_url
2: " . redirect_canonical( $redirect_url, false ) ); return; } } else { return $redirect_url; } } /** * Removes arguments from a query string if they are not present in a URL * DO NOT use this in plugin code. * * @since 3.4.0 * @access private * * @param string $query_string * @param array $args_to_check * @param string $url * @return string The altered query string */ function _remove_qs_args_if_not_in_url( $query_string, array $args_to_check, $url ) { $parsed_url = @parse_url( $url ); if ( ! empty( $parsed_url['query'] ) ) { parse_str( $parsed_url['query'], $parsed_query ); foreach ( $args_to_check as $qv ) { if ( ! isset( $parsed_query[ $qv ] ) ) { $query_string = remove_query_arg( $qv, $query_string ); } } } else { $query_string = remove_query_arg( $args_to_check, $query_string ); } return $query_string; } /** * Strips the #fragment from a URL, if one is present. * * @since 4.4.0 * * @param string $url The URL to strip. * @return string The altered URL. */ function strip_fragment_from_url( $url ) { $parsed_url = @parse_url( $url ); if ( ! empty( $parsed_url['host'] ) ) { // This mirrors code in redirect_canonical(). It does not handle every case. $url = $parsed_url['scheme'] . '://' . $parsed_url['host']; if ( ! empty( $parsed_url['port'] ) ) { $url .= ':' . $parsed_url['port']; } if ( ! empty( $parsed_url['path'] ) ) { $url .= $parsed_url['path']; } if ( ! empty( $parsed_url['query'] ) ) { $url .= '?' . $parsed_url['query']; } } return $url; } /** * Attempts to guess the correct URL based on query vars * * @since 2.3.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @return false|string The correct URL if one is found. False on failure. */ function redirect_guess_404_permalink() { global $wpdb; if ( get_query_var( 'name' ) ) { $where = $wpdb->prepare( 'post_name LIKE %s', $wpdb->esc_like( get_query_var( 'name' ) ) . '%' ); // if any of post_type, year, monthnum, or day are set, use them to refine the query if ( get_query_var( 'post_type' ) ) { $where .= $wpdb->prepare( ' AND post_type = %s', get_query_var( 'post_type' ) ); } else { $where .= " AND post_type IN ('" . implode( "', '", get_post_types( array( 'public' => true ) ) ) . "')"; } if ( get_query_var( 'year' ) ) { $where .= $wpdb->prepare( ' AND YEAR(post_date) = %d', get_query_var( 'year' ) ); } if ( get_query_var( 'monthnum' ) ) { $where .= $wpdb->prepare( ' AND MONTH(post_date) = %d', get_query_var( 'monthnum' ) ); } if ( get_query_var( 'day' ) ) { $where .= $wpdb->prepare( ' AND DAYOFMONTH(post_date) = %d', get_query_var( 'day' ) ); } $post_id = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE $where AND post_status = 'publish'" ); if ( ! $post_id ) { return false; } if ( get_query_var( 'feed' ) ) { return get_post_comments_feed_link( $post_id, get_query_var( 'feed' ) ); } elseif ( get_query_var( 'page' ) && 1 < get_query_var( 'page' ) ) { return trailingslashit( get_permalink( $post_id ) ) . user_trailingslashit( get_query_var( 'page' ), 'single_paged' ); } else { return get_permalink( $post_id ); } } return false; } /** * Redirects a variety of shorthand URLs to the admin. * * If a user visits example.com/admin, they'll be redirected to /wp-admin. * Visiting /login redirects to /wp-login.php, and so on. * * @since 3.4.0 * * @global WP_Rewrite $wp_rewrite */ function wp_redirect_admin_locations() { global $wp_rewrite; if ( ! ( is_404() && $wp_rewrite->using_permalinks() ) ) { return; } $admins = array( home_url( 'wp-admin', 'relative' ), home_url( 'dashboard', 'relative' ), home_url( 'admin', 'relative' ), site_url( 'dashboard', 'relative' ), site_url( 'admin', 'relative' ), ); if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $admins ) ) { wp_redirect( admin_url() ); exit; } $logins = array( home_url( 'wp-login.php', 'relative' ), home_url( 'login', 'relative' ), site_url( 'login', 'relative' ), ); if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $logins ) ) { wp_redirect( wp_login_url() ); exit; } } /** * HTTP API: WP_HTTP_Proxy class * * @package WordPress * @subpackage HTTP * @since 4.4.0 */ /** * Core class used to implement HTTP API proxy support. * * There are caveats to proxy support. It requires that defines be made in the wp-config.php file to * enable proxy support. There are also a few filters that plugins can hook into for some of the * constants. * * Please note that only BASIC authentication is supported by most transports. * cURL MAY support more methods (such as NTLM authentication) depending on your environment. * * The constants are as follows: *
    *
  1. WP_PROXY_HOST - Enable proxy support and host for connecting.
  2. *
  3. WP_PROXY_PORT - Proxy port for connection. No default, must be defined.
  4. *
  5. WP_PROXY_USERNAME - Proxy username, if it requires authentication.
  6. *
  7. WP_PROXY_PASSWORD - Proxy password, if it requires authentication.
  8. *
  9. WP_PROXY_BYPASS_HOSTS - Will prevent the hosts in this list from going through the proxy. * You do not need to have localhost and the site host in this list, because they will not be passed * through the proxy. The list should be presented in a comma separated list, wildcards using * are supported, eg. *.wordpress.org
  10. *
* * An example can be as seen below. * * define('WP_PROXY_HOST', '192.168.84.101'); * define('WP_PROXY_PORT', '8080'); * define('WP_PROXY_BYPASS_HOSTS', 'localhost, www.example.com, *.wordpress.org'); * * @link https://core.trac.wordpress.org/ticket/4011 Proxy support ticket in WordPress. * @link https://core.trac.wordpress.org/ticket/14636 Allow wildcard domains in WP_PROXY_BYPASS_HOSTS * * @since 2.8.0 */ class WP_HTTP_Proxy { /** * Whether proxy connection should be used. * * @since 2.8.0 * * @use WP_PROXY_HOST * @use WP_PROXY_PORT * * @return bool */ public function is_enabled() { return defined( 'WP_PROXY_HOST' ) && defined( 'WP_PROXY_PORT' ); } /** * Whether authentication should be used. * * @since 2.8.0 * * @use WP_PROXY_USERNAME * @use WP_PROXY_PASSWORD * * @return bool */ public function use_authentication() { return defined( 'WP_PROXY_USERNAME' ) && defined( 'WP_PROXY_PASSWORD' ); } /** * Retrieve the host for the proxy server. * * @since 2.8.0 * * @return string */ public function host() { if ( defined( 'WP_PROXY_HOST' ) ) { return WP_PROXY_HOST; } return ''; } /** * Retrieve the port for the proxy server. * * @since 2.8.0 * * @return string */ public function port() { if ( defined( 'WP_PROXY_PORT' ) ) { return WP_PROXY_PORT; } return ''; } /** * Retrieve the username for proxy authentication. * * @since 2.8.0 * * @return string */ public function username() { if ( defined( 'WP_PROXY_USERNAME' ) ) { return WP_PROXY_USERNAME; } return ''; } /** * Retrieve the password for proxy authentication. * * @since 2.8.0 * * @return string */ public function password() { if ( defined( 'WP_PROXY_PASSWORD' ) ) { return WP_PROXY_PASSWORD; } return ''; } /** * Retrieve authentication string for proxy authentication. * * @since 2.8.0 * * @return string */ public function authentication() { return $this->username() . ':' . $this->password(); } /** * Retrieve header string for proxy authentication. * * @since 2.8.0 * * @return string */ public function authentication_header() { return 'Proxy-Authorization: Basic ' . base64_encode( $this->authentication() ); } /** * Whether URL should be sent through the proxy server. * * We want to keep localhost and the site URL from being sent through the proxy server, because * some proxies can not handle this. We also have the constant available for defining other * hosts that won't be sent through the proxy. * * @since 2.8.0 * * @staticvar array|null $bypass_hosts * @staticvar array $wildcard_regex * * @param string $uri URI to check. * @return bool True, to send through the proxy and false if, the proxy should not be used. */ public function send_through_proxy( $uri ) { /* * parse_url() only handles http, https type URLs, and will emit E_WARNING on failure. * This will be displayed on sites, which is not reasonable. */ $check = @parse_url( $uri ); // Malformed URL, can not process, but this could mean ssl, so let through anyway. if ( $check === false ) { return true; } $home = parse_url( get_option( 'siteurl' ) ); /** * Filters whether to preempt sending the request through the proxy server. * * Returning false will bypass the proxy; returning true will send * the request through the proxy. Returning null bypasses the filter. * * @since 3.5.0 * * @param null $override Whether to override the request result. Default null. * @param string $uri URL to check. * @param array $check Associative array result of parsing the URI. * @param array $home Associative array result of parsing the site URL. */ $result = apply_filters( 'pre_http_send_through_proxy', null, $uri, $check, $home ); if ( ! is_null( $result ) ) { return $result; } if ( 'localhost' == $check['host'] || ( isset( $home['host'] ) && $home['host'] == $check['host'] ) ) { return false; } if ( ! defined( 'WP_PROXY_BYPASS_HOSTS' ) ) { return true; } static $bypass_hosts = null; static $wildcard_regex = array(); if ( null === $bypass_hosts ) { $bypass_hosts = preg_split( '|,\s*|', WP_PROXY_BYPASS_HOSTS ); if ( false !== strpos( WP_PROXY_BYPASS_HOSTS, '*' ) ) { $wildcard_regex = array(); foreach ( $bypass_hosts as $host ) { $wildcard_regex[] = str_replace( '\*', '.+', preg_quote( $host, '/' ) ); } $wildcard_regex = '/^(' . implode( '|', $wildcard_regex ) . ')$/i'; } } if ( ! empty( $wildcard_regex ) ) { return ! preg_match( $wildcard_regex, $check['host'] ); } else { return ! in_array( $check['host'], $bypass_hosts ); } } } /** * Navigation Menu functions * * @package WordPress * @subpackage Nav_Menus * @since 3.0.0 */ /** * Returns a navigation menu object. * * @since 3.0.0 * * @param int|string|WP_Term $menu Menu ID, slug, name, or object. * @return WP_Term|false False if $menu param isn't supplied or term does not exist, menu object if successful. */ function wp_get_nav_menu_object( $menu ) { $menu_obj = false; if ( is_object( $menu ) ) { $menu_obj = $menu; } if ( $menu && ! $menu_obj ) { $menu_obj = get_term( $menu, 'nav_menu' ); if ( ! $menu_obj ) { $menu_obj = get_term_by( 'slug', $menu, 'nav_menu' ); } if ( ! $menu_obj ) { $menu_obj = get_term_by( 'name', $menu, 'nav_menu' ); } } if ( ! $menu_obj || is_wp_error( $menu_obj ) ) { $menu_obj = false; } /** * Filters the nav_menu term retrieved for wp_get_nav_menu_object(). * * @since 4.3.0 * * @param WP_Term|false $menu_obj Term from nav_menu taxonomy, or false if nothing had been found. * @param int|string|WP_Term $menu The menu ID, slug, name, or object passed to wp_get_nav_menu_object(). */ return apply_filters( 'wp_get_nav_menu_object', $menu_obj, $menu ); } /** * Check if the given ID is a navigation menu. * * Returns true if it is; false otherwise. * * @since 3.0.0 * * @param int|string|WP_Term $menu Menu ID, slug, name, or object of menu to check. * @return bool Whether the menu exists. */ function is_nav_menu( $menu ) { if ( ! $menu ) { return false; } $menu_obj = wp_get_nav_menu_object( $menu ); if ( $menu_obj && ! is_wp_error( $menu_obj ) && ! empty( $menu_obj->taxonomy ) && 'nav_menu' == $menu_obj->taxonomy ) { return true; } return false; } /** * Registers navigation menu locations for a theme. * * @since 3.0.0 * * @global array $_wp_registered_nav_menus * * @param array $locations Associative array of menu location identifiers (like a slug) and descriptive text. */ function register_nav_menus( $locations = array() ) { global $_wp_registered_nav_menus; add_theme_support( 'menus' ); $_wp_registered_nav_menus = array_merge( (array) $_wp_registered_nav_menus, $locations ); } /** * Unregisters a navigation menu location for a theme. * * @since 3.1.0 * @global array $_wp_registered_nav_menus * * @param string $location The menu location identifier. * @return bool True on success, false on failure. */ function unregister_nav_menu( $location ) { global $_wp_registered_nav_menus; if ( is_array( $_wp_registered_nav_menus ) && isset( $_wp_registered_nav_menus[ $location ] ) ) { unset( $_wp_registered_nav_menus[ $location ] ); if ( empty( $_wp_registered_nav_menus ) ) { _remove_theme_support( 'menus' ); } return true; } return false; } /** * Registers a navigation menu location for a theme. * * @since 3.0.0 * * @param string $location Menu location identifier, like a slug. * @param string $description Menu location descriptive text. */ function register_nav_menu( $location, $description ) { register_nav_menus( array( $location => $description ) ); } /** * Retrieves all registered navigation menu locations in a theme. * * @since 3.0.0 * * @global array $_wp_registered_nav_menus * * @return array Registered navigation menu locations. If none are registered, an empty array. */ function get_registered_nav_menus() { global $_wp_registered_nav_menus; if ( isset( $_wp_registered_nav_menus ) ) { return $_wp_registered_nav_menus; } return array(); } /** * Retrieves all registered navigation menu locations and the menus assigned to them. * * @since 3.0.0 * * @return array Registered navigation menu locations and the menus assigned them. * If none are registered, an empty array. */ function get_nav_menu_locations() { $locations = get_theme_mod( 'nav_menu_locations' ); return ( is_array( $locations ) ) ? $locations : array(); } /** * Determines whether a registered nav menu location has a menu assigned to it. * * @since 3.0.0 * * @param string $location Menu location identifier. * @return bool Whether location has a menu. */ function has_nav_menu( $location ) { $has_nav_menu = false; $registered_nav_menus = get_registered_nav_menus(); if ( isset( $registered_nav_menus[ $location ] ) ) { $locations = get_nav_menu_locations(); $has_nav_menu = ! empty( $locations[ $location ] ); } /** * Filters whether a nav menu is assigned to the specified location. * * @since 4.3.0 * * @param bool $has_nav_menu Whether there is a menu assigned to a location. * @param string $location Menu location. */ return apply_filters( 'has_nav_menu', $has_nav_menu, $location ); } /** * Returns the name of a navigation menu. * * @since 4.9.0 * * @param string $location Menu location identifier. * @return string Menu name. */ function wp_get_nav_menu_name( $location ) { $menu_name = ''; $locations = get_nav_menu_locations(); if ( isset( $locations[ $location ] ) ) { $menu = wp_get_nav_menu_object( $locations[ $location ] ); if ( $menu && $menu->name ) { $menu_name = $menu->name; } } /** * Filters the navigation menu name being returned. * * @since 4.9.0 * * @param string $menu_name Menu name. * @param string $location Menu location identifier. */ return apply_filters( 'wp_get_nav_menu_name', $menu_name, $location ); } /** * Determines whether the given ID is a nav menu item. * * @since 3.0.0 * * @param int $menu_item_id The ID of the potential nav menu item. * @return bool Whether the given ID is that of a nav menu item. */ function is_nav_menu_item( $menu_item_id = 0 ) { return ( ! is_wp_error( $menu_item_id ) && ( 'nav_menu_item' == get_post_type( $menu_item_id ) ) ); } /** * Creates a navigation menu. * * Note that `$menu_name` is expected to be pre-slashed. * * @since 3.0.0 * * @param string $menu_name Menu name. * @return int|WP_Error Menu ID on success, WP_Error object on failure. */ function wp_create_nav_menu( $menu_name ) { // expected_slashed ($menu_name) return wp_update_nav_menu_object( 0, array( 'menu-name' => $menu_name ) ); } /** * Delete a Navigation Menu. * * @since 3.0.0 * * @param int|string|WP_Term $menu Menu ID, slug, name, or object. * @return bool|WP_Error True on success, false or WP_Error object on failure. */ function wp_delete_nav_menu( $menu ) { $menu = wp_get_nav_menu_object( $menu ); if ( ! $menu ) { return false; } $menu_objects = get_objects_in_term( $menu->term_id, 'nav_menu' ); if ( ! empty( $menu_objects ) ) { foreach ( $menu_objects as $item ) { wp_delete_post( $item ); } } $result = wp_delete_term( $menu->term_id, 'nav_menu' ); // Remove this menu from any locations. $locations = get_nav_menu_locations(); foreach ( $locations as $location => $menu_id ) { if ( $menu_id == $menu->term_id ) { $locations[ $location ] = 0; } } set_theme_mod( 'nav_menu_locations', $locations ); if ( $result && ! is_wp_error( $result ) ) { /** * Fires after a navigation menu has been successfully deleted. * * @since 3.0.0 * * @param int $term_id ID of the deleted menu. */ do_action( 'wp_delete_nav_menu', $menu->term_id ); } return $result; } /** * Save the properties of a menu or create a new menu with those properties. * * Note that `$menu_data` is expected to be pre-slashed. * * @since 3.0.0 * * @param int $menu_id The ID of the menu or "0" to create a new menu. * @param array $menu_data The array of menu data. * @return int|WP_Error Menu ID on success, WP_Error object on failure. */ function wp_update_nav_menu_object( $menu_id = 0, $menu_data = array() ) { // expected_slashed ($menu_data) $menu_id = (int) $menu_id; $_menu = wp_get_nav_menu_object( $menu_id ); $args = array( 'description' => ( isset( $menu_data['description'] ) ? $menu_data['description'] : '' ), 'name' => ( isset( $menu_data['menu-name'] ) ? $menu_data['menu-name'] : '' ), 'parent' => ( isset( $menu_data['parent'] ) ? (int) $menu_data['parent'] : 0 ), 'slug' => null, ); // double-check that we're not going to have one menu take the name of another $_possible_existing = get_term_by( 'name', $menu_data['menu-name'], 'nav_menu' ); if ( $_possible_existing && ! is_wp_error( $_possible_existing ) && isset( $_possible_existing->term_id ) && $_possible_existing->term_id != $menu_id ) { return new WP_Error( 'menu_exists', /* translators: %s: menu name */ sprintf( __( 'The menu name %s conflicts with another menu name. Please try another.' ), '' . esc_html( $menu_data['menu-name'] ) . '' ) ); } // menu doesn't already exist, so create a new menu if ( ! $_menu || is_wp_error( $_menu ) ) { $menu_exists = get_term_by( 'name', $menu_data['menu-name'], 'nav_menu' ); if ( $menu_exists ) { return new WP_Error( 'menu_exists', /* translators: %s: menu name */ sprintf( __( 'The menu name %s conflicts with another menu name. Please try another.' ), '' . esc_html( $menu_data['menu-name'] ) . '' ) ); } $_menu = wp_insert_term( $menu_data['menu-name'], 'nav_menu', $args ); if ( is_wp_error( $_menu ) ) { return $_menu; } /** * Fires after a navigation menu is successfully created. * * @since 3.0.0 * * @param int $term_id ID of the new menu. * @param array $menu_data An array of menu data. */ do_action( 'wp_create_nav_menu', $_menu['term_id'], $menu_data ); return (int) $_menu['term_id']; } if ( ! $_menu || ! isset( $_menu->term_id ) ) { return 0; } $menu_id = (int) $_menu->term_id; $update_response = wp_update_term( $menu_id, 'nav_menu', $args ); if ( is_wp_error( $update_response ) ) { return $update_response; } $menu_id = (int) $update_response['term_id']; /** * Fires after a navigation menu has been successfully updated. * * @since 3.0.0 * * @param int $menu_id ID of the updated menu. * @param array $menu_data An array of menu data. */ do_action( 'wp_update_nav_menu', $menu_id, $menu_data ); return $menu_id; } /** * Save the properties of a menu item or create a new one. * * The menu-item-title, menu-item-description, and menu-item-attr-title are expected * to be pre-slashed since they are passed directly into `wp_insert_post()`. * * @since 3.0.0 * * @param int $menu_id The ID of the menu. Required. If "0", makes the menu item a draft orphan. * @param int $menu_item_db_id The ID of the menu item. If "0", creates a new menu item. * @param array $menu_item_data The menu item's data. * @return int|WP_Error The menu item's database ID or WP_Error object on failure. */ function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item_data = array() ) { $menu_id = (int) $menu_id; $menu_item_db_id = (int) $menu_item_db_id; // make sure that we don't convert non-nav_menu_item objects into nav_menu_item objects if ( ! empty( $menu_item_db_id ) && ! is_nav_menu_item( $menu_item_db_id ) ) { return new WP_Error( 'update_nav_menu_item_failed', __( 'The given object ID is not that of a menu item.' ) ); } $menu = wp_get_nav_menu_object( $menu_id ); if ( ! $menu && 0 !== $menu_id ) { return new WP_Error( 'invalid_menu_id', __( 'Invalid menu ID.' ) ); } if ( is_wp_error( $menu ) ) { return $menu; } $defaults = array( 'menu-item-db-id' => $menu_item_db_id, 'menu-item-object-id' => 0, 'menu-item-object' => '', 'menu-item-parent-id' => 0, 'menu-item-position' => 0, 'menu-item-type' => 'custom', 'menu-item-title' => '', 'menu-item-url' => '', 'menu-item-description' => '', 'menu-item-attr-title' => '', 'menu-item-target' => '', 'menu-item-classes' => '', 'menu-item-xfn' => '', 'menu-item-status' => '', ); $args = wp_parse_args( $menu_item_data, $defaults ); if ( 0 == $menu_id ) { $args['menu-item-position'] = 1; } elseif ( 0 == (int) $args['menu-item-position'] ) { $menu_items = 0 == $menu_id ? array() : (array) wp_get_nav_menu_items( $menu_id, array( 'post_status' => 'publish,draft' ) ); $last_item = array_pop( $menu_items ); $args['menu-item-position'] = ( $last_item && isset( $last_item->menu_order ) ) ? 1 + $last_item->menu_order : count( $menu_items ); } $original_parent = 0 < $menu_item_db_id ? get_post_field( 'post_parent', $menu_item_db_id ) : 0; if ( 'custom' === $args['menu-item-type'] ) { // If custom menu item, trim the URL. $args['menu-item-url'] = trim( $args['menu-item-url'] ); } else { /* * If non-custom menu item, then: * - use the original object's URL. * - blank default title to sync with the original object's title. */ $args['menu-item-url'] = ''; $original_title = ''; if ( 'taxonomy' == $args['menu-item-type'] ) { $original_parent = get_term_field( 'parent', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' ); $original_title = get_term_field( 'name', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' ); } elseif ( 'post_type' == $args['menu-item-type'] ) { $original_object = get_post( $args['menu-item-object-id'] ); $original_parent = (int) $original_object->post_parent; $original_title = $original_object->post_title; } elseif ( 'post_type_archive' == $args['menu-item-type'] ) { $original_object = get_post_type_object( $args['menu-item-object'] ); if ( $original_object ) { $original_title = $original_object->labels->archives; } } if ( $args['menu-item-title'] == $original_title ) { $args['menu-item-title'] = ''; } // hack to get wp to create a post object when too many properties are empty if ( '' == $args['menu-item-title'] && '' == $args['menu-item-description'] ) { $args['menu-item-description'] = ' '; } } // Populate the menu item object $post = array( 'menu_order' => $args['menu-item-position'], 'ping_status' => 0, 'post_content' => $args['menu-item-description'], 'post_excerpt' => $args['menu-item-attr-title'], 'post_parent' => $original_parent, 'post_title' => $args['menu-item-title'], 'post_type' => 'nav_menu_item', ); $update = 0 != $menu_item_db_id; // New menu item. Default is draft status if ( ! $update ) { $post['ID'] = 0; $post['post_status'] = 'publish' == $args['menu-item-status'] ? 'publish' : 'draft'; $menu_item_db_id = wp_insert_post( $post ); if ( ! $menu_item_db_id || is_wp_error( $menu_item_db_id ) ) { return $menu_item_db_id; } /** * Fires immediately after a new navigation menu item has been added. * * @since 4.4.0 * * @see wp_update_nav_menu_item() * * @param int $menu_id ID of the updated menu. * @param int $menu_item_db_id ID of the new menu item. * @param array $args An array of arguments used to update/add the menu item. */ do_action( 'wp_add_nav_menu_item', $menu_id, $menu_item_db_id, $args ); } // Associate the menu item with the menu term // Only set the menu term if it isn't set to avoid unnecessary wp_get_object_terms() if ( $menu_id && ( ! $update || ! is_object_in_term( $menu_item_db_id, 'nav_menu', (int) $menu->term_id ) ) ) { wp_set_object_terms( $menu_item_db_id, array( $menu->term_id ), 'nav_menu' ); } if ( 'custom' == $args['menu-item-type'] ) { $args['menu-item-object-id'] = $menu_item_db_id; $args['menu-item-object'] = 'custom'; } $menu_item_db_id = (int) $menu_item_db_id; update_post_meta( $menu_item_db_id, '_menu_item_type', sanitize_key( $args['menu-item-type'] ) ); update_post_meta( $menu_item_db_id, '_menu_item_menu_item_parent', strval( (int) $args['menu-item-parent-id'] ) ); update_post_meta( $menu_item_db_id, '_menu_item_object_id', strval( (int) $args['menu-item-object-id'] ) ); update_post_meta( $menu_item_db_id, '_menu_item_object', sanitize_key( $args['menu-item-object'] ) ); update_post_meta( $menu_item_db_id, '_menu_item_target', sanitize_key( $args['menu-item-target'] ) ); $args['menu-item-classes'] = array_map( 'sanitize_html_class', explode( ' ', $args['menu-item-classes'] ) ); $args['menu-item-xfn'] = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['menu-item-xfn'] ) ) ); update_post_meta( $menu_item_db_id, '_menu_item_classes', $args['menu-item-classes'] ); update_post_meta( $menu_item_db_id, '_menu_item_xfn', $args['menu-item-xfn'] ); update_post_meta( $menu_item_db_id, '_menu_item_url', esc_url_raw( $args['menu-item-url'] ) ); if ( 0 == $menu_id ) { update_post_meta( $menu_item_db_id, '_menu_item_orphaned', (string) time() ); } elseif ( get_post_meta( $menu_item_db_id, '_menu_item_orphaned' ) ) { delete_post_meta( $menu_item_db_id, '_menu_item_orphaned' ); } // Update existing menu item. Default is publish status if ( $update ) { $post['ID'] = $menu_item_db_id; $post['post_status'] = 'draft' == $args['menu-item-status'] ? 'draft' : 'publish'; wp_update_post( $post ); } /** * Fires after a navigation menu item has been updated. * * @since 3.0.0 * * @see wp_update_nav_menu_item() * * @param int $menu_id ID of the updated menu. * @param int $menu_item_db_id ID of the updated menu item. * @param array $args An array of arguments used to update a menu item. */ do_action( 'wp_update_nav_menu_item', $menu_id, $menu_item_db_id, $args ); return $menu_item_db_id; } /** * Returns all navigation menu objects. * * @since 3.0.0 * @since 4.1.0 Default value of the 'orderby' argument was changed from 'none' * to 'name'. * * @param array $args Optional. Array of arguments passed on to get_terms(). * Default empty array. * @return array Menu objects. */ function wp_get_nav_menus( $args = array() ) { $defaults = array( 'hide_empty' => false, 'orderby' => 'name', ); $args = wp_parse_args( $args, $defaults ); /** * Filters the navigation menu objects being returned. * * @since 3.0.0 * * @see get_terms() * * @param array $menus An array of menu objects. * @param array $args An array of arguments used to retrieve menu objects. */ return apply_filters( 'wp_get_nav_menus', get_terms( 'nav_menu', $args ), $args ); } /** * Return if a menu item is valid. * * @link https://core.trac.wordpress.org/ticket/13958 * * @since 3.2.0 * @access private * * @param object $item The menu item to check. * @return bool False if invalid, otherwise true. */ function _is_valid_nav_menu_item( $item ) { return empty( $item->_invalid ); } /** * Retrieves all menu items of a navigation menu. * * Note: Most arguments passed to the `$args` parameter – save for 'output_key' – are * specifically for retrieving nav_menu_item posts from get_posts() and may only * indirectly affect the ultimate ordering and content of the resulting nav menu * items that get returned from this function. * * @since 3.0.0 * * @staticvar array $fetched * * @param int|string|WP_Term $menu Menu ID, slug, name, or object. * @param array $args { * Optional. Arguments to pass to get_posts(). * * @type string $order How to order nav menu items as queried with get_posts(). Will be ignored * if 'output' is ARRAY_A. Default 'ASC'. * @type string $orderby Field to order menu items by as retrieved from get_posts(). Supply an orderby * field via 'output_key' to affect the output order of nav menu items. * Default 'menu_order'. * @type string $post_type Menu items post type. Default 'nav_menu_item'. * @type string $post_status Menu items post status. Default 'publish'. * @type string $output How to order outputted menu items. Default ARRAY_A. * @type string $output_key Key to use for ordering the actual menu items that get returned. Note that * that is not a get_posts() argument and will only affect output of menu items * processed in this function. Default 'menu_order'. * @type bool $nopaging Whether to retrieve all menu items (true) or paginate (false). Default true. * } * @return false|array $items Array of menu items, otherwise false. */ function wp_get_nav_menu_items( $menu, $args = array() ) { $menu = wp_get_nav_menu_object( $menu ); if ( ! $menu ) { return false; } static $fetched = array(); $items = get_objects_in_term( $menu->term_id, 'nav_menu' ); if ( is_wp_error( $items ) ) { return false; } $defaults = array( 'order' => 'ASC', 'orderby' => 'menu_order', 'post_type' => 'nav_menu_item', 'post_status' => 'publish', 'output' => ARRAY_A, 'output_key' => 'menu_order', 'nopaging' => true, ); $args = wp_parse_args( $args, $defaults ); $args['include'] = $items; if ( ! empty( $items ) ) { $items = get_posts( $args ); } else { $items = array(); } // Get all posts and terms at once to prime the caches if ( empty( $fetched[ $menu->term_id ] ) && ! wp_using_ext_object_cache() ) { $fetched[ $menu->term_id ] = true; $posts = array(); $terms = array(); foreach ( $items as $item ) { $object_id = get_post_meta( $item->ID, '_menu_item_object_id', true ); $object = get_post_meta( $item->ID, '_menu_item_object', true ); $type = get_post_meta( $item->ID, '_menu_item_type', true ); if ( 'post_type' == $type ) { $posts[ $object ][] = $object_id; } elseif ( 'taxonomy' == $type ) { $terms[ $object ][] = $object_id; } } if ( ! empty( $posts ) ) { foreach ( array_keys( $posts ) as $post_type ) { get_posts( array( 'post__in' => $posts[ $post_type ], 'post_type' => $post_type, 'nopaging' => true, 'update_post_term_cache' => false, ) ); } } unset( $posts ); if ( ! empty( $terms ) ) { foreach ( array_keys( $terms ) as $taxonomy ) { get_terms( $taxonomy, array( 'include' => $terms[ $taxonomy ], 'hierarchical' => false, ) ); } } unset( $terms ); } $items = array_map( 'wp_setup_nav_menu_item', $items ); if ( ! is_admin() ) { // Remove invalid items only in front end $items = array_filter( $items, '_is_valid_nav_menu_item' ); } if ( ARRAY_A == $args['output'] ) { $items = wp_list_sort( $items, array( $args['output_key'] => 'ASC', ) ); $i = 1; foreach ( $items as $k => $item ) { $items[ $k ]->{$args['output_key']} = $i++; } } /** * Filters the navigation menu items being returned. * * @since 3.0.0 * * @param array $items An array of menu item post objects. * @param object $menu The menu object. * @param array $args An array of arguments used to retrieve menu item objects. */ return apply_filters( 'wp_get_nav_menu_items', $items, $menu, $args ); } /** * Decorates a menu item object with the shared navigation menu item properties. * * Properties: * - ID: The term_id if the menu item represents a taxonomy term. * - attr_title: The title attribute of the link element for this menu item. * - classes: The array of class attribute values for the link element of this menu item. * - db_id: The DB ID of this item as a nav_menu_item object, if it exists (0 if it doesn't exist). * - description: The description of this menu item. * - menu_item_parent: The DB ID of the nav_menu_item that is this item's menu parent, if any. 0 otherwise. * - object: The type of object originally represented, such as "category," "post", or "attachment." * - object_id: The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories. * - post_parent: The DB ID of the original object's parent object, if any (0 otherwise). * - post_title: A "no title" label if menu item represents a post that lacks a title. * - target: The target attribute of the link element for this menu item. * - title: The title of this menu item. * - type: The family of objects originally represented, such as "post_type" or "taxonomy." * - type_label: The singular label used to describe this type of menu item. * - url: The URL to which this menu item points. * - xfn: The XFN relationship expressed in the link of this menu item. * - _invalid: Whether the menu item represents an object that no longer exists. * * @since 3.0.0 * * @param object $menu_item The menu item to modify. * @return object $menu_item The menu item with standard menu item properties. */ function wp_setup_nav_menu_item( $menu_item ) { if ( isset( $menu_item->post_type ) ) { if ( 'nav_menu_item' == $menu_item->post_type ) { $menu_item->db_id = (int) $menu_item->ID; $menu_item->menu_item_parent = ! isset( $menu_item->menu_item_parent ) ? get_post_meta( $menu_item->ID, '_menu_item_menu_item_parent', true ) : $menu_item->menu_item_parent; $menu_item->object_id = ! isset( $menu_item->object_id ) ? get_post_meta( $menu_item->ID, '_menu_item_object_id', true ) : $menu_item->object_id; $menu_item->object = ! isset( $menu_item->object ) ? get_post_meta( $menu_item->ID, '_menu_item_object', true ) : $menu_item->object; $menu_item->type = ! isset( $menu_item->type ) ? get_post_meta( $menu_item->ID, '_menu_item_type', true ) : $menu_item->type; if ( 'post_type' == $menu_item->type ) { $object = get_post_type_object( $menu_item->object ); if ( $object ) { $menu_item->type_label = $object->labels->singular_name; } else { $menu_item->type_label = $menu_item->object; $menu_item->_invalid = true; } if ( 'trash' === get_post_status( $menu_item->object_id ) ) { $menu_item->_invalid = true; } $menu_item->url = get_permalink( $menu_item->object_id ); $original_object = get_post( $menu_item->object_id ); /** This filter is documented in wp-includes/post-template.php */ $original_title = apply_filters( 'the_title', $original_object->post_title, $original_object->ID ); if ( '' === $original_title ) { /* translators: %d: ID of a post */ $original_title = sprintf( __( '#%d (no title)' ), $original_object->ID ); } $menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title; } elseif ( 'post_type_archive' == $menu_item->type ) { $object = get_post_type_object( $menu_item->object ); if ( $object ) { $menu_item->title = '' == $menu_item->post_title ? $object->labels->archives : $menu_item->post_title; $post_type_description = $object->description; } else { $menu_item->_invalid = true; $post_type_description = ''; } $menu_item->type_label = __( 'Post Type Archive' ); $post_content = wp_trim_words( $menu_item->post_content, 200 ); $post_type_description = '' == $post_content ? $post_type_description : $post_content; $menu_item->url = get_post_type_archive_link( $menu_item->object ); } elseif ( 'taxonomy' == $menu_item->type ) { $object = get_taxonomy( $menu_item->object ); if ( $object ) { $menu_item->type_label = $object->labels->singular_name; } else { $menu_item->type_label = $menu_item->object; $menu_item->_invalid = true; } $term_url = get_term_link( (int) $menu_item->object_id, $menu_item->object ); $menu_item->url = ! is_wp_error( $term_url ) ? $term_url : ''; $original_title = get_term_field( 'name', $menu_item->object_id, $menu_item->object, 'raw' ); if ( is_wp_error( $original_title ) ) { $original_title = false; } $menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title; } else { $menu_item->type_label = __( 'Custom Link' ); $menu_item->title = $menu_item->post_title; $menu_item->url = ! isset( $menu_item->url ) ? get_post_meta( $menu_item->ID, '_menu_item_url', true ) : $menu_item->url; } $menu_item->target = ! isset( $menu_item->target ) ? get_post_meta( $menu_item->ID, '_menu_item_target', true ) : $menu_item->target; /** * Filters a navigation menu item's title attribute. * * @since 3.0.0 * * @param string $item_title The menu item title attribute. */ $menu_item->attr_title = ! isset( $menu_item->attr_title ) ? apply_filters( 'nav_menu_attr_title', $menu_item->post_excerpt ) : $menu_item->attr_title; if ( ! isset( $menu_item->description ) ) { /** * Filters a navigation menu item's description. * * @since 3.0.0 * * @param string $description The menu item description. */ $menu_item->description = apply_filters( 'nav_menu_description', wp_trim_words( $menu_item->post_content, 200 ) ); } $menu_item->classes = ! isset( $menu_item->classes ) ? (array) get_post_meta( $menu_item->ID, '_menu_item_classes', true ) : $menu_item->classes; $menu_item->xfn = ! isset( $menu_item->xfn ) ? get_post_meta( $menu_item->ID, '_menu_item_xfn', true ) : $menu_item->xfn; } else { $menu_item->db_id = 0; $menu_item->menu_item_parent = 0; $menu_item->object_id = (int) $menu_item->ID; $menu_item->type = 'post_type'; $object = get_post_type_object( $menu_item->post_type ); $menu_item->object = $object->name; $menu_item->type_label = $object->labels->singular_name; if ( '' === $menu_item->post_title ) { /* translators: %d: ID of a post */ $menu_item->post_title = sprintf( __( '#%d (no title)' ), $menu_item->ID ); } $menu_item->title = $menu_item->post_title; $menu_item->url = get_permalink( $menu_item->ID ); $menu_item->target = ''; /** This filter is documented in wp-includes/nav-menu.php */ $menu_item->attr_title = apply_filters( 'nav_menu_attr_title', '' ); /** This filter is documented in wp-includes/nav-menu.php */ $menu_item->description = apply_filters( 'nav_menu_description', '' ); $menu_item->classes = array(); $menu_item->xfn = ''; } } elseif ( isset( $menu_item->taxonomy ) ) { $menu_item->ID = $menu_item->term_id; $menu_item->db_id = 0; $menu_item->menu_item_parent = 0; $menu_item->object_id = (int) $menu_item->term_id; $menu_item->post_parent = (int) $menu_item->parent; $menu_item->type = 'taxonomy'; $object = get_taxonomy( $menu_item->taxonomy ); $menu_item->object = $object->name; $menu_item->type_label = $object->labels->singular_name; $menu_item->title = $menu_item->name; $menu_item->url = get_term_link( $menu_item, $menu_item->taxonomy ); $menu_item->target = ''; $menu_item->attr_title = ''; $menu_item->description = get_term_field( 'description', $menu_item->term_id, $menu_item->taxonomy ); $menu_item->classes = array(); $menu_item->xfn = ''; } /** * Filters a navigation menu item object. * * @since 3.0.0 * * @param object $menu_item The menu item object. */ return apply_filters( 'wp_setup_nav_menu_item', $menu_item ); } /** * Get the menu items associated with a particular object. * * @since 3.0.0 * * @param int $object_id The ID of the original object. * @param string $object_type The type of object, such as "taxonomy" or "post_type." * @param string $taxonomy If $object_type is "taxonomy", $taxonomy is the name of the tax that $object_id belongs to * @return array The array of menu item IDs; empty array if none; */ function wp_get_associated_nav_menu_items( $object_id = 0, $object_type = 'post_type', $taxonomy = '' ) { $object_id = (int) $object_id; $menu_item_ids = array(); $query = new WP_Query; $menu_items = $query->query( array( 'meta_key' => '_menu_item_object_id', 'meta_value' => $object_id, 'post_status' => 'any', 'post_type' => 'nav_menu_item', 'posts_per_page' => -1, ) ); foreach ( (array) $menu_items as $menu_item ) { if ( isset( $menu_item->ID ) && is_nav_menu_item( $menu_item->ID ) ) { $menu_item_type = get_post_meta( $menu_item->ID, '_menu_item_type', true ); if ( 'post_type' == $object_type && 'post_type' == $menu_item_type ) { $menu_item_ids[] = (int) $menu_item->ID; } elseif ( 'taxonomy' == $object_type && 'taxonomy' == $menu_item_type && get_post_meta( $menu_item->ID, '_menu_item_object', true ) == $taxonomy ) { $menu_item_ids[] = (int) $menu_item->ID; } } } return array_unique( $menu_item_ids ); } /** * Callback for handling a menu item when its original object is deleted. * * @since 3.0.0 * @access private * * @param int $object_id The ID of the original object being trashed. */ function _wp_delete_post_menu_item( $object_id = 0 ) { $object_id = (int) $object_id; $menu_item_ids = wp_get_associated_nav_menu_items( $object_id, 'post_type' ); foreach ( (array) $menu_item_ids as $menu_item_id ) { wp_delete_post( $menu_item_id, true ); } } /** * Serves as a callback for handling a menu item when its original object is deleted. * * @since 3.0.0 * @access private * * @param int $object_id Optional. The ID of the original object being trashed. Default 0. * @param int $tt_id Term taxonomy ID. Unused. * @param string $taxonomy Taxonomy slug. */ function _wp_delete_tax_menu_item( $object_id = 0, $tt_id, $taxonomy ) { $object_id = (int) $object_id; $menu_item_ids = wp_get_associated_nav_menu_items( $object_id, 'taxonomy', $taxonomy ); foreach ( (array) $menu_item_ids as $menu_item_id ) { wp_delete_post( $menu_item_id, true ); } } /** * Automatically add newly published page objects to menus with that as an option. * * @since 3.0.0 * @access private * * @param string $new_status The new status of the post object. * @param string $old_status The old status of the post object. * @param object $post The post object being transitioned from one status to another. */ function _wp_auto_add_pages_to_menu( $new_status, $old_status, $post ) { if ( 'publish' != $new_status || 'publish' == $old_status || 'page' != $post->post_type ) { return; } if ( ! empty( $post->post_parent ) ) { return; } $auto_add = get_option( 'nav_menu_options' ); if ( empty( $auto_add ) || ! is_array( $auto_add ) || ! isset( $auto_add['auto_add'] ) ) { return; } $auto_add = $auto_add['auto_add']; if ( empty( $auto_add ) || ! is_array( $auto_add ) ) { return; } $args = array( 'menu-item-object-id' => $post->ID, 'menu-item-object' => $post->post_type, 'menu-item-type' => 'post_type', 'menu-item-status' => 'publish', ); foreach ( $auto_add as $menu_id ) { $items = wp_get_nav_menu_items( $menu_id, array( 'post_status' => 'publish,draft' ) ); if ( ! is_array( $items ) ) { continue; } foreach ( $items as $item ) { if ( $post->ID == $item->object_id ) { continue 2; } } wp_update_nav_menu_item( $menu_id, 0, $args ); } } /** * Delete auto-draft posts associated with the supplied changeset. * * @since 4.8.0 * @access private * * @param int $post_id Post ID for the customize_changeset. */ function _wp_delete_customize_changeset_dependent_auto_drafts( $post_id ) { $post = get_post( $post_id ); if ( ! $post || 'customize_changeset' !== $post->post_type ) { return; } $data = json_decode( $post->post_content, true ); if ( empty( $data['nav_menus_created_posts']['value'] ) ) { return; } remove_action( 'delete_post', '_wp_delete_customize_changeset_dependent_auto_drafts' ); foreach ( $data['nav_menus_created_posts']['value'] as $stub_post_id ) { if ( empty( $stub_post_id ) ) { continue; } if ( 'auto-draft' === get_post_status( $stub_post_id ) ) { wp_delete_post( $stub_post_id, true ); } elseif ( 'draft' === get_post_status( $stub_post_id ) ) { wp_trash_post( $stub_post_id ); delete_post_meta( $stub_post_id, '_customize_changeset_uuid' ); } } add_action( 'delete_post', '_wp_delete_customize_changeset_dependent_auto_drafts' ); } /** * Handle menu config after theme change. * * @access private * @since 4.9.0 */ function _wp_menus_changed() { $old_nav_menu_locations = get_option( 'theme_switch_menu_locations', array() ); $new_nav_menu_locations = get_nav_menu_locations(); $mapped_nav_menu_locations = wp_map_nav_menu_locations( $new_nav_menu_locations, $old_nav_menu_locations ); set_theme_mod( 'nav_menu_locations', $mapped_nav_menu_locations ); delete_option( 'theme_switch_menu_locations' ); } /** * Maps nav menu locations according to assignments in previously active theme. * * @since 4.9.0 * * @param array $new_nav_menu_locations New nav menu locations assignments. * @param array $old_nav_menu_locations Old nav menu locations assignments. * @return array Nav menus mapped to new nav menu locations. */ function wp_map_nav_menu_locations( $new_nav_menu_locations, $old_nav_menu_locations ) { $registered_nav_menus = get_registered_nav_menus(); $new_nav_menu_locations = array_intersect_key( $new_nav_menu_locations, $registered_nav_menus ); // Short-circuit if there are no old nav menu location assignments to map. if ( empty( $old_nav_menu_locations ) ) { return $new_nav_menu_locations; } // If old and new theme have just one location, map it and we're done. if ( 1 === count( $old_nav_menu_locations ) && 1 === count( $registered_nav_menus ) ) { $new_nav_menu_locations[ key( $registered_nav_menus ) ] = array_pop( $old_nav_menu_locations ); return $new_nav_menu_locations; } $old_locations = array_keys( $old_nav_menu_locations ); // Map locations with the same slug. foreach ( $registered_nav_menus as $location => $name ) { if ( in_array( $location, $old_locations, true ) ) { $new_nav_menu_locations[ $location ] = $old_nav_menu_locations[ $location ]; unset( $old_nav_menu_locations[ $location ] ); } } // If there are no old nav menu locations left, then we're done. if ( empty( $old_nav_menu_locations ) ) { return $new_nav_menu_locations; } /* * If old and new theme both have locations that contain phrases * from within the same group, make an educated guess and map it. */ $common_slug_groups = array( array( 'primary', 'menu-1', 'main', 'header', 'navigation', 'top' ), array( 'secondary', 'menu-2', 'footer', 'subsidiary', 'bottom' ), array( 'social' ), ); // Go through each group... foreach ( $common_slug_groups as $slug_group ) { // ...and see if any of these slugs... foreach ( $slug_group as $slug ) { // ...and any of the new menu locations... foreach ( $registered_nav_menus as $new_location => $name ) { // ...actually match! if ( is_string( $new_location ) && false === stripos( $new_location, $slug ) && false === stripos( $slug, $new_location ) ) { continue; } elseif ( is_numeric( $new_location ) && $new_location !== $slug ) { continue; } // Then see if any of the old locations... foreach ( $old_nav_menu_locations as $location => $menu_id ) { // ...and any slug in the same group... foreach ( $slug_group as $slug ) { // ... have a match as well. if ( is_string( $location ) && false === stripos( $location, $slug ) && false === stripos( $slug, $location ) ) { continue; } elseif ( is_numeric( $location ) && $location !== $slug ) { continue; } // Make sure this location wasn't mapped and removed previously. if ( ! empty( $old_nav_menu_locations[ $location ] ) ) { // We have a match that can be mapped! $new_nav_menu_locations[ $new_location ] = $old_nav_menu_locations[ $location ]; // Remove the mapped location so it can't be mapped again. unset( $old_nav_menu_locations[ $location ] ); // Go back and check the next new menu location. continue 3; } } // endforeach ( $slug_group as $slug ) } // endforeach ( $old_nav_menu_locations as $location => $menu_id ) } // endforeach foreach ( $registered_nav_menus as $new_location => $name ) } // endforeach ( $slug_group as $slug ) } // endforeach ( $common_slug_groups as $slug_group ) return $new_nav_menu_locations; } /** * REST API: WP_REST_Comment_Meta_Fields class * * @package WordPress * @subpackage REST_API * @since 4.7.0 */ /** * Core class to manage comment meta via the REST API. * * @since 4.7.0 * * @see WP_REST_Meta_Fields */ class WP_REST_Comment_Meta_Fields extends WP_REST_Meta_Fields { /** * Retrieves the object type for comment meta. * * @since 4.7.0 * * @return string The meta type. */ protected function get_meta_type() { return 'comment'; } /** * Retrieves the object meta subtype. * * @since 4.9.8 * * @return string 'comment' There are no subtypes. */ protected function get_meta_subtype() { return 'comment'; } /** * Retrieves the type for register_rest_field() in the context of comments. * * @since 4.7.0 * * @return string The REST field type. */ public function get_rest_field_type() { return 'comment'; } }