1

I'm trying to return a custom field as soon as a post gets published. I'm using the publish_post (or {status}_{post_type}) action, but it looks like the custom fields are created after the hook.

My code in functions.php:

function create_recurring_posts( $ID, $post ) {
    logMe(print_r(get_post_custom($ID), true));
}
add_action( 'publish_profile', 'create_recurring_posts', 10, 2 );

The logMe() function just logs the output to a file for testing purposes. My problem is, when I create the profile post, the only custom fields that get returned are _edit_last and _edit_lock. But when I view the page afterwards, where I have the same get_post_custom() function being ran, I see the other custom field I need.

I'm using Advanced Custom Fields for the field creation. Any help is appreciated.

3

Your action is triggered in wp_transition_post_status() which gets called by wp_insert_post() before the action save_post is triggered. save_post is the typical action to handle custom fields. ACF also works on this.

Basically you have to wait until ACF is done with its stuff, means you'll have to hook to save_post with a priority > 10 or better use wp_insert_post which runs right after save_post.

To track the post status transition, you can use a simple »log« like this:

<?php

namespace WPSE199070;

class PublishedTransitionLog {

    /**
     * @type array
     */
    private $status_log = [];

    /**
     * logs a published post id 
     * 
     * @wp-hook publish_profile
     *
     * @param int $post_id
     */
    public function published_post( $post_id ) {

        $blog_id = get_current_blog_id();
        if ( ! isset( $this->status_log[ $blog_id ] ) )
            $this->status_log[ $blog_id ] = [];

        if ( in_array( $post_id, $this->status_log[ $blog_id ] ) )
            return;

        $this->status_log[ $blog_id ][] = $post_id;
    }

    /**
     * @param int $post_id
     * @return bool
     */
    public function post_published( $post_id ) {

        $blog_id = get_current_blog_id();
        if ( ! isset( $this->status_log[ $blog_id ] ) )
            return FALSE;

        return in_array( $post_id, $this->status_log[ $blog_id ] );
    }
}

class PublishPostHandler {

    /**
     * @type PublishedTransitionLog
     */
    private $log;

    public function __construct( PublishedTransitionLog $log ) {

        $this->log = $log;
    }

    /**
     * @param int $post_id
     * @param \WP_Post $post 
     * @param bool $updated
     */
    public function update( $post_id, \WP_Post $post, $updated ) {

        if ( ! $this->log->post_published( $post_id ) )
            return;

        // do your stuff here
    }
}

$transition_log = new PublishedTransitionLog;
$handler        = new PublisPostHandler( $transition_log );

add_action( 'publish_profile', array( $transition_log, 'published_post' ) );
add_action( 'wp_insert_post', array( $handler, 'update', 10, 3 ) );

Let me explain this. The first class, PublishedTransitionLog listens to the action publish_profile and stores each published post for each blog internally. It also provides a method to check if a post was published before.

The second class should provide your logic and depends on the first class. If the post was not published it does just nothing.

This way you can listen independently to tow different hooks.

1

@David explained why your code doesn't work and sketched out a solution (use save_post instead). However, you can "chain" hooks together so that you should still be able to use the transition filters to control execution:

function create_recurring_posts( $ID, $post ) {
  add_action(
    'save_post',
    function() {
      // debug, since I don't have a `logMe()` function :)
      var_dump(print_r(get_post_custom($ID), true));
      die;
    },
    PHP_INT_MAX,
    1
  );   
}
add_action( 'publish_profile', 'create_recurring_posts', 10, 2 );
  • That's a notable architectural improvement, but you would still have to check the blog context in your save_post handler as well as compare the post IDs as you can not rely that other plugins update posts or switching the blog context on this hook. That's why I suggested to use wp_insert_post instead. – David Aug 20 '15 at 7:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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