在 Wordpress 自定义 post 类型上使用动态重写标签的自定义永久链接
Custom permalink with dynamic rewrite tags on a Wordpress custom post type
我有一个名为 location
的自定义 post 类型,我正在尝试将此类型的 post 设置为现有页面的子级,以实现这样的永久链接结构:
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`
我必须在两个不同的 post 类型之间创建层次关系的最接近方法是通过一个元框,我可以在其中分配一个 post ID 作为我自定义的 post_parent
保存时输入 posts。然而,尽管页面 ID 确实保存到 CPT post_parent
字段,但它对永久链接没有影响。它们按照 rewrite
CPT 选项中的定义来。但是我不知道如何使 ['rewrite']['slug']
选项动态化,或者它是否可能。
我的 post 类型是这样定义的:
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,
] );
} );
如何为位置配置重写规则以获得我需要的永久链接?
我假设所有 location
post 都有一个永久链接结构,如下所示:
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/
页面。
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 时,将 post_parent
自定义字段的值设置为 ID 'state Page'——例如/alabama/
页。
并且此代码将过滤 get_permalink()
输出,并且 return 是 location
post:
的适当永久链接
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;
}
例如,如果 location
post 的 slug 是 location-1
,那么 get_permalink( 123 )
会 return http://example.com/alabama/locations/location-1
'state Page' 是 /alabama/
.
更新
当请求永久链接时(即用户访问 example.com/{STATE NAME}/locations/{CPT SLUG}
),并且您想确保 'state Page' 和 location
post 都存在,和 'state Page'确实与location
post相关联,那么这段代码可以帮助你:
// 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()
函数。
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.;
mkey = $( 'input[name="meta[' + mid + '][key]"]' ).val();
if ( meta_key === mkey ) {
ajax();
}
}
}
$( '#the-list' )
.on( 'wpListAddEnd', _go )
.on( 'wpListDelEnd', _go );
} );
</script>
<?php
endif;
}
我有一个名为 location
的自定义 post 类型,我正在尝试将此类型的 post 设置为现有页面的子级,以实现这样的永久链接结构:
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`
我必须在两个不同的 post 类型之间创建层次关系的最接近方法是通过一个元框,我可以在其中分配一个 post ID 作为我自定义的 post_parent
保存时输入 posts。然而,尽管页面 ID 确实保存到 CPT post_parent
字段,但它对永久链接没有影响。它们按照 rewrite
CPT 选项中的定义来。但是我不知道如何使 ['rewrite']['slug']
选项动态化,或者它是否可能。
我的 post 类型是这样定义的:
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,
] );
} );
如何为位置配置重写规则以获得我需要的永久链接?
我假设所有 location
post 都有一个永久链接结构,如下所示:
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/
页面。
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 时,将 post_parent
自定义字段的值设置为 ID 'state Page'——例如/alabama/
页。
并且此代码将过滤 get_permalink()
输出,并且 return 是 location
post:
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;
}
例如,如果 location
post 的 slug 是 location-1
,那么 get_permalink( 123 )
会 return http://example.com/alabama/locations/location-1
'state Page' 是 /alabama/
.
更新
当请求永久链接时(即用户访问 example.com/{STATE NAME}/locations/{CPT SLUG}
),并且您想确保 'state Page' 和 location
post 都存在,和 'state Page'确实与location
post相关联,那么这段代码可以帮助你:
// 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()
函数。
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.;
mkey = $( 'input[name="meta[' + mid + '][key]"]' ).val();
if ( meta_key === mkey ) {
ajax();
}
}
}
$( '#the-list' )
.on( 'wpListAddEnd', _go )
.on( 'wpListDelEnd', _go );
} );
</script>
<?php
endif;
}