WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I try to use this function i have created when a post is published for the first time.

function a_new_post($post){
  $post_id = $post->ID;

  if ( !get_post_meta( $post_id, 'firstpublish', $single = true ) ) {
      // ...run code once
      update_post_meta( $post_id, 'firstpublish', true );
add_action( 'draft_to_published', 'a_new_post' );

I can't see anything wrong with it, but when i try to create some sample posts i check the database and the field "firstpublished" has not been created.

Does anyone see anything wrong?

share|improve this question
shouldn't you change the hook to publish_post. draft_to_publish won't run for all the cases – Mridul Aggarwal Oct 19 '12 at 7:40
I tried publish_post and it does not work (wordpress.stackexchange.com/questions/141779/…) – user11948 Apr 21 '14 at 22:28
This is the most frustrating thing I have ever dealt with in WordPress. There is absolutely now way to catch publish and block update. Now way, no how. – user11948 May 1 '14 at 20:53
up vote 6 down vote accepted

The correct action is 'draft_to_publish'.

To be sure you used the correct status try to get a list of all registered post statuses (including custom statuses) with:

<pre><?php print '- ' . implode( "\n- ", array_keys( get_post_stati() ) );?></pre>

On a vanilla installation you should get:

  • publish
  • future
  • draft
  • pending
  • private
  • trash
  • auto-draft
  • inherit

Note that publish_post is called each time you edit a published post.

Note also get_post_stati() is one of these unpredictable names in WordPress: it is plain wrong. The plural of the noun status is statuses in English and statūs in Latin. :D

You could also hook into 'transition_post_status', depending on your needs. You get the new and the old status as arguments, the third argument is the post object. It will catch future_to_publish too, and also posts that were trashed once and republished now (trash_to_publish).


add_action( 'transition_post_status', 'a_new_post', 10, 3 );

function a_new_post( $new_status, $old_status, $post )
    if ( 'publish' !== $new_status or 'publish' === $old_status )

    if ( 'post' !== $post->post_type )
        return; // restrict the filter to a specific post type

    // do something awesome
share|improve this answer
+1 for the fourth- / u-declension – Johannes Pille Oct 19 '12 at 9:34
Can you tell me how this might be tailored to what I am trying to do @tocsho? See my question at wordpress.stackexchange.com/questions/141779/… -- thanks, greatly appreciated – user11948 Apr 21 '14 at 22:37
@H.Ferrence Replace your publish_post with transition_post_status (don’t forget the 10, 3 at the end). Set my checks on top of the callback function, then run your custom code where my example says do something awesome. – toscho Apr 21 '14 at 22:39
ok...everything else stays the same? – user11948 Apr 21 '14 at 22:40
@H.Ferrence You don’t need the get_post() call from your code anymore, because the third parameters is the complete post object. – toscho Apr 21 '14 at 22:45

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.