ajax - Display sub-taxonomies based on SELECTED parent-taxonomy

admin2025-06-03  0

I have two drop downs. The first one contains list of parent taxonomies from a custom post type. And the second one contains all the sub-taxonomies at a time. But I'm trying to display only those sub-taxonomies of selected parent taxonomy (not all the sub-taxonomies from other parent taxonomies). For example, if I select a parent taxonomy from the first dropdown, then second dropdown should only display the sub-taxonomies of it. I'm not finding any php logic to achieve this goal. I'm displaying these two dropdowns on 'Edit Profile' page. Here is my code on functions.php

<?php
function slcustom_user_profile_fields($user) { ?>
<h1 id="temppp">Select a parent taxonomy</h1>
<select name="parent_category" id="parent_category">
  <?php
    global $wpdb;
    $parentCat = $wpdb->get_results( "SELECT name FROM wp_terms WHERE term_id IN (SELECT term_id FROM wp_term_taxonomy WHERE taxonomy = 'project_category' AND parent = 0)" );
    foreach ( $parentCat as $cat ) { ?>
      <option value="<?php echo esc_attr( $cat->name ) ?>"<?php echo selected( $user->parent_category, $cat->name ); ?>><?php echo $cat->name; ?></option>
    <?php }
  ?>
</select>

<p>Select a child taxonomy</p>
<select name="child_category" id="child_category">
  <?php 
//trying to bring this $termName value from JS
if(isset($_POST['selectedParentName'])) {
  $termName = isset($_POST['selectedParentName']);
}

$termId = get_term_by('name', $termName, 'project_category');
$selectedTermId = $termId->term_id;

  $id = $selectedTermId;
    $childCats = $wpdb->get_results( "SELECT name FROM wp_terms WHERE term_id IN (SELECT term_id FROM wp_term_taxonomy WHERE taxonomy = 'project_category' AND parent = ".$id." )" );
    foreach ($childCats as $childCat) { ?>
      <option value="<?php echo esc_attr( $childCat->name ) ?>"<?php echo selected( $user->child_category, $childCat->name ); ?>><?php echo $childCat->name; ?></option>
    <?php }
  ?>
</select>
<?php
}
add_action('show_user_profile', 'slcustom_user_profile_fields');
add_action('edit_user_profile', 'slcustom_user_profile_fields');


function save_custom_user_profile_fields($user_id) {
    if( current_user_can('edit_user', $user_id) ) {
        update_user_meta($user_id, 'parent_category', $_POST['parent_category']);
        update_user_meta($user_id, 'child_category', $_POST['child_category']);
    }
}
add_action('personal_options_update', 'save_custom_user_profile_fields');
add_action('edit_user_profile_update', 'save_custom_user_profile_fields');

script.js

$('select#parent_category').on('change', function() {
  var selectedParentName = this.value; //it tracks changes dropdown value
  $.ajax({
    type: 'POST',
    url: 'http://localhost:3000/wp-content/themes/mytheme/functions.php',
    data: { selectedParentName : selectedParentName }, //trying to send this 'selectedParentName' to functions.php
    success: function(data) {
       var sendThisDataToPHP = selectedParentName;
    }
  });
});

Updated Feb 19, 2019: script.js added and few lines on functions.php to receiving JS variable.

I have two drop downs. The first one contains list of parent taxonomies from a custom post type. And the second one contains all the sub-taxonomies at a time. But I'm trying to display only those sub-taxonomies of selected parent taxonomy (not all the sub-taxonomies from other parent taxonomies). For example, if I select a parent taxonomy from the first dropdown, then second dropdown should only display the sub-taxonomies of it. I'm not finding any php logic to achieve this goal. I'm displaying these two dropdowns on 'Edit Profile' page. Here is my code on functions.php

<?php
function slcustom_user_profile_fields($user) { ?>
<h1 id="temppp">Select a parent taxonomy</h1>
<select name="parent_category" id="parent_category">
  <?php
    global $wpdb;
    $parentCat = $wpdb->get_results( "SELECT name FROM wp_terms WHERE term_id IN (SELECT term_id FROM wp_term_taxonomy WHERE taxonomy = 'project_category' AND parent = 0)" );
    foreach ( $parentCat as $cat ) { ?>
      <option value="<?php echo esc_attr( $cat->name ) ?>"<?php echo selected( $user->parent_category, $cat->name ); ?>><?php echo $cat->name; ?></option>
    <?php }
  ?>
</select>

<p>Select a child taxonomy</p>
<select name="child_category" id="child_category">
  <?php 
//trying to bring this $termName value from JS
if(isset($_POST['selectedParentName'])) {
  $termName = isset($_POST['selectedParentName']);
}

$termId = get_term_by('name', $termName, 'project_category');
$selectedTermId = $termId->term_id;

  $id = $selectedTermId;
    $childCats = $wpdb->get_results( "SELECT name FROM wp_terms WHERE term_id IN (SELECT term_id FROM wp_term_taxonomy WHERE taxonomy = 'project_category' AND parent = ".$id." )" );
    foreach ($childCats as $childCat) { ?>
      <option value="<?php echo esc_attr( $childCat->name ) ?>"<?php echo selected( $user->child_category, $childCat->name ); ?>><?php echo $childCat->name; ?></option>
    <?php }
  ?>
</select>
<?php
}
add_action('show_user_profile', 'slcustom_user_profile_fields');
add_action('edit_user_profile', 'slcustom_user_profile_fields');


function save_custom_user_profile_fields($user_id) {
    if( current_user_can('edit_user', $user_id) ) {
        update_user_meta($user_id, 'parent_category', $_POST['parent_category']);
        update_user_meta($user_id, 'child_category', $_POST['child_category']);
    }
}
add_action('personal_options_update', 'save_custom_user_profile_fields');
add_action('edit_user_profile_update', 'save_custom_user_profile_fields');

script.js

$('select#parent_category').on('change', function() {
  var selectedParentName = this.value; //it tracks changes dropdown value
  $.ajax({
    type: 'POST',
    url: 'http://localhost:3000/wp-content/themes/mytheme/functions.php',
    data: { selectedParentName : selectedParentName }, //trying to send this 'selectedParentName' to functions.php
    success: function(data) {
       var sendThisDataToPHP = selectedParentName;
    }
  });
});

Updated Feb 19, 2019: script.js added and few lines on functions.php to receiving JS variable.

Share Improve this question edited Feb 19, 2019 at 11:06 Shihab asked Feb 17, 2019 at 11:37 ShihabShihab 1341 gold badge3 silver badges11 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 5 +50

Here's a fully functional snippet for doing this.

  • I added the correct WordPress table stylings
  • This requires adding my smyles_get_taxonomy_hierarchy to add children of taxonomy to the term object
  • This hides the child dropdown if no children exist
  • This handles everything (and saves) based on TERM ID not the NAME .. you should always use term ID as if you decide to change the wording/slug later on you will have all kinds of issues

Seems code syntax highlighter on here can't handle mix of HTML/JS/PHP, so here's a GitHub Gist of working code: https://gist.github/tripflex/527dd82db1d1f3bf82f761486fcc3303

Breakdown:

You first need to include my function to generate taxonomy array with children in that term object:

if ( ! function_exists( 'smyles_get_taxonomy_hierarchy' ) ) {
    /**
     * Recursively get taxonomy and its children
     *
     * @param string $taxonomy
     * @param int    $parent Parent term ID (0 for top level)
     * @param array  $args   Array of arguments to pass to get_terms (to override default)
     *
     * @return array
     */
    function smyles_get_taxonomy_hierarchy( $taxonomy, $parent = 0, $args = array( 'hide_empty' => false ) ) {

        $defaults = array(
            'parent'     => $parent,
            'hide_empty' => false
        );
        $r        = wp_parse_args( $args, $defaults );
        // get all direct decendants of the $parent
        $terms = get_terms( $taxonomy, $r );
        // prepare a new array.  these are the children of $parent
        // we'll ultimately copy all the $terms into this new array, but only after they
        // find their own children
        $children = array();
        // go through all the direct decendants of $parent, and gather their children
        foreach ( $terms as $term ) {
            // recurse to get the direct decendants of "this" term
            $term->children = smyles_get_taxonomy_hierarchy( $taxonomy, $term->term_id );
            // add the term to our new array
            $children[ $term->term_id ] = $term;
        }

        // send the results back to the caller
        return $children;
    }
}

jQuery/JavaScript code handling:

jQuery( function($){
    // slcustom_categories var should be available here
    $('#parent_category').change( function(e){
        var child_cat_select = $( '#child_category' );
        var term_id = $(this).val();

        console.log( 'Parent Category Changed', term_id );

        // Remove any existing
        child_cat_select.find( 'option' ).remove();

        // Loop through children and add to children dropdown
        if( slcustom_categories && slcustom_categories[ term_id ] && slcustom_categories[ term_id ]['children'] ){
            console.log( 'Adding Children', slcustom_categories[ term_id ]['children'] );
            $.each( slcustom_categories[term_id]['children'], function( i, v ){
                console.log( 'Adding Child: ', v );
                child_cat_select.append( '<option value="' + v['term_id'] + '">' + v[ 'name' ] + '</option>');
            });

            // Show if child cats
            $( '#child_category_row' ).show();
        } else {
            // Hide if no child cats
            $( '#child_category_row' ).hide();
        }
    });

    // Trigger change on initial page load to load child categories
    $('#parent_category').change();
});

Function to output fields:

function slcustom_user_profile_fields( $user ){

    $categories = smyles_get_taxonomy_hierarchy( 'project_category' );
    $parent_category = $user->parent_category;
    $child_category = $user->child_category;
//  $parent_category = 52; // used for testing
//  $child_category = 82; // used for testing
    $parent_has_children = ! empty( $parent_category ) && $categories[ $parent_category ] && ! empty( $categories[ $parent_category ]->children );

    // Creative way to use wp_localize_script which creates a JS variable from array
    // You should actually change this to load your JavaScript file and move JS below to that file
    wp_register_script( 'slcustom_user_profile_fields', '' );
    wp_localize_script( 'slcustom_user_profile_fields', 'slcustom_categories', $categories );
    wp_enqueue_script( 'slcustom_user_profile_fields' );
    ?>
    <h1 id="temppp">Select a parent taxonomy</h1>
    <table class="form-table">
        <tbody>
            <tr>
                <th>
                    Parent
                </th>
                <td>
                    <select name="parent_category" id="parent_category">
                    <?php
                        foreach( (array) $categories as $term_id => $cat ){
                            ?>
                            <option value="<?php echo esc_attr( $term_id ) ?>"<?php echo selected( $parent_category, $term_id ); ?>><?php echo $cat->name; ?></option>
                            <?php
                        }
                    ?>
                    </select>
                </td>
            </tr>
            <tr id="child_category_row" style="<?php if( ! $parent_has_children ){ echo 'display: none;'; }?>">
                <th>
                    Child
                </th>
                <td>
                    <select name="child_category" id="child_category">
                        <?php
                            if( $parent_has_children ){
                                foreach( (array) $categories[$parent_category]->children as $c_term_id => $child ){
                                    ?>
                                    <option value="<?php echo esc_attr( $c_term_id ) ?>"<?php echo selected( $child_category, $c_term_id ); ?>><?php echo $child->name; ?></option>
                                    <?php
                                }
                            }
                        ?>
                    </select>
                </td>
            </tr>
        </tbody>
    </table>
    <?php
}

You can use a simple foreach loop.

Let say I have a custom taxonomy "books"

This is how I get all the parents terms:

$terms = get_terms(array('taxonomy' => 'books', 'hide_empty' => false ));
$parents = array();
foreach ($terms as $item) {
    if($item->parent===0){
        $parents[] = $item;
    }
}
print_r($parents); //Show all the parent objects

On ajax call, send the parent id, to get the list of children objects, like this:

$parent = $_POST['parent'];
$terms = get_terms(array('taxonomy' => 'books', 'hide_empty' => false ));
$children = array();
foreach ($terms as $item) {
    if($item->parent === $parent){
        $children[] = $item;
    }
}
print_r($children); //show all children objects

You could achieve that by using js / jQuery. There might be more ways to it, but two comes into my mind.

  1. Watch for changes on the parent select and populate the child select options with ajax based on the selected parent option.
  2. Watch for changes on the parent select and hide the unrelated options from the child select based on the selected parent option.

EDIT 19.2.2019

add_action( 'wp_ajax_my_action', 'my_action' );
function my_action() {

  // check if user is logged in
  // is ajax request nonce valid
  // other stuff to make sure we can trust this request

  $selected_aprent_tax = strip_tags($_POST['parent_cat']);

  $tax_query = new WP_Tax_Query(array(
    'taxonomy'  =>  'project_category',
    'parent'    =>  $selected_aprent_tax,
  ));

  if ( $tax_query->terms ) {
    wp_send_json_success( $tax_query->terms );
  } else {
    wp_send_json( array() );
    wp_die();
  }

}

Then use my_action as the action parameter in your ajax request to trigger the function above. And send the ajax request to admin_url( 'admin-ajax.php' ).

With your jQuery script you would then grab the terms the php returns and do whatever you want with them. E.g. create select options from them.

NB It's quite late as I'm typing this so it's not a perfect example, but a rough one. Please refer to the codex to make the example work in your case, https://codex.wordpress/AJAX_in_Plugins

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1748883249a314516.html

最新回复(0)