По умолчанию в WordPress можно создавать записи с одинаковыми заголовками. И как выяснялось, поправить это не так-то просто. Во всяком случае подходящего хука под такую задачу я не нашел и в «интернетах» какие-то непонятные или нерабочие решения. Поэтому пришлось использовать не совсем подходящий фильтр wp_insert_post_empty_content, который, впрочем, отлично справляется с задачей.
// Disallow Same Post Title . add_filter( 'wp_insert_post_empty_content', 'disallow_same_post_title', 10, 2 ); /** * Prohibits publish posts with the same title (if such a title * already exists for the current post type). * * The function is designed to be used on a hook: * * add_filter( 'wp_insert_post_empty_content', 'disallow_same_post_title', 10, 2 ); * * @param bool $false * @param array $postarr * * @return bool * * @author Kama (wp-kama.com) */ function disallow_same_post_title( $false, $postarr ){ global $wpdb; // do only for publish post status if( $postarr['post_status'] !== 'publish' ){ return $false; } $AND = [ $wpdb->prepare( 'post_title = %s AND post_type = %s AND post_status = %s', $postarr['post_title'], $postarr['post_type'], 'publish' ) ]; // set not post ID if it`s update if( ! empty( $postarr['ID'] ) ){ $AND[] = $wpdb->prepare( "ID != %d", $postarr['ID'] ); } // duplicate post_title $dupl_post_id = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE ". implode( ' AND ', $AND ) ); if( $dupl_post_id ){ // change error message add_filter( 'wp_error_added', function( $code, $message, $data, $that ) use ( $dupl_post_id ){ $code === 'empty_content' && $that->errors[ $code ] = [ sprintf( 'Duplicate title! Post with such title already exists: %s', get_permalink( $dupl_post_id ) ) ]; }, 10, 4 ); return true; // stop } return $false; }