Returning ACF custom field from publish_post

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.

2 Answers
2

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.

Leave a Comment