动态添加重写规则

时间:2022-01-14 作者:yevg

我试图动态添加一个重写规则,允许用户访问我选择的另一个永久链接结构下的任何页面。

例如,如果交替permalink结构包括段塞foo/ 在第一个帖子中,我想添加一个重写规则,以便:

example.com/foo/my-page 重写到example.com/my-page

example.com/foo/my-cool/blog/post 重写到example.com/my-cool/blog/post

因此,基本上,无论查询是针对页面、帖子还是任何其他类型的自定义内容,我都希望在/foo/ slug以及原始的非foo URL结构。

我已经编写了一个工作函数,它通过..来实现这一点。。

读取URI从URI中删除段塞,遍历所有现有重写规则,将URI与删除的段塞匹配到现有重写规则,获取匹配组以匹配重写规则将其值作为目标以下是代码:

// functions.php

add_filter(\'rewrite_rules_array\', function($rules) {

    $slug = \'foo\';

    // get the request URI
    $uri = $_SERVER[\'REQUEST_URI\'];
    
    // determine whether URI has slug in the first position
    if(preg_match(\'/^(\\/\' . $slug . \')/\', $uri)){

        // get the base URI by removing the slug
        $base_uri = str_replace(\'/\'.$slug,\'\',$uri);

        // loop through existing rewrite rules
        foreach($rules as $src => $dest){

            // find the rewrite rule for which the base URI would have matched
            $regex_to_match = \'/\' . str_replace(\'/\',\'\\/\',$src) . \'/\';
            preg_match_all($regex_to_match, $base_uri, $matches, PREG_SET_ORDER);

            if(count($matches) > 0){

                // get the specific matching groups
                $matches = $matches[0]; 

                // compile valid regex from URI with slug to create new rewrite source
                $new_src = ($uri[0] == \'/\' ? substr($uri, 1) : $uri) . \'?$\';
                
                // replace match variables with their string values to create new rewrite destination
                for($i=1; $i<count($matches)+1; $i++){
                    $replacement = isset($matches[$i]) ? $matches[$i] : \'\';
                    $dest = str_replace(\'$matches[\' . $i . \']\', $replacement, $dest);
                }
                $new_dest = $dest;

                // add new rewrite rule to $wp_rewrite rules array
                $rules[$new_src] = $new_dest;

                // add the write rule
                add_rewrite_rule($new_src,$new_dest,\'top\');

                break;
            }
        }
    }

    return $rules;

});

flush_rewrite_rules();
这可以工作,但仅适用于具有多个段塞的URL。

example.com/foo/my-page/123 正确重写!

example.com/foo/abc/defg/bar 正确重写!

example.com/foo/abc DOES NOT 正确重写。而是重定向到example.com/abc

与相同example.com/foo/my-page -- 它重定向到example.com/my-page

1 个回复
SO网友:brianjohnhanna

更新代码的问题在于add_rewrite_rule() 在过滤器内部,它无法将其正确添加到列表的顶部。如果您将$rules 大堆因为它被添加到$rules 列表中,WP提前介入,在后台使用一些魔法单独匹配slug。

为了绕过这个过程,您必须手动将其添加到列表的顶部,并从过滤器返回。

具体来说,您需要更改add_rewrite_rule() 调用此:

$rules = [$new_src => $new_dest] + $rules;

我在下面包含了完整的更新代码。

add_filter(\'rewrite_rules_array\', function($rules) {

    $slug = \'foo\';

    // get the request URI
    $uri = $_SERVER[\'REQUEST_URI\'];
    
    // determine whether URI has slug in the first position
    if(preg_match(\'/^(\\/\' . $slug . \')/\', $uri)){

        // get the base URI by removing the slug
        $base_uri = str_replace(\'/\'.$slug,\'\',$uri);

        // loop through existing rewrite rules
        foreach($rules as $src => $dest){

            // find the rewrite rule for which the base URI would have matched
            $regex_to_match = \'/\' . str_replace(\'/\',\'\\/\',$src) . \'/\';
            
            preg_match_all($regex_to_match, $base_uri, $matches, PREG_SET_ORDER);


            if(count($matches) > 0){

                // get the specific matching groups
                $matches = $matches[0]; 

                // compile valid regex from URI with slug to create new rewrite source
                $new_src = ($uri[0] == \'/\' ? substr($uri, 1) : $uri) . \'?$\';
                
                // replace match variables with their string values to create new rewrite destination
                for($i=1; $i<count($matches)+1; $i++){
                    $replacement = isset($matches[$i]) ? $matches[$i] : \'\';
                    $replacement = strpos($replacement, \'/\') === 0 ? substr($replacement, 1) : $replacement;
                    $dest = str_replace(\'$matches[\' . $i . \']\', $replacement, $dest);
                }
                $new_dest = $dest;

                // add new rewrite rule to $wp_rewrite rules array
                $rules = [$new_src => $new_dest] + $rules;

                break;
            }
        }
    }

    

    return $rules;

});
这样做仍然感觉很奇怪,我相信还有更好的方法,但如果不更好地理解您的用例,我真的无法提供其他建议。对我来说,这里最大的问题是您正在刷新每个请求的重写规则,这可能是一个昂贵的操作。

最初的答案,我不会generate_rewrite_rules 为了这个。您可以使用regular rewrite rules API.

测试了以下内容,可用于重定向http://example.com/foo/test/123https://example.com/test/123. 可以根据您的需要进行定制。将其放入函数中。php或功能插件。

add_action( \'init\',  function() {
    add_rewrite_rule( \'foo/([a-z0-9-/]+)[/]?$\', \'index.php?foo_redirect_to=$matches[1]\', \'top\' );
} );

add_filter( \'query_vars\', function( $query_vars ) {
    $query_vars[] = \'foo_redirect_to\';
    return $query_vars;
} );

add_action(\'template_redirect\', function() {
    if ( ( $redirect_to = get_query_var( \'foo_redirect_to\' ) ) == false ) {
        return;
    }

    wp_redirect("https://example.com/$redirect_to");
});

相关推荐

绕过WP查询中的“supress_Filters”

显然,出于某种不合逻辑的原因,开发人员决定获取所有语言帖子的唯一方法是添加supress_filters=true 到WP\\u查询(而不是像这样language_code=all 选项)。无论如何,我的情况是,我需要获取所有语言的帖子,但也需要使用过滤器修改WP\\u查询。有没有办法强制将我的过滤器添加到查询中,即使supress_filters 设置为false?这是我需要添加的过滤器:add_filter( \'posts_where\', function($where, $wp_query) {