'How do you create an ACF custom location rule to compare post meta keys to meta values?

Let's say you create a WordPress post and assign it a meta key foo with value bar. You only want to display an ACF field if foo is equal to bar. However, there's no built-in location rule in ACF to do this. How would you solve this problem by creating an ACF custom location rule?



Solution 1:[1]

In order to display ACF fields if a post meta key is equal or not equal to some value, use the following snippet. It's based off of the ACF Custom Location Rules guide.

if( ! defined( 'ABSPATH' ) ) exit;

class My_ACF_Location_Post_Meta extends ACF_Location {

    public function initialize() {
        $this->name = 'post_meta';
        $this->label = __( "Post Meta", 'acf' );
        $this->category = 'post';
        $this->object_type = 'post';
    }

    public function rule_values($choices, $rule){
    
        if(!acf_is_screen('acf-field-group') && !acf_is_ajax('acf/field_group/render_location_rule')){
        
            return array(
                $rule['meta_key']   => $rule['meta_key'],
                $rule['meta_value'] => $rule['meta_value']
            );
        
        }
        
        ob_start();
        
        acf_render_field(array(
            'type'        => 'text',
            'name'        => 'meta_key',
            'prefix'      => 'acf_field_group[location]['.$rule['group'].']['.$rule['id'].']',
            'value'       => (isset($rule['meta_key']) ? $rule['meta_key'] : ''),
            'placeholder' => 'Meta Key'
        ));
        
        acf_render_field(array(
            'type'        => 'text',
            'name'        => 'meta_value',
            'prefix'      => 'acf_field_group[location]['.$rule['group'].']['.$rule['id'].']',
            'value'       => (isset($rule['meta_value']) ? $rule['meta_value'] : ''),
            'placeholder' => 'Meta Value'
        ));
        
        return ob_get_clean();
        
    }
    
    public function rule_operators($choices, $rule){
        
        $choices = [];
        $choices['key_is_equal_to_value']    = __('key is equal to value', 'acf');
        $choices['key_is_not_equal_to_value']   = __('key is not equal to value', 'acf');
        
        return $choices;
        
    }

    public function match( $rule, $screen, $field_group ) {

        // Check screen args for "post_id" which will exist when editing a post.
        // Return false for all other edit screens.
        if( isset($screen['post_id']) ) {
            $post_id = $screen['post_id'];
        } elseif (isset($screen['attachment_id'])) {
            $post_id = $screen['attachment_id'];
        } else {
            return false;
        }

        // Load the post meta object for this edit screen.
        $post_meta_value = get_post_meta( $post_id, $rule['meta_key'], true );
        if( !$post_meta_value ) {
            return false;
        }

        // Compare the Post's meta value to rule meta value.
        $result = ( strval($post_meta_value) == $rule['meta_value'] );

        // Return result taking into account the operator type.
        if( $rule['operator'] == 'key_is_not_equal_to_value' ) {
            return !$result;
        }
        return $result;
    }
}

add_action('acf/init', 'my_acf_init_location_types');
function my_acf_init_location_types() {
    // Check function exists, then include and register the custom location type class.
    if( function_exists('acf_register_location_type') ) {
        acf_register_location_type( 'My_ACF_Location_Post_Meta' );
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tyler