• Hi all!
    I have written this plugin for a sport club where you can book tennis courts; the idea is to give the admin the possibility to “manual add” new booking.
    To do that I created a custom post type called “booking”, when the admin will click on “add new” I’d like to see the “title box” of my cpt auto-filled with a unique code or incremental id that will identify that booking.
    Which is the best way to generate a title/code like that?
    If I have two people logged with the same admin credentials will be there collapse problem in the code generation?

    function change_mycpt_default_title() {
        if( $_GET['post_type'] == 'booking' ) {
            return 'UNIQUE CODE HERE';
        }
    }
    
    add_filter('default_title', 'change_mycpt_default_title');

    This is the code I use to change the default title of my cpt.

Viewing 8 replies - 1 through 8 (of 8 total)
  • Moderator bcworkz

    (@bcworkz)

    If you want an incremental ID, you could maintain a value in the options table of the next available ID that is incremented once any draft booking post is created. This avoids any possible collisions from other users, but will also create gaps in numbering of published bookings because auto-saves will also increment the counter. I suppose some additional script could check if other drafts of the same slug already exist before incrementing the counter. Or just turn off auto-saving.

    If a unique, non-incremental ID is acceptable, just use the current timestamp. An identical timestamp with multiple users is highly unlikely, but you could begin the ID with the user ID and append the timestamp to that. This is assuming no one is sharing the same logon.

    Another possibility is WP will automatically increment the title slug when the title is the same as another post. You could just use the same default all the time, then when the post is published, change the title to that of the assigned slug. Or at least use whatever algorithm WP uses to assign incremental slugs instead of my counter idea above.

    Thread Starter wizzy85

    (@wizzy85)

    Thank you bcworkz for your long answer… I ended up with this solution:
    I completly hide the title box and I create the cpt title just before publishing the post for the first time (not on updates); here’s the code:

    function set_incremental_post_title( $data, $postarr ) {
        if( 'booking' == $_POST['post_type'] ) {
            if( ( 'publish' == $_POST['post_status'] ) && ( 'publish' != $_POST['original_post_status'] ) ) {
                $booking_num = get_field( 'inc_value', 'options' ) + 1;
                $data['post_title'] = 'BOOKING ' . $booking_num;
                update_field( 'inc_value', $booking_num, 'options' );
            }
        }
    
        return $data;
    }
    
    add_filter( 'wp_insert_post_data', 'set_incremental_post_title', 99, 2 );

    This seems to work pretty well.
    I’m just asking myself what happen if two or more people will publish a booking at the same time…
    I know that it could be near impossible but without a “random” string in my title I should end up to have two or more booking with the same title… am I wrong? There is something I could do to avoid this?

    Moderator bcworkz

    (@bcworkz)

    Tying the inc_field increment to when inserting the post instead of when the post title is established greatly decreases the chances of simultaneous use of the same value. You can decrease the chance a minuscule bit more by placing the update immediately after the get. Not that it takes very long to assign a value, but it does take time.

    I don’t think it’s really much to worry about, but in theory it is possible. To make simultaneous use of the same value completely impossible, you should set a transient value as a flag for locking the value while it is being retrieved and updated. When the flag is set, no other process should access the value. Once the value is updated, the flag is cleared and then another process is free to lock it and access the value.

    Thread Starter wizzy85

    (@wizzy85)

    Sorry bcworkz should I use wp_insert_post or save_post filter/action?
    I read the codex but I can’t understand which one is the last called just before the db insertion.
    I need it to check if I reached the maximum bookings for the tennis court too!

    Moderator bcworkz

    (@bcworkz)

    It doesn’t matter which hook you use, one fires right after the other, nothing happens in between. They both fire after the DB action though. For a hook that fires before the DB action, use ‘wp_insert_post_data’. This filter is specifically intended to let you change post data, such as the title, before being placed in the DB.

    Be aware that it also fires when posts are updated, or even when posts are auto-saved. It fires for nearly all post types, including nav_menu_item, so check the post_type. It could possibly fire more than once for any one post, so you cannot use it for counting something unless logic is in place to increment the counter only once per request no matter how many times the filter fires.

    There are probably better filters for counting, such as the various transition_post_status actions. You can narrow down the conditions for which an action fires, but it can still be more than once per post.

    I can’t suggest any appropriate logic to capture maximum bookings, it depends on how the bookings are scheduled. If they are by arbitrary appointment times, the logic involved is quite tricky. If they are booked by established blocks of time, then you just need to keep a count of bookings for each block.

    Thread Starter wizzy85

    (@wizzy85)

    Ok so why my function set_incremental_post_title with wp_insert_post_data filter isn’t ok?
    I could move the update immediately after the get in this way:

    function set_incremental_post_title( $data, $postarr ) {
        if( 'booking' == $_POST['post_type'] ) {
            if( ( 'publish' == $_POST['post_status'] ) && ( 'publish' != $_POST['original_post_status'] ) ) {
                $booking_num = get_field( 'inc_value', 'options' ) + 1;
                update_field( 'inc_value', $booking_num, 'options' );
                $data['post_title'] = 'BOOKING ' . $booking_num;
            }
        }
    
        return $data;
    }
    
    add_filter( 'wp_insert_post_data', 'set_incremental_post_title', 99, 2 );

    with if( ( 'publish' == $_POST['post_status'] ) && ( 'publish' != $_POST['original_post_status'] ) ) I check that the post is actually published and not updated or auto-saved…
    The thing I need now is just understand how stop the “saving process” if I reach the maximum bookings (that I already have).

    Moderator bcworkz

    (@bcworkz)

    Filters are usually intended to change data before doing something, not stop something from happening. Still, it can be done, there are actually a couple ways you could do this.

    You could change the post status so that it is published directly into the trash. The problem here is how to notify the user their booking was not accepted. Trying to output content from filters often fails because the browser is not expecting output. The way around this is to do the entire booking process with AJAX. Then the browser will be expecting a returned value that controls what the user sees next. It may be difficult converting back end forms to AJAX, or easy, I’ve no idea.

    Your other choice is to simply call wp_die(). The user experience leaves much to be desired, but it does effectively prevent the post from being published.

    Maybe WordPress’ll automatically increment the slug when the title is the same as another post. YJust I think so. As a hack theme… u know

Viewing 8 replies - 1 through 8 (of 8 total)
  • The topic ‘Auto-generate unique code/id as title’ is closed to new replies.