简体   繁体   中英

Foreach loop grouping by category

I asked this question on the WordPress Stack Exchange and it's not getting much of a response after 24 hours. So I thought I would bring it to a bigger community.

Anyway, I am creating an events plugin, which works, however I am having a little trouble nailing down the listing page. It shows all events, however I want it to group them by month. The statement needs to pull the date of the event, grab the month, and group records together that fall in that specific month. I know it's going to be a foreach, but I am not sure how to write it.

Here is my loop:

 // Query Post Type
$args = array(
    'post_type' => 'events',
    'post_status' => 'publish',
    'meta_key' => '_eDate',
    'orderby' => 'meta_value_num'
);
$the_query = new WP_Query($args);

// Build It
if ($the_query->have_posts()) :
    ?>
    <div id="event-list">
        <?php
        global $post;

        $month_array = array();
        while ($the_query->have_posts()) : $the_query->the_post();

            var_dump( get_post_meta( $post->ID, '_eDate', true ) ); 

            $date_field = get_post_meta( $post->ID, '_eDate', true );
            $month_format = new DateTime();
            $month_format->createFromFormat('Y-m-d', $date_field); 
            $month_number = $month_format->format('m'); 
            $month_array[] = $month_number; 

            if ($the_query != 0 && $month_number != $month_array[$the_query->current_post - 1]) //LINE 38
                echo '<h2>' . $month_format->format( 'F' ) . '</h2>'; 
            ?>

            <div class="row">
                <div class="event-image">
                    <a href="<?php echo get_permalink(get_the_ID()); ?>">
                        <?php
                        if (has_post_thumbnail()) {
                            the_post_thumbnail('thumbnail');
                        }
                        ?>
                    </a>
                </div>
                <div class="event-content">
                    <h3><a href="<?php echo get_permalink(get_the_ID()); ?>"><?php the_title(); ?></a></h3>
                    <div class="event-date"><?php display_event_date(); ?></div>
                    <div class="event-time"><?php display_event_time(); ?></div>
                    <div class="event-price"><?php display_event_price(); ?></div>
                    <br/>
                    <a href="<?php echo get_permalink(get_the_ID()); ?>" class="event-info">More Information</a>
                </div>
                <div class="event-buy">
                    <?php display_event_buy_online_url(); ?>
                </div>
            </div>
        </div>
        <?php wp_reset_postdata(); ?>
        <?php
    endwhile;
endif;

--- EDIT 1 ---

I have updated my code block based on input.

The var_dump is outputting as so string(10) "2015-07-09"

I am also getting two errors.

Notice: Object of class WP_Query could not be converted to int in C:\\xampp\\apps\\wordpress\\htdocs\\wp-content\\plugins\\wp-events-em4b\\views\\shortcode.php on line 38

Notice: Undefined offset: -1 in C:\\xampp\\apps\\wordpress\\htdocs\\wp-content\\plugins\\wp-events-em4b\\views\\shortcode.php on line 38

The month that is being converted from int to text is wrong, it is pulling the last time the post was edited, but the var_dump has the correct date.

As I have stated in my answer to your question on WPSE, you will need to get your posts sorted by the date in your custom field. This is as easy as adding the correct parameters to your query arguments

If your dates are saved in the following format, Ymd , it is quite easy. Your year will stay the same, so your can then technically sort by month.

All you need is to add the correct values to the order and orderby parameters. You can try the following

// Query Post Type
$args = array(
    'post_type' => 'events',
    'post_status' => 'publish',
    'meta_key' => '_eDate',
    'orderby' => 'meta_value'
);

If you need to sort by month regardless of year, then you would need to use usort() to sort your loop before executing it. If this is the case, let me know so that I can adjust my answer accordingly.

You've already stated that your date format in your custom field is Ymd , so your loop should be correctly sorted by date according to the date in your custom field _eDate

All you need to do now is to check the dates (months) between the current post in the loop against the previous post in the loop, and if they differ, output the month. You don't need a foreach loop, neither do you need output buffering or creating a new array with posts from the original array of posts

The following code is untested, also, make sure that date format in your custom field is correct. Inside your loop you would want to first do var_dump( get_post_meta( $post->ID, '_eDate', true ) ); to verify that you get the correct value in the correct format. Everything in my code relies on this small piece of info. If the value or format is incorrect in your _eDate custom field, my code will fail. Please adjust, modify and abuse my code as needed

 // Query Post Type
$args = array(
    'post_type' => 'events',
    'post_status' => 'publish',
    'meta_key' => '_eDate',
    'orderby' => 'meta_value' //HAD A BUG HERE, DID NOT SORT CORRECTLY, NEEDS TO BE meta_value
);
$the_query = new WP_Query($args);

// Build It
if ( $the_query->have_posts() ) :
    ?>
    <div id="event-list">
        <?php
        $month_array = array();
        while ( $the_query->have_posts() ) : 
            $the_query->the_post();

            $date_field = get_post_meta( $post->ID, '_eDate', true );
            $month_format = DateTime::createFromFormat( 'Y-m-d', $date_field ); // HAD A BUG HERE, CONVERTED WRONG DATE
            $month_number = $month_format->format('m');
            $month_array[] = $month_number; 

            // Choose the format you want to display as indicated below
            if ( $the_query->current_post == 0 ) // Output date id this is the first post
                echo '<h2>' . $month_format->format( 'F' ) . '</h2>'; // Output month name as January

            if (    $the_query->current_post != 0 //HAD A BUG HERE, WAS $the_query != 0
                 && $month_number != $month_array[$the_query->current_post - 1] 
            )
                echo '<h2>' . $month_format->format( 'F' ) . '</h2>'; // Output month name as January            
            ?>

            <div class="row">
                <div class="event-image">
                    <a href="<?php echo get_permalink(get_the_ID()); ?>">
                        <?php
                        if (has_post_thumbnail()) {
                            the_post_thumbnail('thumbnail');
                        }
                        ?>
                    </a>
                </div>
                <div class="event-content">
                    <h3><a href="<?php echo get_permalink(get_the_ID()); ?>"><?php the_title(); ?></a></h3>
                    <div class="event-date"><?php display_event_date(); ?></div>
                    <div class="event-time"><?php display_event_time(); ?></div>
                    <div class="event-price"><?php display_event_price(); ?></div>
                    <br/>
                    <a href="<?php echo get_permalink(get_the_ID()); ?>" class="event-info">More Information</a>
                </div>
                <div class="event-buy">
                    <?php display_event_buy_online_url(); ?>
                </div>
            </div>
        </div>
        <?php wp_reset_postdata(); ?>
        <?php
    endwhile;
endif;

EDIT

I have fixed the code above and tested it. Everything is working now as expected. Please see the comments in the code for the bugs fixed

Here is one possible way. This example captures the output from rendering the post event to a variable, stores it in an array keyed by the month, and then loops over the array so you can then print the events grouped by month.

You will need to make some adjustment to where it captures the month though as I don't know the details of your functions.

<?php
// Query Post Type
$args = array(
    'post_type' => 'events',
    'post_status' => 'publish'
);

$the_query = new WP_Query($args);
$posts = array(); // array for storing posts by month

// Build It
if ($the_query->have_posts()) :
    ?>
    ob_start(); // start buffering the output from the posts
    <div id="event-list">
        <?php
        while ($the_query->have_posts()) : $the_query->the_post();
            ?>
            <div class="row">
                <div class="event-image alignleft">
                    <a href="<?php echo get_permalink(get_the_ID()); ?>">
                        <?php
                        if (has_post_thumbnail()) {
                            the_post_thumbnail('thumbnail');
                        }
                        ?>
                    </a>
                </div>
                <div class="event-content alignleft">
                    <h3><a href="<?php echo get_permalink(get_the_ID()); ?>"><?php the_title(); ?></a></h3>
                    <div class="event-date"><?php display_event_date(); ?></div>
                    <div class="event-time"><?php display_event_time(); ?></div>
                    <div class="event-price"><?php display_event_price(); ?></div>
                    <br/>
                    <a href="<?php echo get_permalink(get_the_ID()); ?>">More Information</a>
                </div>
                <div class="event-buy alignleft">

                    <div class="event-buy">
                        <a class="buy-btn btn" href="<?php display_event_buy_online_url(); ?>" target="_blank">Buy Online</a>
                    </div>
                </div>
            </div>
            <hr>
        </div>
        $post = ob_get_contents(); // get the contents of the post to a variable
        ob_end_clean(); // clear output buffer
        $month = date('m', strtotime(get_event_date())); // get event month *THIS NEEDS TO BE CHANGED*
        $posts[$month][] = $post; // append post to month array
        <?php wp_reset_postdata(); ?>
        <?php
    endwhile;

    sort($posts); // sort post array by month numbers

    foreach($posts as $month) {
        // starting to display posts for a new month
        foreach($month as $post) {
            echo $post; // output the saved post from variable
        }
    }
endif;

Alternatively, you might be able to use sorting options to sort the events by date:

$args = (
    'orderby' => 'event_date',
    'order' =>   'ASC',`
);

and then check the date in the post loop and check the month of the post in the loop for changes if you want to output any html when the month changes.

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