简体   繁体   中英

Sort a multi-dimensional array in Wordpress

Bit of a setup here to explain my issue, but in theory, all I need to do is order a multi-dimensional array before it outputs. The issue I'm having is that it's not grouping all the As, Bs and Cs etc together. I think it needs to sort all the names, before it adds the first letter...

<?php query_posts ( array ( 
    'post_type' => 'programme',
    'category_name' => 'archive',
    'order' => 'DESC' ) ); ?>

<div class="container_12">
    <div class="prefix_1 grid_10 suffix_1">
        <?php while ( have_posts() ) : the_post(); ?>

            <?php 

            $groups = array();

            if ( have_rows('artists') ) {

                while ( have_rows('artists') ) {

                    the_row();


                    // vars
                    $first_name = get_sub_field('first_name');
                    $last_name = get_sub_field('last_name');
                    $first_letter = substr($last_name, 0, 1);


                    // add $first_letter holder to groups
                    if( !isset($groups[ $first_letter ]) ) {

                        $groups[ $first_letter ] = array();

                    }


                    // append artist to group
                    $groups[ $first_letter ][] = $first_name . ' ' . $last_name;

                }

            }

            // ouput
            if( !empty($groups) ): ?>

                <?php foreach( $groups as $letter => $artists ) : ?>

                    <h3><?php echo $letter; ?></h3>

                    <?php foreach( $artists as $artist ): ?>
                        <p><?php echo $artist; ?></p>
                    <?php endforeach; ?>

                <?php endforeach; ?>

            <?php endif; ?>

        <?php endwhile; ?>
    </div>
</div>
<div class="clear"></div>

<?php wp_reset_postdata(); ?>

This currently outputs as:

在此处输入图片说明

And if you see in the image below, where I have just print_r( $groups ) it needs to add all the arrays into one big array, then sort it.

在此处输入图片说明

So, ultimately, I'd like to end up with something like:

A
Joe Allan
Frank Aztec

B
Jane Bank

C
Mike Crichton
Mandy Curtz

UPDATE

This is what I have no, and need to sort the artists, alphabetically, by their last name.

<?php if( !empty($groups) ) : ?>
    <?php ksort($groups); ?>
    <?php foreach ( $groups as $letter => $artists ) : ?>
        <div>
        <h3><?php echo $letter; ?></h3>
        <?php asort($artists); ?>
        <?php foreach( $artists as $artist ) : ?>
            <p><?php echo $artist; ?></p>
        <?php endforeach; ?>
        </div>
    <?php endforeach; ?>
<?php endif; ?>

This gives me, using B as an example:

B

Berendes, Eva

Bloor, Simon

Bloor, Tom

Burt, Theo

Barnes, Kristian

Bajo, Elena

I would like to propose a totally different approach to the problem. I know it's not the answer to the exact question you post, but I think it's the answer to your problem. I believe your problem is getting the array of artists with the capital letter, so, instead of doing all this PHP nightmare, I would like to propose you get all ordered via MySQL from the DDBB (because ordering via PHP is hard, complex (as you are just watching) and resourcing hog...) and only print the results:

<?php
    // Get access to DDBB manager object
    global $wpdb;

    // Launch a query will give back all ordered, in rows with the capital letter
    // and an array in JSON format with the group names
    $query = $wpdb->get_results("
SELECT 
  GROUP_CONCAT('[', CONCAT(first_name, ', ',last_name), ']' SEPARATOR ', ') as name
, LEFT(last_name, 1) capLetter
FROM artists 
GROUP BY capLetter
ORDER BY last_name, first_name;");

    // Printing the results (they came ordered, ;D):
    foreach ($query as $row) {
        echo $row->capLetter;
        $artists = json_decode($row->name);
        foreach ($artists as $artist) {
            echo $artist;
        }
    }    

?>

I use GROUP_CONCAT to build a JSON array in which we store the values from the DDBB, and with group and order from the MySQL engine is pretty easy to achieve what we want. I only tested the query, and I got the way of launching a custom query with WordPress from http://www.makeuseof.com/tag/working-custom-database-tables-wordpress/

Put $groups = array(); above the first while loop, and also:

    if( !empty($groups) ): ?>

        <?php foreach( $groups as $letter => $artists ) : ?>

            <h3><?php echo $letter; ?></h3>

            <?php foreach( $artists as $artist ): ?>
                <p><?php echo $artist; ?></p>
            <?php endforeach; ?>

        <?php endforeach; ?>

    <?php endif; ?>

below the <?php endwhile; ?> <?php endwhile; ?>

Like how Chococroc proposed , achieving it using a database query would be efficient .

But if you were already running a query for some other purpose which also retrieves the artists , then rather than running another query , you could use PHP based solution .

Assuming that you can grab all the names , I am considering an input array like this :

$allNames =
    array(
        array( 'Kate' ,'Allen' )
        ,array( 'Simon' ,'Bloor' )
        ,array( 'Tom' ,'Bloor' )
        ,array( 'Theo' ,'Burt' )
        ,array( 'Ross' ,'Chisholm' )
        ,array( 'Eva' ,'Berendes' )
        ,array( 'Kristian' ,'Barnes' )
        ,array( 'Ashley' ,'Holmes' )
        ,array( 'Joe' ,'Allan' )
        ,array( 'Frank' ,'Aztec' )
        ,array( 'Jane' ,'Bank' )
        ,array( 'Kike' ,'Crichton' )
        ,array( 'Mandy' ,'Curtz' )
    );

The actual solution starts here :

/*
 *  Put all the names in to $tempArray as lastName:firstName format
 */

$tempArray = array();

foreach( $allNames as $fullName )
{
    list( $firstName ,$lastName ) = $fullName;
    $tempArray[] = $lastName .':' .$firstName; 
}

/*
 *  Use which ever sort suits your requirement and sort the $tempArray
 */

sort( $tempArray );

/*
 *  Now put the names into groups by the first letter of last name
 */

$groups = array( );

foreach( $tempArray as $value )
{
    $firstLetter = substr( $value ,0 ,1 );

    if( ! isset( $groups[$firstLetter] ) ) $groups[$firstLetter] = array( );

    list( $lastName ,$firstName ) = explode( ":" ,$value );

    $groups[$firstLetter][] = $firstName .' ' .$lastName;
}

Result :

var_dump( $groups );

Gives :

  'A' => 
      'Joe Allan'
      'Kate Allen'
      'Frank Aztec'
  'B' => 
      'Jane Bank'
      'Kristian Barnes'
      'Eva Berendes'
      'Simon Bloor'
      'Tom Bloor'
      'Theo Burt'
  'C' => 
      'Ross Chisholm'
      'Kike Crichton'
      'Mandy Curtz'
  'H' => 
      'Ashley Holmes'

If I were to include my solution in to the code you've tried , it could turn to as shown below . This is not tested and probably could need modifications :

<?php query_posts ( array (
    'post_type' => 'programme',
    'category_name' => 'archive',
    'order' => 'DESC' ) ); ?>

<div class="container_12">
    <div class="prefix_1 grid_10 suffix_1">
        <?php
        /*
         *  Put all the names in to $tempArray as lastName:firstName format
         */
        $tempArray = array();
        ?>

        <?php while( have_posts() ) : the_post(); ?>

            <?php 
            if( have_rows( 'artists' ) )
            {
                while( have_rows('artists') )
                {
                    the_row();
                    $tempArray[] = get_sub_field( 'last_name' ) .':' .get_sub_field( 'first_name' );
                }
            }
            ?>

        <?php endwhile; ?>

        <?php
        /*
         *  Use which ever sort suits your requirement and sort the $tempArray
         */

        sort( $tempArray );

        /*
         *  Now put the names into groups by the first letter of last name
         */

        $groups = array( );

        foreach( $tempArray as $value )
        {
            $firstLetter = substr( $value ,0 ,1 );

            if( ! isset( $groups[$firstLetter] ) ) $groups[$firstLetter] = array( );

            list( $lastName ,$firstName ) = explode( ":" ,$value );

            $groups[$firstLetter][] = $firstName .' ' .$lastName;
        }
        ?>

        <?php if( ! empty($groups) ): ?>

            <?php foreach( $groups as $letter => $artists ) : ?>

                <h3><?php echo $letter; ?></h3>

                <?php foreach( $artists as $artist ): ?>
                    <p><?php echo $artist; ?></p>
                <?php endforeach; ?>

            <?php endforeach; ?>

        <?php endif; ?>
</div>
</div>
<div class="clear"></div>

<?php wp_reset_postdata(); ?>

Since the author got another problem with sorting the array i will add another answer which hopefully does help. As stated in my comment you should use ksort to sort the outer array by key. Now sorting the inner arrays by the last name is a little bit trickier. There is a useful function called uasort , which lets the user define a function by which the array entries are getting compared. So what you want to do is something like this:

ksort($groups);
foreach ($groups as &$group) {
    uasort($group, 'sortLastName');
}
unset($group); 

While using sortLastName as a comparison function, which is defined like this:

function sortLastName($a, $b) {
    $aLast = end(explode(" ", $a));
    $bLast = end(explode(" ", $b));

    return strcasecmp($aLast, $bLast);
};

Here is a working example on Ideone.com http://ideone.com/vU8ukk

Hope i could help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM