<?php if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly if( ! class_exists('ACF_Local_Meta') ) : class ACF_Local_Meta { /** @var array Storage for meta data. */ var $meta = array(); /** @var mixed Storage for the current post_id. */ var $post_id = 0; /** * __construct * * Sets up the class functionality. * * @date 8/10/18 * @since 5.8.0 * * @param void * @return void */ function __construct() { // add filters add_filter( 'acf/pre_load_post_id', array($this, 'pre_load_post_id'), 1, 2 ); add_filter( 'acf/pre_load_meta', array($this, 'pre_load_meta'), 1, 2 ); add_filter( 'acf/pre_load_metadata', array($this, 'pre_load_metadata'), 1, 4 ); } /** * add * * Adds postmeta to storage. * Accepts data in either raw or request format. * * @date 8/10/18 * @since 5.8.0 * * @param array $meta An array of metdata to store. * @param mixed $post_id The post_id for this data. * @param bool $is_main Makes this postmeta visible to get_field() without a $post_id value. * @return array */ function add( $meta = array(), $post_id = 0, $is_main = false ) { // Capture meta if supplied meta is from a REQUEST. if( $this->is_request($meta) ) { $meta = $this->capture( $meta, $post_id ); } // Add to storage. $this->meta[ $post_id ] = $meta; // Set $post_id reference when is the "main" postmeta. if( $is_main ) { $this->post_id = $post_id; } // Return meta. return $meta; } /** * is_request * * Returns true if the supplied $meta is from a REQUEST (serialized <form> data). * * @date 11/3/19 * @since 5.7.14 * * @param array $meta An array of metdata to check. * @return bool */ function is_request( $meta = array() ) { return acf_is_field_key( key( $meta ) ); } /** * capture * * Returns a flattened array of meta for the given postdata. * This is achieved by simulating a save whilst capturing all meta changes. * * @date 26/2/19 * @since 5.7.13 * * @param array $values An array of raw values. * @param mixed $post_id The post_id for this data. * @return array */ function capture( $values = array(), $post_id = 0 ) { // Reset meta. $this->meta[ $post_id ] = array(); // Listen for any added meta. add_filter('acf/pre_update_metadata', array($this, 'capture_update_metadata'), 1, 5); // Simulate update. if( $values ) { acf_update_values( $values, $post_id ); } // Remove listener filter. remove_filter('acf/pre_update_metadata', array($this, 'capture_update_metadata'), 1, 5); // Return meta. return $this->meta[ $post_id ]; } /** * capture_update_metadata * * Records all meta activity and returns a non null value to bypass DB updates. * * @date 26/2/19 * @since 5.7.13 * * @param null $null . * @param (int|string) $post_id The post id. * @param string $name The meta name. * @param mixed $value The meta value. * @param bool $hidden If the meta is hidden (starts with an underscore). * @return false. */ function capture_update_metadata( $null, $post_id, $name, $value, $hidden ) { $name = ($hidden ? '_' : '') . $name; $this->meta[ $post_id ][ $name ] = $value; // Return non null value to escape update process. return true; } /** * remove * * Removes postmeta from storage. * * @date 8/10/18 * @since 5.8.0 * * @param mixed $post_id The post_id for this data. * @return void */ function remove( $post_id = 0 ) { // unset meta unset( $this->meta[ $post_id ] ); // reset post_id if( $post_id === $this->post_id ) { $this->post_id = 0; } } /** * pre_load_meta * * Injects the local meta. * * @date 8/10/18 * @since 5.8.0 * * @param null $null An empty parameter. Return a non null value to short-circuit the function. * @param mixed $post_id The post_id for this data. * @return mixed */ function pre_load_meta( $null, $post_id ) { if( isset($this->meta[ $post_id ]) ) { return $this->meta[ $post_id ]; } return $null; } /** * pre_load_metadata * * Injects the local meta. * * @date 8/10/18 * @since 5.8.0 * * @param null $null An empty parameter. Return a non null value to short-circuit the function. * @param (int|string) $post_id The post id. * @param string $name The meta name. * @param bool $hidden If the meta is hidden (starts with an underscore). * @return mixed */ function pre_load_metadata( $null, $post_id, $name, $hidden ) { $name = ($hidden ? '_' : '') . $name; if( isset($this->meta[ $post_id ]) ) { if( isset($this->meta[ $post_id ][ $name ]) ) { return $this->meta[ $post_id ][ $name ]; } return '__return_null'; } return $null; } /** * pre_load_post_id * * Injects the local post_id. * * @date 8/10/18 * @since 5.8.0 * * @param null $null An empty parameter. Return a non null value to short-circuit the function. * @param mixed $post_id The post_id for this data. * @return mixed */ function pre_load_post_id( $null, $post_id ) { if( !$post_id && $this->post_id ) { return $this->post_id; } return $null; } } endif; // class_exists check /** * acf_setup_meta * * Adds postmeta to storage. * * @date 8/10/18 * @since 5.8.0 * @see ACF_Local_Meta::add() for list of parameters. * * @return array */ function acf_setup_meta( $meta = array(), $post_id = 0, $is_main = false ) { return acf_get_instance('ACF_Local_Meta')->add( $meta, $post_id, $is_main ); } /** * acf_reset_meta * * Removes postmeta to storage. * * @date 8/10/18 * @since 5.8.0 * @see ACF_Local_Meta::remove() for list of parameters. * * @return void */ function acf_reset_meta( $post_id = 0 ) { return acf_get_instance('ACF_Local_Meta')->remove( $post_id ); }