简体   繁体   English

自定义永久链接,在Wordpress自定义帖子类型上使用动态重写标记

[英]Custom permalink with dynamic rewrite tags on a Wordpress custom post type

I have a custom post type named location and I'm trying to set posts of this type as children of existing pages, to achieve a permalink structure like this: 我有一个名为location的自定义帖子类型,我正在尝试将此类型的帖子设置为现有页面的子项,以实现这样的永久链接结构:

example.com/alabama  <-- Page with generic content
example.com/alabama/locations  <-- Another page, child of a state page
example.com/alabama/locations/location-name  <- Custom type, child of alabama/locations seen above and titled `Location Name`

The closest I've got to create hierarchical relationships between two distinct post types was through a meta box where I can assign a post ID as the post_parent of my custom type posts when saving them. 最接近我必须在两个不同的帖子类型之间创建层次关系是通过一个元框,我可以在保存它们时将帖子ID post_parent为我的自定义类型帖子的post_parent However despite the page ID being indeed saved to the CPT post_parent field, it has no effect on the permalinks. 尽管页面ID确实保存在CPT post_parent字段中,但它对永久链接没有影响。 They are coming as defined in the rewrite CPT option. 它们按rewrite CPT选项中的定义进行。 But I don't know how to make the ['rewrite']['slug'] option dynamic, or if it's even possible. 但我不知道如何使['rewrite']['slug']选项动态化,或者甚至可能。

This is how my post type is being defined: 这就是我的帖子类型的定义方式:

add_action( 'init', function() {
  register_post_type( 'location', [
    'label' => 'Location',
    'menu_icon' => 'dashicons-location-alt',
    'supports' => [ 'title', 'editor', 'custom-fields' ],
    'public' => true,
    'hierarchical' => false,
    'has_archive' => false,
    'rewrite' => false,
  ] );
} );

How can I configure the rewrite rules for locations to get the permalinks I need? 如何配置位置的重写规则以获得我需要的永久链接?

I'm assuming that all the location posts will have a permalink structure that looks like this: 我假设所有的location帖子都有一个永久链接结构,如下所示:

example.com/{STATE NAME}/locations/{CPT SLUG}

Sample URL addresses: 示例URL地址:

http://example.com/alabama/locations/location-1
http://example.com/alabama/locations/location-2
http://example.com/new-york/locations/location-3

So if that is correct, then: 所以,如果这是正确的,那么:

• Use the add_rewrite_rule() function to add a custom rewrite rule for those permalinks. •使用add_rewrite_rule()函数为这些永久链接添加自定义重写规则。

• You don't need the /locations/ Page. •您不需要/locations/ Page。

add_action( 'init', function(){
    // Handles requests to `your-site-domain.com/{STATE NAME}/locations/{CPT SLUG}`
    add_rewrite_rule(
        '([^/]+)/locations/([^/]+)(?:/([0-9]+))?/?$',
        'index.php?location=$matches[2]&page=$matches[3]&state_name=$matches[1]',
        'top'
    );

    // Allows you to retrieve the `state_name`; for example using `get_query_var()`.
    add_rewrite_tag( '%state_name%', '([\w\-]+)' );
} );

(You can change state_name to another name; it's up to you. And don't forget to flush the rewrite rules — go to the Permalink Settings page and click on the Save Changes button without having to make any changes.) (您可以将state_name更改为其他名称;这取决于您。并且不要忘记刷新重写规则 - 转到“永久链接设置”页面并单击“保存更改”按钮,而不必进行任何更改。)


Next, when you create or edit a location post, set the value of the post_parent custom field to the ID of the 'state Page' — eg the /alabama/ Page. 接下来,当您创建或编辑location信息时,请将post_parent自定义字段的值设置为“状态页面”的ID - 例如/alabama/ Page。

And this code will filter the get_permalink() output, and returns the appropriate permalink for a location post: 此代码将过滤get_permalink()输出,并返回location帖子的相应永久链接:

add_filter( 'post_type_link', 'so51217355_post_type_link', 10, 2 );
function so51217355_post_type_link( $permalink, $post ) {
    if ( 'location' === $post->post_type ) {
        $page_id = get_post_meta( $post->ID, 'post_parent', true );

        $state_name = ( is_numeric( $page_id ) && $page_id ) ?
            get_post_field( 'post_name', $page_id ) : null;

        // Make sure the post is associated to a valid 'state Page'.
        if ( $state_name ) {
            $permalink = $state_name . '/locations/' . $post->post_name;
            $permalink = home_url( user_trailingslashit( $permalink ) );
        }
    }

    return $permalink;
}

So for example, get_permalink( 123 ) would return http://example.com/alabama/locations/location-1 , if the location post's slug is location-1 , and its 'state Page' is /alabama/ . 例如, get_permalink( 123 )将返回http://example.com/alabama/locations/location-1 ,如果location帖子的slug是location-1 ,并且其'state Page'是/alabama/


UPDATE UPDATE

When the permalink is requested (ie users visit example.com/{STATE NAME}/locations/{CPT SLUG} ), and you want to make sure the 'state Page' and location post both exist, and that the 'state Page' was indeed associated to the location post, then this code can help you: 当请求永久链接时(即用户访问example.com/{STATE NAME}/locations/{CPT SLUG} ),您要确保“状态页面”和location帖子都存在, 确保“状态页面”确实与location贴相关联,那么此代码可以帮助您:

// Validates the `state_name` of the current page/URL.
add_action( 'parse_request', 'so51217355_parse_request' );
function so51217355_parse_request( $wp ) {
    if ( ! empty( $wp->query_vars['state_name'] ) &&
        ! empty( $wp->query_vars['location'] ) ) {
        global $wpdb;

        $page_id = $wpdb->get_var( $wpdb->prepare(
            "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s",
            $wp->query_vars['state_name']
        ) );

        if ( ! is_numeric( $page_id ) || ! $page_id ) {
            $wp->query_vars['error'] = '404';

            // Don't let WordPress finds a post with nearest match.
            remove_action( 'template_redirect', 'redirect_canonical' );

            return;
        }

        $post_id = $wpdb->get_var( $wpdb->prepare(
            "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s",
            $wp->query_vars['location']
        ) );

        $page_id2 = get_post_meta( $post_id, 'post_parent', true );
        if ( (int) $page_id2 !== (int) $page_id ) {
            $wp->query_vars['error'] = '404';

            // Don't let WordPress finds a post with nearest match.
            remove_action( 'template_redirect', 'redirect_canonical' );
        }
    }
}

UPDATE #2 更新#2

Refer to the // Comment in the code below this image — see the _so51217355_admin_ajax_js() function. 请参阅此图像下方代码中的// Comment - 请参阅_so51217355_admin_ajax_js()函数。

在此输入图像描述

add_action( 'wp_ajax_so51217355_admin_ajax', '_so51217355_admin_ajax_php' );
function _so51217355_admin_ajax_php() {
    $post_id = filter_input( INPUT_POST, 'post_id' );
    echo get_sample_permalink_html( $post_id );
    wp_die();
}

add_action( 'admin_print_footer_scripts', '_so51217355_admin_ajax_js', 11 );
function _so51217355_admin_ajax_js() {
    $screen = get_current_screen();
    if ( 'location' === $screen->id ) :
    ?>
<script>
// This script will sync the Permalink under the big/main post title box on
// the Edit Post page; but only if and when editing or deleting the custom
// field as in `meta_key` below. Make sure to change it, if necessary.
jQuery( function( $ ){
    var meta_key = 'post_parent';

    function ajax() {
        $.post( ajaxurl, {
            action: 'so51217355_admin_ajax',
            post_id: $( '#post_ID' ).val()
        }, function( s ){
            $( '#edit-slug-box' ).html( s );
        } );
    }

    function _go( e, a ) {
        var $input = $( a.target ),
            mid, mkey;

        if ( /^meta\-(\d+)\-submit$/.test( $input.attr( 'name' ) ) ||
            /^deletemeta\[(\d+)\]$/.test( $input.attr( 'name' ) ) ) {
            mid = RegExp.$1;
            mkey = $( 'input[name="meta[' + mid + '][key]"]' ).val();

            if ( meta_key === mkey ) {
                ajax();
            }
        }
    }

    $( '#the-list' )
        .on( 'wpListAddEnd', _go )
        .on( 'wpListDelEnd', _go );
} );
</script>
    <?php
    endif;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM