How to replace custom post type slug with an ACF value?

Can be the $cptslug value dynamic according to ACF value?

Yes, it can.

Here’s how:

  1. First off, my ACF field settings are as follows:

    Name: video_or_image
    Type: Select
    Options:

    1 : Video
    0 : Image
    
  2. So I register the post type like so, where the rewrite slug is set to %video_or_image% — i.e. %{Name of the ACF field}%, but you don’t have to follow that format:

    register_post_type( 'video', array(
        'label'   => 'Video',
        'public'  => true,
        'rewrite' => array(
            'slug' => '%video_or_image%',
        ),
        ...
    ) );
    

    Or if you want to or can only use the register_post_type_args to change the rewrite slug, then just set the $cptslug to %video_or_image%.

  3. Next, I register the rewrite tag (%video_or_image%) after the register_post_type() call, which is hooked to the init action:

    add_rewrite_tag( '%video_or_image%', '([^/]+)' );
    

    Registering the tag is mandatory, and ensures that the tag is properly replaced with the RegEx pattern (i.e. ([^/]+)) when the rewrite rules are saved:

  4. Then I replace the rewrite tag with the proper (ACF) field value using the post_type_link filter:

    add_filter( 'post_type_link', function( $url, $post ){
        if ( 'video' === $post->post_type ) {
            $value = get_field( 'video_or_image', $post->ID );
            $url = str_replace( '%video_or_image%', $value, $url );
        }
    
        return $url;
    }, 10, 2 );
    

That’s all, but don’t forget to flush the rewrite rules — simply visit the permalink settings page.

And I suggest you to set a default value for your ACF field, and use “better” values if possible.. I mean, other than 1 or 0.. but if you’re sure about such values, then (I think) it’s alright. =)

UPDATE

In my case, using only ([^/]+) in the rewrite tag, causes troubles when loading Pages (i.e. page post type):

add_rewrite_tag( '%video_or_image%', '([^/]+)' );

How I solved the problem

  1. Use a unique identifier, e.g. v/ as in:

    add_rewrite_tag( '%video_or_image%', 'v/([^/]+)' );
    

    Then in the post permalink, v/ should also be added to the rewrite tag replacement value — see step #4 above:

    $url = str_replace( '%video_or_image%', 'v/' . $value, $url );
    
  2. I restricted the ACF field value to numeric, then I used:

    add_rewrite_tag( '%video_or_image%', '(\d+)' );
    

    That (\d+) does not guarantee no conflict with other rewrite rules, but at least in my case, it worked.

Sorry about the ([^/]+) — I thought the 0 and 1 values were just examples. I should’ve just used (\d+).