How to Add Custom Filters like Date Range in Posts List Admin Area
Almost every part of the WordPress core can be modified using hooks. They can be added to your plugin or a theme and can be used to change how WordPress displays data. If you are new to hooks, here is a whole article about them explaining how they interact with WordPress. We’ll use hooks as well to modify the posts list in the admin area. We suggest adding this functionality to a plugin.
Table of Contents
Almost every part of the WordPress core can be modified using hooks. They can be added to your plugin or a theme and can be used to change how WordPress displays data. If you are new to hooks, here is a whole article about them explaining how they interact with WordPress. We’ll use hooks as well to modify the posts list in the admin area. We suggest adding this functionality to a plugin.
Let’s get started.
Hooks we need
- restrict_manage_posts
- pre_get_posts
- admin_enqueue_scripts
We’ll use the restrict_manage_posts to create the field for filtering. The second hook we’ll be used for filtering the posts, and the third one we’ll be used to include the jquery-ui-datepicker script because it is not automatically included in the admin area.
If successful, the posts list should look something like this:
The code
In your main plugin or a theme file add these hooks (it is up to you how you would like to structure your plugin):
<?php
add_action( 'restrict_manage_posts', 'form_select' );
add_action( 'pre_get_posts', 'query_filter' );
add_action( 'admin_enqueue_scripts', 'jqueryui' );
Create a function (or a method if you are using a class) for each callback:
<?php
function form_select() {
$post_type = (isset($_GET['post_type'])) ? $_GET['post_type'] : 'post';
if ($post_type == 'post') {
// please use unique name
$from = ( isset( $_GET['pe_date'] ) && $_GET['pe_date'] ) ? $_GET['pe_date'] : '';
echo '<input type="text" name="pe_date" placeholder="Date From" value="' . esc_attr( $from ) . '" />
<script>
jQuery( function($) {
let from = $(\'input[name="pe_date"]\');
// the dates look like this "April 3, 2017" by default
// you can schoose something different, for example
from.datepicker( {dateFormat : "yy-mm-dd"} );
});
</script>';
} // end if
}
You can include the filter in any post type you want.
function query_filter( $admin_query ) {
global $pagenow;
$post_type = (isset($_GET['post_type'])) ? $_GET['post_type'] : 'post';
if ( $post_type == 'post' && $pagenow == 'edit.php' && isset( $_GET['pe_date'] ) && !empty( $_GET['pe_date'] ) ) {
$admin_query->set(
'date_query', // date_query appeared in WordPress 3.7!
array(
'after' => sanitize_text_field( $_GET['pe_date'] ),
'before' => sanitize_text_field( $_GET['pe_date'] ),
'inclusive' => true, // include the selected days as well
'column' => 'post_date' // 'post_modified', 'post_date_gmt', 'post_modified_gmt'
)
);
}
return $admin_query;
}
Do the filtering by date only if the custom post type is post, if we are on the edit page, and if the pe_date field is not empty.
<?php
function jqueryui () {
wp_enqueue_style( 'pe-jquery-ui', '//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.min.css' );
wp_enqueue_script( 'jquery-ui-datepicker' );
}
Include the script and the styling for the datepicker.
This is it. Now, let’s make things more interesting and add another filter that will display the posts by status.
Tweak the form_select function like this:
function form_select() {
$post_type = ( isset($_GET['post_type']) ) ? $_GET['post_type'] : 'post';
if ($post_type == 'post') {
// please use unique name
$from = ( isset( $_GET['pe_date'] ) && $_GET['pe_date'] ) ? $_GET['pe_date'] : '';
$current_status = $_GET['pe_status'] ?? '';
$statuses = get_post_statuses();
echo '<input type="text" name="pe_date" placeholder="Date From" value="' . esc_attr( $from ) . '" />';
?>
<select name="pe_status">
<option value=""><?= __('All statuses', 'projectsengine'); ?></option>
<?php
foreach ($statuses as $key => $status) {
printf(
'<option value="%s"%s>%s</option>',
$key,
$key == $current_status ? ' selected="selected"' : '',
$status
);
}
?>
</select>
<?php
echo '<script>
jQuery( function($) {
let from = $(\'input[name="pe_date"]\');
// the dates look like this "April 3, 2017" by default
// you can schoose something different, for example
from.datepicker( {dateFormat : "yy/mm/dd"} );
});
</script>';
}
}
get_post_statuses() will return all of the statuses that are currently registered on your website. Add them as options to a select field.
Tweak the query_filter function like this:
function query_filter( $admin_query ) {
global $pagenow;
$post_type = (isset($_GET['post_type'])) ? $_GET['post_type'] : 'post';
if ( $post_type == 'post' && $pagenow == 'edit.php' ) {
if ( isset( $_GET['pe_status'] ) && ! empty( $_GET['pe_status'] ) ) {
$admin_query->set('post_status', $_GET['pe_status'] );
}
if ( isset( $_GET['pe_date'] ) && ! empty( $_GET['pe_date'] ) ) {
$admin_query->set(
'date_query', // date_query appeared in WordPress 3.7!
array(
'after' => sanitize_text_field( $_GET['pe_date'] ),
'before' => sanitize_text_field( $_GET['pe_date'] ),
'inclusive' => true, // include the selected days as well
'column' => 'post_date' // 'post_modified', 'post_date_gmt', 'post_modified_gmt'
)
);
}
}
return $admin_query;
}
We’ll modify the posts query only if the fields/filters are not empty.
Comments
At the moment, there are 2 comments for this post.