0

I read over the ACF & WordPress documentation and both do not mention why/when/how duplicate values are removed from an array when sorting taxonomy terms by custom fields.

I learned that ACF does this from this StackExchange answer. But in this example code it is not sorting correctly and it doesn't work with krsort. With anything besides usort it gives the error: "krsort() expects parameter 2 to be long". Could anyone help here?

Shortcode I am trying to make with the example code:

function ranker_shortcode( $atts ) {
    extract( shortcode_atts( 
        array(
            'taxonomy' => '',
        ), $atts 
    ));
    $args = array( 
        'taxonomy' => $taxonomy,
    );

    $sorted = array();
    $terms  = get_terms( $taxonomy, $args );

    if( $terms ) {
        foreach ( $terms as $term ) {
            $sorted[]  = array(
                'height' => get_field( 'height', $term ), // Get field from ACF
                'name'  => $term->name,
            );
        }

        krsort( $sorted, SORT_NUMERIC );

        foreach( $sorted as $t ) {
            $html .= $t['height'] . ', ' . $t['name'] . '<br>';
        }

        return $html;
    }
}
add_shortcode( 'ranker', 'ranker_shortcode' );

Solved + Answer: Thanks to Pieter Goosen I got this working. I edited his answer somewhat to include more fields.

/**
 * Shortcode to sort taxonomy terms by meta field. Utilizes Advanced Custom Fields plugin.
 */
function sort_term_shortcode( $atts ) {
    // Defualt attributes
    $attributes = shortcode_atts( 
        [
            'taxonomy' => '',
        ], $atts 
    );

    $html = '';

    $taxonomy = filter_var( $attributes['taxonomy'], FILTER_SANITIZE_STRING );
    if ( ! $taxonomy ) 
        return $html; // sanitize shortcode attributes

    if ( ! taxonomy_exists( $taxonomy ) ) 
        return $html; // check shortcode attributes exists

    $terms  = get_terms( $taxonomy );
    if( ! $terms ) 
        return $html; // check terms exists

    $newterms = [];
    foreach ( $terms as $term ) {
        $height  = get_field( 'height', $term );
        $newterms[$height][]  = array(
            'name'        => $term->name,
            'count'       => $term->count,
            'description' => wpautop( $term->description ),
            'link'        => esc_url( get_term_link( $term ) ),
            'weight'      => get_field( 'weight', $term )
        );
    }

    krsort( $newterms, SORT_NUMERIC ); // biggest to smallest sort

    $c = 0;
    foreach( $newterms as $key => $value ) {
        foreach ( $value as $v ) {
            $c++;
            $thumb = wp_get_attachment_image_src( $v['avatar'], 't_thumb' );
            $html .= '<div class="panel panel-default">' . "\n";
                $html .= '<div class="panel-heading">' . "\n";
                    $html .= '<h3 class="panel-title">' . $c . ' &nbsp; <strong>' . $v['name'] . '</strong>,&nbsp; ' . $key . ', ' . $v['weight'] . 'lbs.</h3>' . "\n";
                $html .= '</div>' . "\n";
                $html .= '<div class="media panel-body">' . "\n";
                    $html .= '<a class="media-left" href="' . $v['link'] . '"><img src="' . $thumb[0] . '"></a>' . "\n";
                    $html .= '<div class="media-body">' . "\n";
                        $html .= $v['description'] . "\n";
                    $html .= '</div>' . "\n";
                $html .= '</div>' . "\n";
            $html .= '</div>' . "\n";
        }
    }
    return $html;

}
add_shortcode( 'sort_term', 'sort_term_shortcode' );
5
  • ACF specific questions are off-topic. Feb 23, 2016 at 17:34
  • @MarkKaplun There are definitely much more generic stuff which makes this on topic as ACF specific support ;-) Feb 23, 2016 at 17:38
  • If I understand the question correctly, it is about the stupid way ACF stores values associated with tems @PieterGoosen Feb 23, 2016 at 17:41
  • but maybe my mind not working properly Feb 23, 2016 at 17:42
  • It's actually a krsort/sorting issue. Sorting removes the duplicate values. Not just ACF @MarkKaplun Feb 23, 2016 at 17:57

1 Answer 1

1

PHP does not allow duplicate keys, the previous key/value pair is simply replaced with the current key/value pair. Anyways, lets look at your code and how we will solve it

You have a few issues here

  • You should not be using extract(), ever. It was removed from core a few years ago for very specific reasons. Please read @toscho's answer regarding extract()

  • Always sanitize and validate any user submitted data, even if that data is coming from you. User input data may contain malicious code which a hacker can use to get access to your site

  • $html is an undefined variable in your code, which is a bug. If you have debug turned on, you would get an explicit notice about that. Always define a variable before trying to use it, and always have debug set to true on your local test install

  • You are using get_terms() wrongly. The second parameter takes an array of parameters which does not include the taxonomy. The taxonomy is passed as first parameter

  • You are using ACF and ACF functions which will crash your site should ACF be uninstalled. Always do a check to make sure that external functions exists before suing it to avoid WSOD. Just a tip here, as from WordPress 4.4, you can now make use of the term metadata table to store additional info related to a term and then use that data to sort terms by. ACF is almost always a pain in the butt to remove when you no longer need the plugin

  • krsort is definitely the wrong sorting function to use in your current code. usort() should have being the correct sorting function to use. In our new code, krsort() would work perfectly

Lets look at better workaround. I accept that you need to display terms sorted by ACF field. You can try the following: (NOTE: The code below is untested and might be buggy. Also, I don't know the ACF plugin, make sure about my usage of get_field())

add_shortcode( 'ranker', 'ranker_shortcode' );
function ranker_shortcode( $atts ) 
{
    // Define our defualt attributes
    $attributes = shortcode_atts( 
        [
            'taxonomy' => '',
        ], $atts 
    );

    // Set our $html variable as empty string
    $html = '';

    // Sanitize and validate our taxonomy to avoid bugs later on. Return $html should anything fail
    $taxonomy = filter_var( $attributes['taxonomy'], FILTER_SANITIZE_STRING );
    if ( !$taxonomy )
        return $html;

    if ( !taxonomy_exists( $taxonomy ) )
        return $html;

    // We made it to hear, check if the ACF plugin is activated and that get_field() exists
    if ( !function_exists( 'get_field' ) )
        return $html;

    // Great, we made it to here, our checks checked out, lets continue
    $terms  = get_terms( $taxonomy );

    // Make sure we have terms, no need to check for WP_Error object because we know the taxonomy exists
    if( !$terms )
        return $html;

    // We have terms, lets loop through them and build our array
    $sorted = [];
    foreach ( $terms as $term ) {
        // Get our field value and make sure we have a field value, if not, just continue
        $field  = get_field( 'height', $term ); // Make sure we can pass the term object, don't know ACF

        if ( !$field )
            continue;

        // Our term have a field, lets build the array
        $sorted[$field][]  = $term->name;
    }

    // Lets sort the array DESC according to array key, which is our $field value
    krsort( $sorted, SORT_NUMERIC ); // Make sure here that your field is actually numeric to avoid bugs

    if ( !$sorted )
        return $html;

    // We are done, lets build our string and return it
    foreach( $sorted as $key=>$value ) {
        foreach ( $value as $v ) {
            $html .= $key . ', ' . $v . '<br>';
        }
    }
    return $html;
}
7
  • Thanks for the reply, it seems to be just returning 2 0's with a line break though. I'm wondering if it's returning all empty taxonomies? I had to slightly change the ACF area to: get_field( 'height', $taxonomy . '_' . $term->term_id ) Feb 23, 2016 at 18:50
  • Add ?><pre><?php var_dump($sorted); ?></pre><?php after krsort( $sorted, SORT_NUMERIC ); and see what the output is Feb 23, 2016 at 18:54
  • You're right! I removed the conditional statements just to test it, but of course I screwed something up in the process. I just ran it with everything you had and it's good to go. I will note though on the ACF field that ',' needs to be changed to ';' for proper PHP syntax. (In case anyone gets tripped by that if they find this through Google). Thanks again! Feb 23, 2016 at 19:18
  • My pleasure, glad it worked, will correct the syntax error. Enjoy ;-) Feb 23, 2016 at 19:21
  • If you don't mind can you add an example to your answer for more than 2 fields (height, name)? How about 3 or more (ex. height, name, description)? If it's tedious don't worry about it, you taught me a lot already. Feb 23, 2016 at 19:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.