I am running a site where I let users create a profile, which is a custom post type, which is submitted/edited through an ACF front-end form. Everything works as expected, except when users both use the same ‘headline’ (which is sanitized and used as permalink).
I want the permalink to have the following ‘structure’: /post-type/city/{post-title}-{post-id}. My thought was to add a post id, so each link would be unique, but I now found out this is not the case.
If I would have 2 profiles:
www.domain.com/profile/city/i-am-cool-123
www.domain.com/profile/city/i-am-cool-456
Then www.domain.com/profile/city/i-am-cool-456 redirects to www.domain.com/profile/city/i-am-cool-123.
I knew you can’t have 2 the same permalinks, but I might have misunderstood how permalinks are ‘registered’.
Below is my code.
First I’ve added the necessary query vars for the new vars and added custom rewrite tags.
function sd_custom_rewrite_tag() {
add_rewrite_tag( '%city%', '([^&]+)', 'city=' );
add_rewrite_tag( '%postname%', '([^&]+)', 'name=" );
}
add_action( "init', 'sd_custom_rewrite_tag', 10, 0 );
function sd_add_query_vars( $vars ) {
$vars[] = "city";
$vars[] = "postname";
return $vars;
}
add_filter( 'query_vars', 'sd_add_query_vars' );
To get the permalink I want, I have the following code in place.
function sd_new_profile_permalink( $permalink, $post, $leavename = false ) {
if ( strpos( $permalink, '%city%' ) === FALSE ) {
return $permalink;
}
// Get post
if ( ! $post ) {
return $permalink;
}
// Get custom info
$city_info = get_field( 'sd_city_selector', $post->ID );
$post_slug = $post->post_name;
if ( ! is_wp_error( $city_info ) && ! empty( $city_info ) ) {
$city_replace = str_replace( '\'', '', $city_info[ 'cityName' ] );
$city_replace = str_replace( ' ', '-', $city_replace );
$city_slug = strtolower( $city_replace );
$new_permalink = str_replace( array( '%city%', '%postname%', '%post_id%' ), array( $city_slug, $post_slug, $post->ID ), $permalink );
return $new_permalink;
}
return $permalink;
}
add_filter( 'post_link', 'sd_new_profile_permalink', 10, 3 );
add_filter( 'post_type_link', 'sd_new_profile_permalink', 10, 3 );
So far nothing weird is happening, this is all doing what it’s supposed to do, but now we get down to the issue (I think).
I update the slug through a WPDB action, after the post is submitted, as seen below.
function set_profile_title_from_headline( $post_id ) {
if ( empty( $_POST[ 'acf' ] ) ) {
return;
}
if ( ! empty( $_POST[ 'acf' ][ 'field_57e3ed6c92ea0' ] ) ) {
$entered_title = $_POST[ 'acf' ][ 'field_57e3ed6c92ea0' ];
$cleaned_title = preg_replace( '/[^A-Za-z0-9\-\s]/', '', $entered_title );
$post_name = sanitize_title( $cleaned_title );
update_field( 'sd_ad_title', $cleaned_title, $post_id );
global $wpdb;
$wpdb->update(
$wpdb->posts,
array(
'post_title' => $cleaned_title,
'post_name' => $post_name
),
array(
'ID' => $post_id
)
);
clean_post_cache( $post_id );
}
}
add_action( 'acf/save_post', 'set_profile_title_from_headline', 20 );
And then finally I rewrite the url.
function sd_single_profile_rewrite() {
global $wp_rewrite;
$wp_rewrite->add_permastruct( 'profile', 'profile/%city%/%postname%-%post_id%/', false );
add_rewrite_rule( 'profile\/([a-z-]+)\/(.+)-[0-9]+\/?$', 'index.php?post_type=profile&p=$matches[2]&city=$matches[1]&name=$matches[2]', 'top' );
}
add_action( 'init', 'sd_single_profile_rewrite' );
Basically my question is: Is there a way to ‘do’ what I want to do ?
And if so, how 🙂