如何从WordPress URL中删除自定义文章类型?

3
我有一个使用自定义模板和自定义文章类型(如landing和services)的WordPress网站。
每个文章类型在URL中都有特定的slug,例如:(http://example.com/landing/landing-page-name)
我想将此URL (http://example.com/landing/landing-page-name) 更改为这个URL (http://example.com/landing-page-name)。
实际上,我需要从URL中删除“landing”短语。重要的是,“landing”是我的文章表中的自定义文章类型。
我已经尝试了以下解决方案:
==> 我在register_post_type()中将slug更改为'/' --> 它会破坏所有landings、posts和pages的URL(404)
==> 我将'rewrite'属性中的'with_front' => false添加到rewrite属性中 --> 没有任何变化

==> 我尝试在htaccess中使用RewriteRule来实现这个 --> 但它没有起作用或者给出了太多的重定向错误。

我无法得到正确的结果。

有人之前解决过这个问题吗?

4个回答

7

首先,您需要过滤自定义文章类型的永久链接,以便所有已发布的文章在其URL中都没有该slug:

function stackoverflow_remove_cpt_slug( $post_link, $post ) {
    if ( 'landing' === $post->post_type && 'publish' === $post->post_status ) {
        $post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
    }
    return $post_link;
}
add_filter( 'post_type_link', 'stackoverflow_remove_cpt_slug', 10, 2 );

此时,尝试查看链接会导致404(页面未找到)错误。这是因为WordPress只知道帖子和页面可以具有像domain.com/post-name/domain.com/page-name/这样的URL。我们需要教它我们自定义文章类型的文章也可以具有像domain.com/cpt-post-name/这样的URL。
function stackoverflow_add_cpt_post_names_to_main_query( $query ) {
    // Return if this is not the main query.
    if ( ! $query->is_main_query() ) {
        return;
    }
    // Return if this query doesn't match our very specific rewrite rule.
    if ( ! isset( $query->query['page'] ) || 2 !== count( $query->query ) ) {
        return;
    }
    // Return if we're not querying based on the post name.
    if ( empty( $query->query['name'] ) ) {
        return;
    }
    // Add CPT to the list of post types WP will include when it queries based on the post name.
    $query->set( 'post_type', array( 'post', 'page', 'landing' ) );
}
add_action( 'pre_get_posts', 'stackoverflow_add_cpt_post_names_to_main_query' );

嗨 @entreprenerds 谢谢你的回答。 你能告诉我应该在哪里使用这些代码吗? 是在WordPress核心还是在我的模板中?以及在哪个文件中? - undefined
我不知道如何使用这些代码。 你能帮助我吗? @entreprenerds - undefined
抱歉 - 你只需要将它们粘贴到你的 functions.php 文件中即可。function {..} 代码定义了我们想要使用的新函数,然后 add_filteradd_action 命令告诉 WordPress 何时使用它们。 - undefined

4
try this code , 100% working single custom post type and multiple post type.
add this class in functions.php file in our theme , or create separate file and import into functions.php


class remove_cpt_base {
    var $plugin_admin_page;
    static $instance = null;

    static public function init() {
        if (self::$instance == null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    function __construct() {
        add_action('plugins_loaded', array($this, 'plugins_loaded'));

        $this->rcptb_selected = get_option('rcptb_selected', array());
        $this->rcptb_selected_keys = array_keys($this->rcptb_selected);

        add_action('admin_menu', array($this, 'plugin_menu_link'));
        add_filter('post_type_link', array($this, 'remove_slug'), 10, 3);
        add_action('template_redirect', array($this, 'auto_redirect_old'), 1);
        add_action('pre_get_posts', array($this, 'handle_cpts'), 1);
    }

    function plugins_loaded() {
        load_plugin_textdomain('remove_cpt_base', FALSE, basename(dirname(__FILE__)) . '/languages/');
    }

    function filter_plugin_actions($links, $file) {
        $settings_link = '<a href="options-general.php?page=' . basename(__FILE__) . '">' . __('Settings') . '</a>';
        array_unshift($links, $settings_link);
        return $links;
    }

    function plugin_menu_link() {
        $this->plugin_admin_page = add_submenu_page(
            'options-general.php',
            __('Remove CPT base', 'remove_cpt_base'),
            __('Remove CPT base', 'remove_cpt_base'),
            'manage_options',
            basename(__FILE__),
            array($this, 'admin_options_page')
        );
        add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'filter_plugin_actions'), 10, 2);
    }

    function admin_options_page() {
        if (get_current_screen()->id != $this->plugin_admin_page) {
            return;
        }

        global $wp_post_types;?>
        <div class="wrap">
            <h2><?php _e('Remove base slug from url for these custom post types:', 'remove_cpt_base')?></h2><?php
if (isset($_POST['rcptb_selected_sent'])) {

            if (!isset($_POST['rcptb_alternation']) || !is_array($_POST['rcptb_alternation'])) {
                $alternation = array();
            } else {
                $alternation = $_POST['rcptb_alternation'];
            }

            if (!isset($_POST['rcptb_selected']) || !is_array($_POST['rcptb_selected'])) {
                $this->rcptb_selected = array();
            } else {
                $this->rcptb_selected = $_POST['rcptb_selected'];
            }

            foreach ($this->rcptb_selected as $post_type => $active) {
                $this->rcptb_selected[$post_type] = isset($alternation[$post_type]) ? 1 : 0;
            }

            $this->rcptb_selected_keys = array_keys($this->rcptb_selected);

            update_option('rcptb_selected', $this->rcptb_selected, 'no');
            echo '<div class="below-h2 updated"><p>' . __('Settings saved.') . '</p></div>';
            flush_rewrite_rules();
        }?>
            <br>
            <form method="POST" action="">
                <input type="hidden" name="rcptb_selected_sent" value="1">
                <table class="widefat" style="width:auto">
                    <tbody><?php
foreach ($wp_post_types as $type => $custom_post) {
            if ($custom_post->_builtin == false) {?>
                                <tr>
                                    <td>
                                        <label>
                                            <input type="checkbox" name="rcptb_selected[<?php echo $custom_post->name ?>]" value="1" <?php echo isset($this->rcptb_selected[$custom_post->name]) ? 'checked' : '' ?>>
                                            <?php echo $custom_post->label ?> (<?php echo $custom_post->name ?>)
                                        </label>
                                    </td>
                                    <td>
                                        <label>
                                            <input type="checkbox" name="rcptb_alternation[<?php echo $custom_post->name ?>]" value="1" <?php echo isset($this->rcptb_selected[$custom_post->name]) && $this->rcptb_selected[$custom_post->name] == 1 ? 'checked' : '' ?>>
                                            <?php _e('alternation', 'remove_cpt_base')?>
                                        </label>
                                    </td>
                                </tr><?php
}
        }?>
                    </tbody>
                </table>

                <p><?php _e('* if your custom post type children return error 404, then try alternation mode', 'remove_cpt_base')?></p>
                <hr>
                <p class="submit">
                    <input type="submit" class="button-primary" value="<?php _e('Save')?>">
                </p>
            </form>
        </div><?php
}

    function remove_slug($permalink, $post, $leavename) {
        global $wp_post_types;
        foreach ($wp_post_types as $type => $custom_post) {
            if ($custom_post->_builtin == false && $type == $post->post_type && isset($this->rcptb_selected[$custom_post->name])) {
                $custom_post->rewrite['slug'] = trim($custom_post->rewrite['slug'], '/');
                $permalink = str_replace('/' . $custom_post->rewrite['slug'] . '/', '/', $permalink);
            }
        }
        return $permalink;
    }

    function get_current_url() {
        $REQUEST_URI = strtok($_SERVER['REQUEST_URI'], '?');
        $real_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
        $real_url .= $_SERVER['SERVER_NAME'] . $REQUEST_URI;
        return $real_url;
    }

    function handle_cpts($query) {
        // make sure it's main query on frontend
        if (!is_admin() && $query->is_main_query() && !$query->get('queried_object_id')) {
            // conditions investigated after many tests
            if ($query->is_404() || $query->get('pagename') || $query->get('attachment') || $query->get('name') || $query->get('category_name')) {
                // test both site_url and home_url
                $web_roots = array();
                $web_roots[] = site_url();
                if (site_url() != home_url()) {
                    $web_roots[] = home_url();
                }
                // polylang fix
                if (function_exists('pll_home_url')) {
                    if (site_url() != pll_home_url()) {
                        $web_roots[] = pll_home_url();
                    }
                }

                foreach ($web_roots as $web_root) {
                    // get clean current URL path
                    $path = $this->get_current_url();
                    $path = str_replace($web_root, '', $path);
                    // fix missing slash
                    if (substr($path, 0, 1) != '/') {
                        $path = '/' . $path;
                    }
                    // test for posts
                    $post_data = get_page_by_path($path, OBJECT, 'post');
                    if (!($post_data instanceof WP_Post)) {
                        // test for pages
                        $post_data = get_page_by_path($path);
                        if (!is_object($post_data)) {
                            // test for selected CPTs
                            $post_data = get_page_by_path($path, OBJECT, $this->rcptb_selected_keys);
                            if (is_object($post_data)) {
                                // maybe name with ancestors is needed
                                $post_name = $post_data->post_name;
                                if ($this->rcptb_selected[$post_data->post_type] == 1) {
                                    $ancestors = get_post_ancestors($post_data->ID);
                                    foreach ($ancestors as $ancestor) {
                                        $post_name = get_post_field('post_name', $ancestor) . '/' . $post_name;
                                    }
                                }
                                // get CPT slug
                                $query_var = get_post_type_object($post_data->post_type)->query_var;
                                // alter query
                                $query->is_404 = 0;
                                $query->tax_query = NULL;
                                $query->is_attachment = 0;
                                $query->is_category = 0;
                                $query->is_archive = 0;
                                $query->is_tax = 0;
                                $query->is_page = 0;
                                $query->is_single = 1;
                                $query->is_singular = 1;
                                $query->set('error', NULL);
                                unset($query->query['error']);
                                $query->set('page', '');
                                $query->query['page'] = '';
                                $query->set('pagename', NULL);
                                unset($query->query['pagename']);
                                $query->set('attachment', NULL);
                                unset($query->query['attachment']);
                                $query->set('category_name', NULL);
                                unset($query->query['category_name']);
                                $query->set('post_type', $post_data->post_type);
                                $query->query['post_type'] = $post_data->post_type;
                                $query->set('name', $post_name);
                                $query->query['name'] = $post_name;
                                $query->set($query_var, $post_name);
                                $query->query[$query_var] = $post_name;

                                break;
                            } else {
                                // deeper matching
                                global $wp_rewrite;
                                // test all selected CPTs
                                foreach ($this->rcptb_selected_keys as $post_type) {
                                    // get CPT slug and its length
                                    $query_var = get_post_type_object($post_type)->query_var;
                                    // test all rewrite rules
                                    foreach ($wp_rewrite->rules as $pattern => $rewrite) {
                                        // test only rules for this CPT
                                        if (strpos($pattern, $query_var) !== false) {
                                            if (strpos($pattern, '(' . $query_var . ')') === false) {
                                                preg_match_all('#' . $pattern . '#', '/' . $query_var . $path, $matches, PREG_SET_ORDER);
                                            } else {
                                                preg_match_all('#' . $pattern . '#', $query_var . $path, $matches, PREG_SET_ORDER);
                                            }

                                            if (count($matches) !== 0 && isset($matches[0])) {
                                                // build URL query array
                                                $rewrite = str_replace('index.php?', '', $rewrite);
                                                parse_str($rewrite, $url_query);
                                                foreach ($url_query as $key => $value) {
                                                    $value = (int) str_replace(array('$matches[', ']'), '', $value);
                                                    if (isset($matches[0][$value])) {
                                                        $value = $matches[0][$value];
                                                        $url_query[$key] = $value;
                                                    }
                                                }

                                                // test new path for selected CPTs
                                                if (isset($url_query[$query_var])) {
                                                    $post_data = get_page_by_path('/' . $url_query[$query_var], OBJECT, $this->rcptb_selected_keys);
                                                    if (is_object($post_data)) {
                                                        // alter query
                                                        $query->is_404 = 0;
                                                        $query->tax_query = NULL;
                                                        $query->is_attachment = 0;
                                                        $query->is_category = 0;
                                                        $query->is_archive = 0;
                                                        $query->is_tax = 0;
                                                        $query->is_page = 0;
                                                        $query->is_single = 1;
                                                        $query->is_singular = 1;
                                                        $query->set('error', NULL);
                                                        unset($query->query['error']);
                                                        $query->set('page', '');
                                                        $query->query['page'] = '';
                                                        $query->set('pagename', NULL);
                                                        unset($query->query['pagename']);
                                                        $query->set('attachment', NULL);
                                                        unset($query->query['attachment']);
                                                        $query->set('category_name', NULL);
                                                        unset($query->query['category_name']);
                                                        $query->set('post_type', $post_data->post_type);
                                                        $query->query['post_type'] = $post_data->post_type;
                                                        $query->set('name', $url_query[$query_var]);
                                                        $query->query['name'] = $url_query[$query_var];
                                                        // solve custom rewrites, pagination, etc.
                                                        foreach ($url_query as $key => $value) {
                                                            if ($key != 'post_type' && substr($value, 0, 8) != '$matches') {
                                                                $query->set($key, $value);
                                                                $query->query[$key] = $value;
                                                            }
                                                        }
                                                        break 3;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    function auto_redirect_old() {
        global $post;
        if (!is_preview() && is_single() && is_object($post) && isset($this->rcptb_selected[$post->post_type])) {
            $new_url = get_permalink();
            $real_url = $this->get_current_url();
            if (substr_count($new_url, '/') != substr_count($real_url, '/') && strstr($real_url, $new_url) == false) {
                remove_filter('post_type_link', array($this, 'remove_slug'), 10);
                $old_url = get_permalink();
                add_filter('post_type_link', array($this, 'remove_slug'), 10, 3);
                $fixed_url = str_replace($old_url, $new_url, $real_url);
                wp_redirect($fixed_url, 301);
            }
        }
    }
}

function rcptb_remove_plugin_options() {
    delete_option('rcptb_selected');
}

add_action('init', array('remove_cpt_base', 'init'), 99);
register_activation_hook(__FILE__, 'flush_rewrite_rules');
register_deactivation_hook(__FILE__, 'flush_rewrite_rules');
register_uninstall_hook(__FILE__, 'rcptb_remove_plugin_options');

1
这是完美的解决方案。Entreprenerds提供的解决方案对我的多站点没有起作用,页面显示404错误,尽管我试图修复代码。真希望我能给这个点赞50次。 - undefined
在尝试了这里和其他几个网站提供的所有其他方法之后,这个方法完美无瑕地起作用。我很惊讶为什么这个答案没有被接受。它应该得到更多赞同。 - undefined
你只是从我的插件中复制粘贴源代码...这不太好...你应该安装我的插件,因为期间会有更新和更改... - undefined

1

对于重写,您只需要将当前的slug从'cpt-slug'更改为'/'并将with-front:'false'。完成后,只需重新保存永久链接,URL就不应再显示cpt slug。


1
正如@saeed所述,这会破坏其他页面类型,包括其他自定义文章类型。 - undefined

0

我遇到了同样的问题,看到了这个答案,但上面提到的解决方案都不起作用,所以尝试了不同的插件,最好的是移除基础缩略词并解决了404错误,请尝试移除CPT基础


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接