Knowledge
The filter title_save_pre
runs before the post is written to the database, and also before any of its post meta is saved to the database.
wp_get_object_terms
at this point will be blank.
To correct this you'll want to hook into save_post
and update the post from there. save_post
runs after the post has been saved to the database, and the in-built 'custom fields' have been saved.
There is a few things to understand before using save_post
like the infinite loop case. Overall you were pretty close.
Demo
I've commented everything. I've added a bit of jquery to disable the title input and a filter to update the default placeholder. I've also restricted the ability to publish, if there is no taxonomy selected.
<?php
add_action( 'init', function() {
/**
* Determines whether the current request is for an administrative interface page
* @link https://developer.wordpress.org/reference/functions/is_admin/
*/
if( ! is_admin() ) {
return;
};
global $custom_taxonomies, $custom_post_type;
$custom_post_type = '_custom_post_type_'; // set your custom post type
$custom_taxonomies = [ '_first_custom_taxonomy_', '_second_custom_taxonomy_' ]; // set your custom taxonomies
/**
* Disable title input
* @link https://developer.wordpress.org/reference/hooks/enter_title_here/
*/
add_action( 'admin_head', function() {
global $custom_post_type, $custom_taxonomies;
if( get_post_type() !== $custom_post_type ) {
return;
};
echo "<script type='text/javascript'>
jQuery( document ).ready( function( $ ) {
$( '#title' ).css( 'cursor', 'not-allowed' ).attr( 'readonly', true ).attr( 'disabled', true );
var term = $( 'input[name^=\"tax_input\"]:checkbox' );
term.change( function() {
$( '#publish, #save-post' ).prop( 'disabled', term.filter( ':checked' ).length < 1 );
} );
term.change();
} ); </script>";
} );
/**
* Replace the default placeholder
* @link https://developer.wordpress.org/reference/hooks/enter_title_here/
*/
add_filter( 'enter_title_here', function( $placeholder ) {
global $custom_post_type, $custom_taxonomies;
if( get_post_type() !== $custom_post_type ) {
return;
};
$placeholder = "Title automatically generated";
return $placeholder;
} );
/**
* Fires once a post has been saved
* @link https://developer.wordpress.org/reference/hooks/save_post/
*/
add_action( 'save_post', 'automatically_generated_title', 10, 2 );
function automatically_generated_title( $post_id, $post ) {
/**
* Prevent function if custom the post type isn't matching
* ...or if the post is published as auto-draft
* @link https://wordpress.stackexchange.com/a/218291/190376
* @link https://wordpress.stackexchange.com/a/217101/190376
*/
global $custom_post_type, $custom_taxonomies;
if ( $post->post_type != $custom_post_type || $post->post_status == 'auto-draft' ) {
return;
};
/**
* Prevent function on auto save
* @link https://wordpress.stackexchange.com/a/218291/190376
*/
if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
};
/**
* Prevent title from updating on post update
* @link https://wordpress.stackexchange.com/a/177670/190376
*/
$created = new DateTime( $post->post_date_gmt ); // get post publication date
$modified = new DateTime( $post->post_modified_gmt ); // get post modification date
$delta = $created->diff( $modified ); // calculate delta between $created and $modified
$delay = ( ( ( $delta->y * 365.25 + $delta->m * 30 + $delta->d ) * 24 + $delta->h ) * 60 + $delta->i ) * 60 + $delta->s; // handle the processing when it begins at the end of a given second, the post_date_gmt and the post_modified_gmt might be different
if( $delay <= 1 ) {
/**
* wp_get_object_terms instead of get_the_terms to retrieve an array() of taxonomies
* @link https://developer.wordpress.org/reference/functions/wp_get_object_terms/
*/
$terms = join( '', wp_list_pluck( wp_get_object_terms( $post_id, $custom_taxonomies ), 'name' ) );
$self = str_replace( '-', '', strtoupper( get_post_type() . $terms . $post_id ) ); // set your title structure
/**
* Prenvent infinite loop case
* @link https://developer.wordpress.org/reference/hooks/save_post/#avoiding-infinite-loops
*/
remove_action( 'save_post', 'automatically_generated_title' ); // unhook this function so it doesn't loop infinitely
/**
* Update a post with new post data
* @link https://developer.wordpress.org/reference/functions/wp_update_post/
* Parameters based on wp_insert_post @see https://developer.wordpress.org/reference/functions/wp_insert_post/#parameters
*/
wp_update_post( array(
'ID' => $post_id,
'post_title' => $self,
'post_name' => $self,
) ); // update the post, which calls save_post again
add_action( 'save_post', 'automatically_generated_title', 10, 2 ); // re-hook this function
};
};
} ); ?>
The title will set itself upon first-publishing submission. It will then ignore any update made to the post to keep a consistent slug. You can easily override that behaviour by removing the code in-between if( $delay <= 1 ) { ...
, moving it outside of the statement, and removing the following lines including the if( $delay <= 1 ) { ...
itself:
$created = new DateTime( $post->post_date_gmt );
$modified = new DateTime( $post->post_modified_gmt );
$delta = $created->diff( $modified );
$delay = ( ( ( $delta->y * 365.25 + $delta->m * 30 + $delta->d ) * 24 + $delta->h ) * 60 + $delta->i ) * 60 + $delta->s;