How to filter select result based on another select’s value

In my WordPress theme, I have a custom post type named Segments which contains two custom fields made with ACF. What I’m trying to achieve is have the second field’s search based on the first field’s value.

The first one is called emission, the type of the field is a taxonomy which links the Segment post to the emission taxonomy.

Read More

The second one is called episode, the type of the field is a post_object which links the Segment post to the episode post type.

Now, what I want is the second field, to filter the episodes, that are in the same emission as the selected value of the first field.

The problem I’m having is, I’m unable to get the value of the first field without saving the Segment. Here’s what I’ve tried:

add_filter('acf/fields/post_object/query/key=field_57503ed5193d6', array($this, 'show_episodes'), 10, 3);

/*
* Function to show episodes that are from the same program as the current segment.
*/
public function show_episodes($args, $field, $post_id){
    error_log('Post Id: ' . $post_id);
    error_log(json_encode(get_field_object('emission')));
    error_log(json_encode(get_field('emission', $post_id)));

    return $args;
}

When I’m calling this for an already saved Segment, it’s returning the saved emission value, which is logical because it’s the value saved in the Database. When I’m calling this for a new segment, it’s not working since it has no value saved in the database, therefore, it returns a null. And whenever I edit the emission value for a saved segment, it still returns the old emission value (the one from the database).

Related posts

Leave a Reply

1 comment

  1. I’ve been able to achieve the result using Ajax and PHP sessions. Here’s what I did:

    Javascript

    // The id of the emission field generated by ACF
    this.emissionField = $('#acf-field_57473a3f32f6d-input');
    
    if(this.emissionField.length){
        let programId = this.emissionField.val();
    
        // Update the program id on page load if it's not empty, otherwise hide the emission box
        if(programId != ""){
            this.updateEpisodeFilter(this.emissionField.val());
        }else if(this.episodeBox.length) this.episodeBox.hide();
    
        // Update the program id when the emission change
        this.emissionField.on('change', function(){
            // Clear the select on value change
            $('#s2id_acf-field_57503ed5193d6-input').select2('val', '');
    
            this.updateEpisodeFilter(this.emissionField.val());
        }.bind(this));
    }
    
    /*
    * Function to update the program id in the session.
    */
    updateEpisodeFilter(programId){
        let episodeBox = this.episodeBox;
    
        $.ajax({
            url: '/wp-admin/admin-ajax.php',
            type: 'POST', 
            data:{
                action: 'update_filter_episodes',
                postId: $('#post_ID').val(),
                programId: programId,
            },
            success: function(response){
                if(response && episodeBox.length) episodeBox.show();
            }
        });
    }
    

    PHP

    // Add the action hook for the Ajax
    add_action('wp_ajax_update_filter_episodes', 'update_filter_episodes');
    add_action('wp_ajax_admin_update_filter_episodes', 'update_filter_episodes');
    

    So when we receive the action filter_episodes via Ajax, it calls the PHP function update_filter_episodes.

    /*
    * Function to update the program id for the episodes filter.
    */
    public function update_filter_episodes(){
        $this->startSession();
        if(isset($_POST['postId']) && isset($_POST['programId'])){
            $_SESSION['post-' . $_POST['postId'] . '-emission-id'] = $_POST['programId'];
            wp_send_json(true);
        }
        wp_send_json(false);
    }
    

    The startSession function to is check if the session has already been started:

    /*
    * Function to start the session if it's not already started.
    */
    protected function startSession(){
        if(session_status() != PHP_SESSION_ACTIVE)
            @session_start();
    }
    

    And to update the query called by ACF, we need another hook which will call the function show_episodes:

    add_filter('acf/fields/post_object/query/key=field_57503ed5193d6', 'show_episodes', 10, 3);
    
    /*
    * Function to show episodes that are from the same show as the current segment.
    */
    public function show_episodes($args, $field, $post_id){
        $this->startSession();
    
        $index = 'post-' . $post_id . '-emission-id';
        if(isset($_SESSION[$index]) && !empty($_SESSION[$index]))
            $args['tax_query'] = array(array('taxonomy' => 'category', 'terms' => $_SESSION[$index]));
    
        return $args;
    }
    

    Not sure if this is the easiest way, but it works for me. However, feel free to let me know if someone has a better solution!