Custom front-end sorting

Hello WPMUDEV community!

It's been a while since I've posted, only because it's been a while I've been stumped with some coding.

I am trying to add a custom front-end sort for 2 separate custom functions (each with custom queries) which appear on the same page (see example next to slider [top right of page contents] http://wearejack.ca/CAL/formations-continue/secteurs-dactivite/).

I want to filter each by year and also by month. The year and month displaying for each post is a custom meta_value represented by ('Ymd').

Is there a way to use pre_get_posts and relate it to a specific function without affecting the other function on the page?

Page output:

<?php echo page_secteurs_upcoming_sceances(); ?>
       <br /><br />
   <?php echo page_secteurs_upcoming_class_start(); ?>

Both queries are fairly similar, so I will show one as the example:

function page_secteurs_upcoming_class_start() {

   // find todays date
	$date = date('Ymd');
	$year = date('Y');
	// find current year (yyyy)
	$nextyear = $year+1;
	// find current year (yyyy)
	$month = date('m');
	$nextmonth = $month+1;

	$beginningofyear = date($year.'0101');
	$endofyear = date($nextyear.'0101');
	$customDate = date('Y'.$month.'d');

   // args
	$args = array(
		'post_type'		 => 'formation-continue',
		'post_status'    => 'publish',
		'posts_per_page' => 3,
		'meta_query'	 => array(
			array(
				'key'		=> 'debut_cours',
				'value'		=> $date,
				'compare'	=> '>=',
				'type'    => 'NUMERIC',
			),
		),
		'meta_key'		 => 'debut_cours',
		'orderby'   	 => 'meta_value',
		'order'			 => 'ASC',
	);

	// query
	$sceances_query = new WP_Query( $args );

			if( $sceances_query->have_posts() ) : while ( $sceances_query->have_posts() ) : $sceances_query->the_post();

			static $count = 0;

            echo '<div class="vc_col-sm-5"><a href="'; the_permalink(); echo '">';
				the_title();
			echo '</a></div>';

			echo '<div class="vc_col-sm-3">';
				the_field('sigle_formation');
			echo '</div>';

			echo '<div class="vc_col-sm-4">';
				//the_field('debut_cours');
				$dateformatstring = "d/m/Y";
				//$dateformatstring = "ymd";
				$unixtimestamp = strtotime(get_field('debut_cours'));
				echo date_i18n($dateformatstring, $unixtimestamp);
			echo '</div>';

			echo '<div class="clearfix"></div>';

				endwhile;
			endif; //#end  // $FC_posts->have_posts() //

				wp_reset_postdata();

	echo '<div class="clearfix"></div>';

}

I read the WPMU post How to Add Post Filters to Your WordPress Site, but I couldn't get it to work for my needs. https://premium.wpmudev.org/blog/add-post-filters/

Any help would be greatly appreciated :slight_smile:

Thanks,
josh

  • Nithin

    Hi josh_redler,

    I haven't test this extensively, but from reading your code, could you please try the following, and check whether it works:

    function pre_custom_date( $where = '' ) {
    
    	$date = date('Ymd');
    	$year = date('Y');
    	// find current year (yyyy)
    	$nextyear = $year+1;
    	// find current year (yyyy)
    	$month = date('m');
    	$nextmonth = $month+1;
    
    	$beginningofyear = date($year.'0101');
    	$endofyear = date($nextyear.'0101');
    	$customDate = date('Y'.$month.'d');
    
        	$where .= " AND post_date < '$customDate'";
    	return $where;
    }
    
    function pre_custom_filter_post( $query ) {
        if ( !is_admin() && $query->is_main_query() ) {
            $query->set( 'order', 'ASC' );
            add_filter( 'posts_where', 'pre_custom_date' );
        }
        return $query;
    }
    add_action( 'pre_get_posts', 'pre_custom_filter_post' );

    This should filter according to the $customDate variable passed, please check whether this would fit to you needs, if not we could give a closer look. Have a nice day. :slight_smile:

    Kind Regards,
    Nithin

  • josh_redler

    Hi Nithin,

    Thanks for your reply. I'm a little confused. How do I relate those functions to the function that outputs my initial results [page_secteurs_upcoming_class_start()]?

    For instance, how would I create a drop down just above the output of the function that gives me a filter to select all where the custom meta_value is equally to a specific month.

    for instance, based on my function page_secteurs_upcoming_class_start() how can I add a post filters form with your functions for pre_get_posts?

    See below what I am trying to accomplish.

    // find current year (yyyy)
    $year = date('Y');
    $nextyear = $year+1;
    // find current month (mm)
    $month = date('m');
    $nextmonth = $month+1;
    
    $beginningofyear = date($year.'0101');
    $endofyear = date($nextyear.'0101');
    
    <form class='post-filters'>
    	<select name="month">
    		<?php
    			$order_options = array(
    				'Jan' => '[meta_value >= $year0101 AND < $year0201]', //i know this is not correct
    				'Feb' => '[meta_value >= $currentyear0201 AND < $currentyear0301]',
                                     etc... for each month
    			);
    			foreach( $order_options as $value => $label ) {
    				echo "<option ".selected( $_GET['order'], $value )." value='$value'>$label</option>";
    			}
    		?>
    	</select>
    	<select name="year">
    		<?php
    			$order_options = array(
    				'2016' => '[meta_value >= $beginningofyear AND <= $endofyear]', //i know this is not correct
    				'2017' => '[meta_value >= $endofyear AND < $nextyear1231]',
                                     etc... for each month
    			);
    			foreach( $order_options as $value => $label ) {
    				echo "<option ".selected( $_GET['order'], $value )." value='$value'>$label</option>";
    			}
    		?>
    	</select>
    	<input type='submit' value='Filter!'>
    </form>
     <?php echo page_secteurs_upcoming_class_start(); // this is the initial custom query output ?>

    Thanks,
    josh

  • Kasia Swiderska

    Hello josh,

    Please see here on how you can add pre_get_post filter to your custom query http://wordpress.stackexchange.com/a/52482 (as you can see there are two methods).
    You can use pre_get_posts only on query.
    Also can you show us whole code you have? I mean the working example (one from above will not work because of the lack of the php tags in right places.

    kind regards,
    Kasia

  • josh_redler

    Hi Kasia and support team!

    Here is a fuller description of my code and what I am trying to accomplish...

    FUNCTION 1

    function page_secteurs_upcoming_sceances() {
    
       // find todays date
    	$date = date('Ymd');
    
       // args
    	$args = array(
    		'numberposts'	 => 3,
    		'post_type'		 => 'formation-continue',
    		'post_status'    => 'publish',
    		'posts_per_page' => 3,
    		'meta_query'	 => array(
    			'relation'		=> 'OR',
    			array(
    				'key'		=> 'seance_dinformations_1_date',
    				'value'		=> $date,
    				'compare'	=> '>=',
    				'type'    => 'NUMERIC',
    			),
    			array(
    				'key'		=> 'seance_dinformations_2_date',
    				'value'		=> $date,
    				'compare'	=> '>=',
    				'type'    => 'NUMERIC',
    			),
    			array(
    				'key'		=> 'seance_dinformations_3_date',
    				'value'		=> $date,
    				'compare'	=> '>=',
    				'type'    => 'NUMERIC',
    			)
    		),
    		'orderby'   	 => 'meta_value',
    		'order'			 => 'ASC',
    	);
    
    	// query
    	$sceances_query = new WP_Query( $args );
    
    	if( $sceances_query->have_posts() ) : while ( $sceances_query->have_posts() ) : $sceances_query->the_post();
    
                echo '<div class="vc_col-sm-5"><a href="'; the_permalink(); echo '">';
    				the_title();
    			echo '</a></div>';
    
    			echo '<div class="vc_col-sm-3">';
    				the_field('sigle_formation');
    			echo '</div>';
    
    			echo '<div class="vc_col-sm-4">';
    
    				if( get_field('seance_dinformations_1_date') >= $date ):
    
    				//the_field('seance_dinformations_1_date');
    				$dateformatstring = "d/m/Y";
    				$unixtimestamp = strtotime(get_field('seance_dinformations_1_date'));
    				echo date_i18n($dateformatstring, $unixtimestamp);
    
    				elseif( get_field('seance_dinformations_2_date') >= $date ):
    
    				//the_field('seance_dinformations_1_date');
    				$dateformatstring = "d/m/Y";
    				$unixtimestamp = strtotime(get_field('seance_dinformations_2_date'));
    				echo date_i18n($dateformatstring, $unixtimestamp);
    
    				elseif( get_field('seance_dinformations_3_date') >= $date ):
    
    				//the_field('seance_dinformations_1_date');
    				$dateformatstring = "d/m/Y";
    				$unixtimestamp = strtotime(get_field('seance_dinformations_3_date'));
    				echo date_i18n($dateformatstring, $unixtimestamp);
    
    				endif;
    
    			echo '</div>';
    
    			echo '<div class="clearfix"></div>';
    
    				endwhile;
    			endif; //#end  // $FC_posts->have_posts() //
    
    				wp_reset_postdata();
    
    	echo '<div class="clearfix"></div>';
    }

    FUNCTION 2

    function page_secteurs_upcoming_class_start() {
    
       // find todays date
    	$date = date('Ymd');
    	$year = date('Y');
    	// find current year (yyyy)
    	$nextyear = $year+1;
    	// find current year (yyyy)
    	$month = date('m');
    	$nextmonth = $month+1;
    
    	$beginningofyear = date($year.'0101');
    	$endofyear = date($nextyear.'0101');
    	$customDate = date('Y'.$month.'d');
    
       // args
    	$args = array(
    		'post_type'		 => 'formation-continue',
    		'post_status'    => 'publish',
    		'posts_per_page' => 3,
    		'meta_query'	 => array(
    			array(
    				'key'		=> 'debut_cours',
    				'value'		=> $date,
    				'compare'	=> '>=',
    				'type'    => 'NUMERIC',
    			),
    		),
    		'meta_key'		 => 'debut_cours',
    		'orderby'   	 => 'meta_value',
    		'order'			 => 'ASC',
    	);
    
    	// query
    	$sceances_query = new WP_Query( $args );
    
    			if( $sceances_query->have_posts() ) : while ( $sceances_query->have_posts() ) : $sceances_query->the_post();
    
                echo '<div class="vc_col-sm-5"><a href="'; the_permalink(); echo '">';
    				the_title();
    			echo '</a></div>';
    
    			echo '<div class="vc_col-sm-3">';
    				the_field('sigle_formation');
    			echo '</div>';
    
    			echo '<div class="vc_col-sm-4">';
    				//the_field('debut_cours');
    				$dateformatstring = "d/m/Y";
    				//$dateformatstring = "ymd";
    				$unixtimestamp = strtotime(get_field('debut_cours'));
    				echo date_i18n($dateformatstring, $unixtimestamp);
    			echo '</div>';
    
    			echo '<div class="clearfix"></div>';
    
    				endwhile;
    			endif; //#end  // $FC_posts->have_posts() //
    
    				wp_reset_postdata();
    
    	echo '<div class="clearfix"></div>';
    
    }

    And the page output code I am using is (this is a quick mock-up, not final version... but just to show output of code).

    <div class="wpb_wrapper">
                    <form>
                        <div class="vc_col-sm-12" style="background: #666;">
                            <div class="vc_col-sm-5">
                                <p style="color:#fff;">Séance d'informations</p>
                            </div>
    
                            <div class="vc_col-sm-4">
                                <select name="month" onchange="this.form.submit()">
                                  <option value="jan">janvier</option>
                                  <option value="feb">février</option>
                                  <option value="mar">mars</option>
                                  <option value="avr">avril</option>
                                  <option value="mai">mai</option>
                                  <option value="jun">juin</option>
                                  <option value="jul">juillet</option>
                                  <option value="aou">août</option>
                                  <option value="sep">septembre</option>
                                  <option value="oct">octobre</option>
                                  <option value="nov">novembre</option>
                                  <option value="dev">décembre</option>
                                </select>
                            </div>
    
                            <div class="vc_col-sm-3">
                                <select name="year" onchange="this.form.submit()">
                                  <option value="2016">2016</option>
                                  <option value="2017">2017</option>
                                </select>
                            </div>
    
                        </div>
                    </form>
    
                    <div class="seances" id="upcoming_seances">
                    	<?php echo page_secteurs_upcoming_sceances(); ?>
                    </div>
    
                    <br /><br />
    
                  	<form>
                        <div class="vc_col-sm-12" style="background: #666;">
                            <div class="vc_col-sm-5">
                                <p style="color:#fff;">Début des cours</p>
                            </div>
    
                            <div class="vc_col-sm-4">
                                <select name="month" onchange="this.form.submit()">
                                  <option value="jan">janvier</option>
                                  <option value="feb">février</option>
                                  <option value="mar">mars</option>
                                  <option value="avr">avril</option>
                                  <option value="mai">mai</option>
                                  <option value="jun">juin</option>
                                  <option value="jul">juillet</option>
                                  <option value="aou">août</option>
                                  <option value="sep">septembre</option>
                                  <option value="oct">octobre</option>
                                  <option value="nov">novembre</option>
                                  <option value="dev">décembre</option>
                                </select>
                            </div>
    
                            <div class="vc_col-sm-3">
                                <select name="year" onchange="this.form.submit()">
                                  <option value="2016">2016</option>
                                  <option value="2017">2017</option>
                                </select>
                            </div>
    
                        </div>
                    </form>
                    <div class="debut_cours" id="cours_debut">
                    	<?php echo page_secteurs_upcoming_class_start(); ?>
                    </div>
    
                </div>

    So what I am trying to do is to get each of the 2 functions have their own filter to execute in their respective div (using AJAX).

    I know my value"" numbers are not the correct values, I do need to make the value search between 2 numbers [for example, if Jan is selected in the drop down form then the meta_value if the custom post types should display only those where the value is ">= '20160101' and < '20160201'"].

    I hope this is more clear to get some great insight into solving this.

    Thanks,
    josh

  • Panos

    Hi josh_redler ,

    One thing that I think you might need to change is the way you are adding months:

    $month = date('m');
    $nextmonth = $month+1;

    If month is December (12), the $nextmonth could end up having value 13.

    So I would recommend to be using the date() and strtotime().

    Assuming you have the given month and year, you could try getting next month with:
    $nextmonth = date('m', strtotime('+1 month', strtotime($year . '-' . $month . '-01')));
    Haven't tested it but it should work.

    Further on:

    Of what I understand you have 2 functions
    page_secteurs_upcoming_sceances()
    and
    page_secteurs_upcoming_class_start()

    and you need each of them to output their info in the according divs with ajax, right? (hope I'm right :slight_smile: )

    My suggestion is to make the two functions accept arguments for $month and $year, eg:

    page_secteurs_upcoming_sceances( $month = '', $year = '' ){
    //DO the date actions according to $month and $year given. If they are empty you can use the current date values
    // rest of your code....
    }

    accordingly to other function.

    Then I took the liberty and changed the layout by keeping only one set of date selectors and added some js for the ajax part. All this is in a shortcode though, so you can test in any page by adding this shortcode:
    [wpmudev_custom_list]
    in any page
    and the following code in your functions.php or in a mu-plugin:

    function wpmudev_custom_list_sh(){
    
    	$cur_year = date( 'Y' );
    	$years_ahead = 4;
    	$years_list = array( $cur_year );
    	for( $y = 1 ; $y <= $years_ahead; $y++ ){
    		$years_list[] = $cur_year + $y;
    	}
    
    	?>
    	<div class="wpb_wrapper">
                    <form>
                        <div class="vc_col-sm-12" style="background: #666;">
                            <div class="vc_col-sm-4">
                                <p style="color:#fff;">Séance d'informations</p>
                            </div>
    
                            <div class="vc_col-sm-3">
                                <select class="info-month-select month-select date-select" name="month"">
                                  <option value="jan">janvier</option>
                                  <option value="feb">février</option>
                                  <option value="mar">mars</option>
                                  <option value="avr">avril</option>
                                  <option value="mai">mai</option>
                                  <option value="jun">juin</option>
                                  <option value="jul">juillet</option>
                                  <option value="aou">août</option>
                                  <option value="sep">septembre</option>
                                  <option value="oct">octobre</option>
                                  <option value="nov">novembre</option>
                                  <option value="dev">décembre</option>
                                </select>
                            </div>
    
                            <div class="vc_col-sm-3">
                                <select class="info-year-select year-select date-select" name="year">
                                  <?php foreach( $years_list as $year ): ?>
                                  <option value="<?php echo $year; ?>"><?php echo $year; ?></option>
                                  <?php endforeach; ?>
                                </select>
                            </div>
    
                            <div class="vc_col-sm-2">
                            	<a class="date-triger-button" href="#">GO</a>
                            </div>
    
                        </div>
                    </form>
    
                    <br /><br />
    
                     <div class="vc_col-sm-12">
    
                     	<div class="vc_col-sm-6">
                     		<h3>Séance d'informations</h3>
                     		<div class="seances" id="upcoming_seances"  style="background: #eee;">
    
    		                </div>
                     	</div>
    
                     	<div class="vc_col-sm-6">
                     		<h3>Séance d'informations</h3>
                     		<div class="debut_cours" id="cours_debut"  style="background: #eee;">
    
    		                </div>
    
                     	</div>
    
                     </div>
                </div>
    
                <script type="text/javascript">
                (function($){
    
                	$( document ).ready( function(){
    
                		get_info_n_course_data();
    
                	});
    
                	$( '.date-triger-button' ).on( 'click',function(e){
                		e.preventDefault();
    
                		get_info_n_course_data();
    
                	});
    
                	function get_info_n_course_data(){
    
                		var selected_month = $( '.info-month-select' ).val();
                		var selected_year = $( '.info-year-select' ).val();
    
                		var data = {
    						action: 'wpmudev_info_cours_ajax',
    						selected_month: selected_month,
    						selected_year: selected_year,
    					};
    
    					 $.ajax({
    			            url:"<?php echo admin_url( 'admin-ajax.php' ); ?>",
    			            type:"POST",
    			            data: data,
    			            dataType: "json",
    			            success: function( response ){
    			            	console.log( response );
    			            	if( response.msg == '__OK__' ){
    			            		$( '#upcoming_seances' ).html( response.upcoming_seances );
    			            		$( '#cours_debut' ).html( response.cours_debut );
    			            	}
    			            	else{
    			            		alert( 'There was an error' );
    			            	}
    			            }
    			        });
    
                	}
    
                })(jQuery)
                </script>
    	<?php
    
    }
    
    function wpmudev_info_cours_ajax_fn(){
    
    	$month = (int)$_POST['selected_month'];
    	$year = (int)$_POST['selected_year'];
    
    	$resp_upcoming_seances = 'Here call the function for upcoming_seances'; // replace with smething like: page_secteurs_upcoming_sceances( $month, $year );
    	$resp_cours_debut = 'Here call the function for cours_debut'; // also replace with page_secteurs_upcoming_class_start( $month, $year )
    
    	if( !$resp_upcoming_seances || !$resp_cours_debut ) {
    		echo json_encode( array( 'msg'=>'__ERROR__' ) );
    		exit;
    	}
    
    	$resp = array(
    		'msg' => '__OK__',
    		'upcoming_seances' => $resp_upcoming_seances,
    		'cours_debut' => $resp_cours_debut
    	);
    
    	echo json_encode( $resp );
    
    	exit;
    
    }
    
    add_shortcode( 'wpmudev_custom_list', 'wpmudev_custom_list_sh' );
    add_action('wp_ajax_wpmudev_info_cours_ajax', 'wpmudev_info_cours_ajax_fn');
    add_action('wp_ajax_nopriv_wpmudev_info_cours_ajax', 'wpmudev_info_cours_ajax_fn');

    Please make sure you replace these variables $resp_upcoming_seances and $resp_cours_debut as described in comments. You will need to fix the corresponding functions as I mentioned earlier in this post.

    Please let me know how you think of this :slight_smile:

    Thanks!
    Panos

  • josh_redler

    Hi Panos,

    Thanks for your great explanation! And ajax is the desired output here :slight_smile:

    I have read through it several times before trying it, and think there may be a slight misunderstanding on the date values for each post. Each of the dates is a custom meta_value whose saved value's format is 'yyyymmdd'. So for October 1st of this year the meta_value of the 'debut_cours' meta value for instance would be '20161001'. So for the October value in the form (for example), it need to find all posts with the meta_value 'debut_cours' >= "20161001" and < "20161101"... if that makes sense.

    The same goes for the meta_value 'seance_dinformations_1_date', 'seance_dinformations_2_date', and 'seance_dinformations_3_date'... where the post can have any of these fields filled in and I am querying by the meta_value for the order of the output.

    I added your code to my functions file and I am not getting an output of the posts (maybe I am missing something). See http://wearejack.ca/CAL/test-secteurs/ for the output example.

    The main functions stayed the same (except adding $month = '' and $year ='' to both):

    function page_secteurs_upcoming_class_start( $month = '', $year = '' )
    function page_secteurs_upcoming_sceances( $month = '', $year = '' )

    I also modified the $nextmonth variable like suggested:
    $nextmonth = date('m', strtotime('+1 month', strtotime($year . '-' . $month . '-01')));.

    As well as adding the functions to the shortcode:

    $resp_upcoming_seances = page_secteurs_upcoming_sceances( $month, $year ); // replace with smething like: page_secteurs_upcoming_sceances( $month, $year );
    $resp_cours_debut = page_secteurs_upcoming_class_start( $month, $year ); // also replace with page_secteurs_upcoming_class_start( $month, $year )

    I appreciate any help.

    Thanks,
    josh

  • Panos

    Hi Josh,

    After adding the month and year arguments to the two functions, you need to search metas by the value

    $search_for_date = $year . $month . '01'; // these are set in the args

    so the $search_for_date will have the date in the format "20161001"

    In case you still have issues please send in ftp info so I can have a closer look on this. You can send that privately through our contact form: https://premium.wpmudev.org/contact/

    Select "I have a different question?" for your topic - this and the subject line ensure that it gets assigned to me.

    Send in:Subject: "Attn: Panos Lyrakis"

    - Admin login:
    Admin username
    Admin password
    Login url

    - FTP credentials
    host
    username
    password
    (and port if required)

    - link back to this thread for reference
    - any other relevant urls

    Thanks!
    Panos

  • josh_redler

    Hi Panos,

    That is such an improvement! The axaj function on the search works great :slight_smile:

    When playing around with the filtering I do not get the proper output for each of the 2 lists (Seances d'informations and Debut de cours). As you can see in the following screenshot I seletced September 2016, clicked GO and the output does not represent the meta_value (date in this instance). For Seances d'informations, there are 3 meta_keys ( 'seance_dinformations_1_date', 'seance_dinformations_2_date', and 'seance_dinformations_3_date':wink:; and 1 meta_key for Debut de cours ( 'debut_cours':wink:, each with a date value. This is what I have ordered by in each of my original queries and this is what I want the filters to search.

    Let me know if this is not clear.

    Also, can each function (query) have its own independent filter (instead of 1 to change them both)?

    Thank you,
    josh

  • Panos

    Hi josh,

    Of what it seems there need to be some modifications in the queries of the functions in order to return the posts you want.

    The code I provided can be used as a guide, which you can use as a base to complete your custom functionality. I'm afraid that providing such custom solutions exceeds the purpose of the support forum but if you still need help you can post this project and hire a skilled developer from the jobs board!

    Kind regards!
    Panos

Thank NAME, for their help.

Let NAME know exactly why they deserved these points.

Gift a custom amount of points.