Ask your WordPress questions! Pay money and get answers fast! (more info)

Set CPT post title from custom fields UPON INITIAL POST CREATION WordPress

This code works for my 'open' custom post type: https://gist.github.com/cliffordp/b1f7aedcca0e457adad4

EXCEPT that it does NOT work when a post is initially created.

My first code attempt hooked into save_post_open (the save_post hook for the Open CPT) but that didn't generate the title for newly-created posts (only existing posts that got updated) so I switched to trying the post_updated hook and that still didn't work... so now asking for help how-to.

tyvm!

Answers (4)

2015-02-08

Navjot Singh answers:

Try hooking into [[LINK href="http://codex.wordpress.org/Plugin_API/Action_Reference/save_post"]]save_post[[/LINK]] or [[LINK href="http://codex.wordpress.org/Plugin_API/Action_Reference/publish_post"]]publish post[[/LINK]].


Clifford P comments:

save_post_open is save_post for the Open CPT

2015-02-08

Reigel Gallarde answers:

I tried your code and it works... that is me skipping types_render_field related lines... maybe your problem is within types_render_field function? can we see your code for it?


Clifford P comments:

It's the free Types plugin, which creates CPT, custom fields, etc


Reigel Gallarde comments:

Have you tried using echo to check if types_render_field got the right values?

or
I see that you just want the raw output, can you try chaging

$location = types_render_field( 'location', array('raw'=>'true') );
$areaname = types_render_field( 'area-name', array('raw'=>'true') );
$hostname = types_render_field( 'host-name', array('raw'=>'true') );
$brokerage = types_render_field( 'brokerage-name', array('raw'=>'true') );
$sponsorrep = types_render_field( 'sponsor-rep', array('raw'=>'true') );
$sponsorentity = types_render_field( 'sponsor-entity', array('raw'=>'true') );


to


$location = get_post_meta( $post_id, 'location', true );
$areaname = get_post_meta( $post_id, 'area-name', true );
$hostname = get_post_meta( $post_id, 'host-name', true );
$brokerage = get_post_meta( $post_id, 'brokerage-name', true );
$sponsorrep = get_post_meta( $post_id, 'sponsor-rep', true );
$sponsorentity = get_post_meta( $post_id, 'sponsor-entity', true );


Clifford P comments:

That part isn't the issue. As I said, it works... just not for newly created posts


Reigel Gallarde comments:

hmmm... I tried removing that lines...

and do something like
$newtitle = 'test';
if( !empty($newtitle) ) {
......

and all works... new or update...
the title changed to 'test'


Clifford P comments:

How about setting to a custom field from the new post?
I read that save_post is after it is saved (so custom fields should be in DB already) so it should work, but I also read that save_post is called right at click of "New Post" (before clicking Save/Publish)


Reigel Gallarde comments:

ok.. I got now an idea... I think your problem is priority...

types_render_field should have also been hooked to save_post... most of us do hook saving cpf to save_post...

can you try adding higher priority of save_post_open?? add_action('save_post_open', 'set_open_post_title',999 );

ps. be careful of infinite loop :D


Clifford P comments:

adding priority doesn't make it work any differently, still results in Auto Draft


Reigel Gallarde comments:

Ok, I've checked everything... Types Plugin hook their saving of cf to save_post, at priority 10.
However your problem is that you are hooking to save_post_open. Which is run before save_post. Which means, you have to run first all the functions hooked to save_post_open before you reach save_post, in where the cf are being saved. So, using save_post_open, your cf is empty on initial creation of a post.

So my final suggestion, and if this does not work, I don't have anymore suggestion...

use

add_action('save_post', 'set_open_post_title',999 );

and just check for post type as to not affect other post types...
set priority higher than 20, cause I also noticed some functions are hooked at save_post using 20 in Types Plugin.


Clifford P comments:

Great info. Thanks. Unfortunately no dice.

Maybe there's a hook like after_post_is_saved_and_really_is_saved? lol


Reigel Gallarde comments:

lol... I don't know how you're doing it... cause as I said earlier, I made it run and save the title...

But that was without the CF..

I tried checking the Types Plugin, and also tried it, and it does work on my end... :D

I can't suggest anything more, cause that's really should do it :D

2015-02-08

Dbranes answers:

Hi Clifford.

You can try:

add_filter( 'default_title', function( $title, $post )
{
if( 'cpt' === $post->post_type )
$title = __( 'This is my default cpt post title!' );

return $title
}, 10, 2 );


to modify your default post title for a given custom post type <em>cpt</em>.


Clifford P comments:

Does default_title work for subsequent post content changes/updates too or only initial post creation?


Dbranes comments:

This is meant for the "write new post" case.

You can for example modify the post_title field directly with the wp_post_insertdata filter, and it will be saved to the database, but it will not show on your post-new.php form. There's also a check that if the post has the auto-draft status, then the title is initialized.

So I think you will have to use this filter to modify it, if you don't want to mess with jQuery etc ;-)

But you can also use the <em>enter_title_here</em> filter to modify the javascript hint, if you want to use that instead.


Dbranes comments:

ps: I meant the <em>wp_insert_post_data</em> ;-)


Clifford P comments:

Want it to be set from custom field data, not arbitrary text


Dbranes comments:

You will have to write the custom field data before the <em>default_title</em> filter is fired, when you start writing a new post.


Clifford P comments:

exactly, which is why I thought using save_post_open would work.
http://codex.wordpress.org/Plugin_API/Action_Reference/save_post says "save_post is an action triggered whenever a post or page is created or updated... this action is triggered right after the post has been saved"


My code is the same concept as from the example from that page: http://codex.wordpress.org/Plugin_API/Action_Reference/save_post#Avoiding_infinite_loops

But nothing I've tried sets the post title to my custom fields upon initial post creation.


Clifford P comments:

I just now tried the hooks publish_open and publish_post (just in case) and neither worked.


Clifford P comments:

I also tried title_save_pre because https://wp-types.com/forums/topic/change-default-custom-post-title-from-auto-draft-to-something-else/#post-204792 said it works and that didn't work for me either.


Dbranes comments:

Here's a simple demo that creates a post meta key <em>'custom_title'</em> with the value <em>'Hello World!'</em> when you first create a post.

Then you will see the title input text, pre-filled with that meta value:

add_filter( 'default_title', function( $title, $post )
{
if( 'post' === $post->post_type )
{
$title = get_post_meta( $post->ID, 'custom_title', true );
}
return $title;
}, 10, 2 );

add_action( 'save_post_post', function( $post_ID, $post, $update )
{
if( 'auto-draft' === $post->post_status && '0000-00-00 00:00:00' === $post->post_modified_gmt )
{
update_post_meta( $post->ID, 'custom_title', 'Hello World!' );
}
}, 10, 3 );


Note that we target the <em>post</em> post type.


Clifford P comments:

I'm not wanting an additional custom field, just altering the actual post title.


Dbranes comments:

This is just an example how we can <em>pre-fill</em> the title from a custom field, that's added when <em>save_post_{$cpt}</em> hook is fired.

As soon as you click "Add New", the pre-filled title shows up.

We could have used some other custom field, but this was just for demonstration.




Clifford P comments:

If I'm understanding you correctly:
Click "Add New" to create a new post
The WP Title will be prefilled with whatever we tell default_title to be.
This pre-fill title would be user-editable and wouldn't stay updated as custom fields change for this post over time.

Therefore, not the solution I'm looking for... Plus, since it's a new, not-yet-saved post, won't it be blank anyway?

2015-02-09

Romel Apuya answers:

add_action has a priority parameter which is 10 by default, you can increase that to load your function late.

Change add_action( 'save_post', 'set_open_post_title' );

to

add_action( 'save_post', 'set_open_post_title', 100 );

Now the priority is to set to 100 and will load quite late and will allow other function associated to load before this function is executed.

For more details check the function reference for [[LINK href="http://codex.wordpress.org/Function_Reference/add_action#Parameters"]]add_action[[/LINK]].


Romel Apuya comments:

<?php
/*
Replace post title to avoid title of "Auto Draft"
Only runs when saving an Open post type
http://codex.wordpress.org/Plugin_API/Action_Reference/save_post#Examples
http://codex.wordpress.org/Function_Reference/wp_update_post
http://wordpress.stackexchange.com/a/73531
http://stackoverflow.com/questions/5434219/problem-with-wordpress-save-post-action -- post_updated hook instead (still did not work for me)
*/
function set_open_post_title($post_id) {
if ( $post_id == null )
return;
if ( $parent_id = wp_is_post_revision( $post_id ) )
$post_id = $parent_id;
/*
SHOULD WE REALLY? What about the potential of wanting to batch re-write titles via CRON?
// Bail out if running an autosave, ajax or a cron -- http://wpsmith.net/2012/wp/bail-function-for-save_post-hook/
if (
( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) //running an autosave
|| ( defined( 'DOING_AJAX' ) && DOING_AJAX ) //running an ajax
|| ( defined( 'DOING_CRON' ) && DOING_CRON ) //running a cron
)
return;
*/
// REQUIRED to pull custom fields
global $post;
if( empty( $post ) )
$post = get_post($post_id);
if( get_post_type($post_id) !== 'open' )
return $post_id;
$newtitle = '';
$newslug = '';
// use types_render_field_single() for repeatable fields
if( function_exists('types_render_field') ) {
$location = types_render_field( 'location', array('raw'=>'true') );
$areaname = types_render_field( 'area-name', array('raw'=>'true') );
$hostname = types_render_field( 'host-name', array('raw'=>'true') );
$brokerage = types_render_field( 'brokerage-name', array('raw'=>'true') );
$sponsorrep = types_render_field( 'sponsor-rep', array('raw'=>'true') );
$sponsorentity = types_render_field( 'sponsor-entity', array('raw'=>'true') );
// BUILD POST TITLE
$newtitle .= $location ? $location : '';
$newtitle .= $areaname ? ' - ' . $areaname : '';
$newtitle .= $hostname ? ' - ' . $hostname : '';
$newtitle .= $brokerage ? ', ' . $brokerage : '';
$newtitle .= $sponsorrep ? ' - ' . $sponsorrep : '';
$newtitle .= $sponsorentity ? ', ' . $sponsorentity : '';
if(empty($newtitle)) {
$newtitle = sprintf('ID%s: TBD', $post_id);
} else {
$newtitle = sprintf('ID%s: %s', $post_id, $newtitle);
}
// BUILD POST SLUG
// http://codex.wordpress.org/Data_Validation#Slugs
$newslug .= $location ? ' - ' . $location : '';
$newslug .= $areaname ? ' - ' . $areaname : '';
$newslug .= $hostname ? ' - ' . $hostname : '';
$newslug .= $brokerage ? ', ' . $brokerage : '';
$newslug .= $sponsorrep ? ' - ' . $sponsorrep : '';
$newslug .= $sponsorentity ? ', ' . $sponsorentity : '';
if(!empty($newslug)) {
$newslug = sprintf('%s-%s', $post_id, $newslug);
}
$newslug = sanitize_title($newslug);
//truncate slug to 100 characters
if( strlen($newslug) > 100 ) {
$newslug = substr($newslug, 0, 99);
}
}
$oldtitle = get_the_title($post_id);
$oldtitlereal = str_replace( array( 'Protected: ', 'Private: '), '', $oldtitle);
if( !empty($newtitle) && $oldtitlereal != $newtitle ) {
// unhook this function so it doesn't loop infinitely
// MUST be exact same as added hook, INCLUDING PRIORITY, else fatal memory exhausted error due to infinite loop
remove_action('save_post', 'set_open_post_title',100);
// update the post, which calls save_post again
$args = array(
'ID' => $post_id,
'post_title' => $newtitle,
'post_name' => $newslug, //WP would also sanitize for URL even if we did not
);
wp_update_post($args);
// re-hook this function
// MUST be exact same as added hook, INCLUDING PRIORITY, else fatal memory exhausted error due to infinite loop
add_action('save_post', 'set_open_post_title',100);
}
}
add_action('save_post', 'set_open_post_title',100);