Удаление всех родителей, кроме самого верхнего из ЧПУ страниц
Нужно у структуры ЧПУ (страниц) убрать всех родителей, кроме самого верхнего. Например 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();