Удаление всех родителей, кроме самого верхнего из ЧПУ страниц
Нужно у структуры ЧПУ (страниц) убрать всех родителей, кроме самого верхнего. Например example.com/rod1/rod2/rod3/pagename
- надо сделать example.com/rod1/pagename
.
Решение
/** * Delete all parents from static page permalink, except top parent. * * What we need to achieve: * /parent/child1/child2/child3/ >>> /parent/child3/ * /parent/child1/child2/ >>> /parent/child2/ * /parent/child1/ >>> /parent/child1/ * /parent/ >>> /parent/ * * For usage just init the class, like so: * Delete_Page_URI_Parents::init(); * * @author Kama * * @version 1.0 */ final class Delete_Page_URI_Parents { static $origin_REQUEST_URI = ''; static $skip_link_change = false; static function init(){ // изменим пермалинк add_filter( 'page_link', [ __CLASS__, 'page_permalink' ] ); // изменяем $_SERVER['REQUEST_URI'] на фильтре `do_parse_request` // и возвращаем пердыдущее значение обратно на фильтре `request` // между ними ВП определяет какая сейчас страница. add_filter( 'do_parse_request', [ __CLASS__, 'replace_uri' ] ); add_filter( 'request', [ __CLASS__, 'replace_uri_back' ] ); } static function page_permalink( $link ){ if( self::$skip_link_change ) return $link; $endslash = '/' === $link{-1} ? '/' : ''; $parts = explode( '/', rtrim( $link, '/' ) ); // our case if( count( $parts ) > 5 ){ $last = end( $parts ); $parts = array_slice( $parts, 0, 4 ); $link = implode( '/', $parts ) ."/$last$endslash"; } return $link; } static function replace_uri( $foo ){ global $wpdb, $wp_rewrite; list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] ); $req_uri = trim( $req_uri, '/' ); // there is no slashes in uri - not our case if( ! substr_count( $req_uri, '/' ) ) return $foo; // Let's do it! list( $req_uri_prefix ) = explode( '/', $req_uri ); // Check all rewrite rules foreach( get_option( 'rewrite_rules' ) as $match => $query ){ list( $match_prefix ) = explode( '/', $match ); if( // URL starts with known prefix: category/foo/bar ( ltrim( $match_prefix, '^' ) === $req_uri_prefix ) || // URL starts with nember: 2019/08/10 is_numeric( $req_uri_prefix ) ){ return $foo; } // Try to find page rewrite rule // and take page path from current URL using found rewrite rule if( strpos( $query, 'pagename=' ) && // for performance ( preg_match( "#^$match#", $req_uri, $matches ) || preg_match( "#^$match#", urldecode( $req_uri ), $matches ) ) && ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) ){ $page_path = $matches[ $varmatch[1] ]; $page_name = basename( $page_path ); // we need at least 1 slash: parent/child2 if( ! substr_count( $page_path, '/' ) ) return $foo; //die( print_r( $req_uri_prefix ) ); //die( print_r( get_option( 'rewrite_rules' ) ) ); //die( print_r( $wp_rewrite ) ); $page = $wpdb->get_row( "SELECT * FROM $wpdb->posts WHERE post_name = '". esc_sql( $page_name ) ."' AND post_type = 'page' AND post_status = 'publish' LIMIT 1" ); // page found if( $page ){ self::$origin_REQUEST_URI = $_SERVER['REQUEST_URI']; $page = get_post( $page ); self::$skip_link_change = 1; $real_page_uri = wp_make_link_relative( get_permalink($page) ); self::$skip_link_change = 0; // make a substitution $_SERVER['REQUEST_URI'] = $real_page_uri; // SEO Redirect // to correct URL, when full path uses in page URL if( substr_count( trim($real_page_uri, '/'), '/' ) > 1 && false !== strpos( self::$origin_REQUEST_URI, $real_page_uri ) ){ wp_redirect( get_permalink($page), 301 ); exit; } } break; // rewrite rule is found, further looking and checks makes no sense } } return $foo; // for filter } static function replace_uri_back( $foo ){ if( self::$origin_REQUEST_URI ) $_SERVER['REQUEST_URI'] = self::$origin_REQUEST_URI; return $foo; // for filter } } Delete_Page_URI_Parents::init();