WordPress 自定义帖子类型上带有动态重写标签的自定义永久链接

kal*_*mar 2 wordpress permalinks

我有一个名为的自定义帖子类型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`
Run Code Online (Sandbox Code Playgroud)

我在两种不同的帖子类型之间创建层次关系的最接近方法是通过元框,post_parent在保存帖子时,我可以将帖子 ID 指定为自定义类型帖子的 ID。然而,尽管页面 ID 确实保存到了 CPTpost_parent字段,但它对永久链接没有影响。它们按照rewriteCPT 选项中的定义来提供。但我不知道如何使该['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,
  ] );
} );
Run Code Online (Sandbox Code Playgroud)

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

Sal*_* CJ 7

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

example.com/{STATE NAME}/locations/{CPT SLUG}
Run Code Online (Sandbox Code Playgroud)

URL 地址示例:

http://example.com/alabama/locations/location-1
http://example.com/alabama/locations/location-2
http://example.com/new-york/locations/location-3
Run Code Online (Sandbox Code Playgroud)

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

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

• 您不需要该/locations/主页。

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\-]+)' );
} );
Run Code Online (Sandbox Code Playgroud)

(您可以更改state_name为其他名称;这取决于您。并且不要忘记刷新重写规则 - 转到“永久链接设置”页面并单击“保存更改”按钮,而无需进行任何更改。)


接下来,当您创建或编辑location帖子时,将自定义字段的值设置post_parent为“状态页面”的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;
}
Run Code Online (Sandbox Code Playgroud)

例如,如果帖子的 slug 是,并且其“状态页面”是 ,get_permalink( 123 )则将返回。http://example.com/alabama/locations/location-1locationlocation-1/alabama/


更新

当请求永久链接时(即用户访问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' );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更新#2

请参阅// 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;
}
Run Code Online (Sandbox Code Playgroud)