You can achieve this using the save_post hook.
save_post
is an action triggered whenever a post or page is created or
updated, which could be from an import, post/page edit form, xmlrpc,
or post by email.
add_action( 'save_post', 'wpse254017_set_post_title', 10, 2 );
function wpse254017_set_post_title ( $post_id, $post ){
//This temporarily removes action to prevent infinite loops
remove_action( 'save_post', 'wpse254017_set_post_title' );
if ( 'my-custom-post-type' !== $post->post_type )
return;
//GET THE CUSTOM FIELD
$post_title = get_post_meta( $post_id, 'apt_first_name', true );
//UPDATE TITLE
wp_update_post( array(
'ID' => $post_id,
'post_title' => $post_title,
));
//redo action
add_action( 'save_post', 'wpse254017_set_post_title', 10, 2 );
}
The hook can also be re-written specifying the post_type save_post_{post_type}
, this way you don’t have the hook running on all post_types.
add_action( 'save_post_{post_type}', 'wpse254017_set_post_title' );
function wpse254017_set_post_title ( $post_id ){
//This temporarily removes action to prevent infinite loops
remove_action( 'save_post_{post_type}', 'wpse254017_set_post_title' );
//GET THE CUSTOM FIELD
$post_title = get_post_meta( $post_id, 'apt_first_name', true );
//UPDATE TITLE
wp_update_post( array(
'ID' => $post_id,
'post_title' => $post_title,
));
//redo action
add_action( 'save_post_{post_type}', 'wpse254017_set_post_title');
}