首页 文章

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

提问于
浏览
1

我有一个名为 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`

最接近我必须在两个不同的帖子类型之间创建层次关系是通过一个元框,我可以在保存它们时将帖子ID指定为我的自定义类型帖子的 post_parent . 尽管页面ID确实保存在CPT post_parent 字段中,但它对永久链接没有影响 . 它们按照 rewrite CPT选项中的定义进行 . 但我不知道如何使 ['rewrite']['slug'] 选项动态化,或者甚至可能 .

这就是我的帖子类型的定义方式:

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,
  ] );
} );

如何配置位置的重写规则以获得我需要的永久链接?

1 回答

  • 2

    我假设所有 location 帖子都有一个永久链接结构,如下所示:

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

    示例URL地址:

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

    所以,如果这是正确的,那么:

    •使用 add_rewrite_rule() 函数为这些永久链接添加自定义重写规则 .

    •您不需要 /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\-]+)' );
    } );
    

    (您可以将 state_name 更改为其他名称;它会忘记刷新重写规则 - 转到“永久链接设置”页面并单击“保存更改”按钮,而不必进行任何更改 . )


    接下来,当您创建或编辑 location 帖子时,请将 post_parent 自定义字段的值设置为'state Page'的ID - 例如 /alabama/ 页 .

    此代码将过滤 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;
    }
    

    例如, get_permalink( 123 ) 将返回 http://example.com/alabama/locations/location-1 ,如果 location 帖子的slug是 location-1 ,其'state Page'是 /alabama/ .


    更新

    当请求永久链接时(即用户访问 example.com/{STATE NAME}/locations/{CPT SLUG} ),并且您想确保'state Page'和 location 帖子都存在,并且'state Page'确实与 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' );
            }
        }
    }
    

    更新#2

    请参阅此图像下方代码中的 // Comment - 请参阅 _so51217355_admin_ajax_js() 功能 .

    enter image description here

    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;
    }
    

相关问题