I'm trying to change the url structure of my custom post type posts, but It's not working correctly right now.

What I'm trying to do is change the urls of my custom post type (Test) posts via functions.php. By using post_type_link and add_rewrite_rule I want to rewrite %hallo% to a custom field value (by using get_post_meta). I hope someone can help me out with this. I've already tried a few dozen approaches, but it's still not working.

On the admin side, what I'm having now is working correctly. It shows the urls the way I want them to (domain.com/test/mycustomfieldvalue/post-title/). The problem happens when I want to view the page on the front-end. I get a 400 Bad Request error and I can see my url is changed to domain.com/test/%hallo%/post-title/.

Note: I'm aware of to need to flush my rewrite rules when changing the urls. I'm constantly using flush_rewrite_rules() right now for testing so that can't be the issue.

Look at my code below.

My custom post type

add_action( 'init', 'cpt_test_init' );

function cpt_test_init() {

    $labels = array(
        'name'               => _x( 'Test', 'post type general name', 'mytheme' ),
        'singular_name'      => _x( 'Test', 'post type singular name', 'mytheme' ),
        'menu_name'          => _x( 'Test', 'admin menu', 'mytheme' ),
        'name_admin_bar'     => _x( 'Test', 'add new on admin bar', 'mytheme' ),
        'add_new'            => _x( 'Nieuwe test toevoegen', 'faq', 'mytheme' ),
        'add_new_item'       => __( 'Nieuwe test toevoegen', 'mytheme' ),
        'new_item'           => __( 'Nieuwe test', 'mytheme' ),
        'edit_item'          => __( 'Test aanpassen', 'mytheme' ),
        'view_item'          => __( 'Bekijk test', 'mytheme' ),
        'all_items'          => __( 'Alle test', 'mytheme' ),
        'search_items'       => __( 'Test zoeken', 'mytheme' ),
        'parent_item_colon'  => __( 'Bovenliggend item:', 'mytheme' ),
        'not_found'          => __( 'Geen test gevonden.', 'mytheme' ),
        'not_found_in_trash' => __( 'Geen test gevonden in de prullenbak.', 'mytheme' )

    $args = array(
        'labels'             => $labels,
        'description'        => __( 'Description.', 'mytheme' ),
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array( 'slug' => 'test/%hallo%', 'with_front' => false ),
        'capability_type'    => 'post',
        'has_archive'        => false,
        'hierarchical'       => false,
        'menu_position'      => NULL,
        'supports'           => array( 'title', 'revisions' )

    register_post_type( 'test', $args );

How I'm trying to change the urls

function change_test_links( $post_link, $post, $leavename ) {
    if ( is_object( $post ) && $post->post_type == 'test' ) {
        $metaText = get_post_meta(get_the_ID(), 'test_text_field', true);
        if ( $metaText ) {
            return str_replace( '%hallo%', $metaText, $post_link );
    return $post_link;
add_filter( 'post_type_link', 'change_test_links', 1, 3 );

function test_rewrite_rules() {
add_action( 'init', 'test_rewrite_rules' );

I really hope someone can help me with this. I feel like I'm close or I'm missing something simple. Thanks in advance!

Edit: When I try to rewrite %hallo% to a hard-coded string (for example 'mynewtext') it all does work. So I'm guessing my problem is the use of get_post_meta.

Does work:

return str_replace( '%hallo%', 'mynewtext', $post_link );

Doesn't work:

$metaText = get_post_meta(get_the_ID(), 'test_text_field', true);
return str_replace( '%hallo%', $metaText, $post_link );

1 Answer 1


Not sure the rewrite rule is good, but to answer the question about getting the post meta - you already have the post Object, so you don't need to run a function to get the global $post, which might also fail or be wrong - you can simply use:

$metaText = get_post_meta( $post->ID, 'test_text_field', true);

You will probably also want to debug the value of $metaText to ensure it returns something.

  • 1
    You are absolutely right, I don't need get_the_ID when I can just do $post->ID. As it looks like, the 'get_the_ID' part was what was the entire problem! You made my day, thanks a million!
    – DeltaG
    Commented Jan 13, 2021 at 12:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.