filter_search_pagination
5 min readDec 14, 2025
//pracPlugin.php
<?php
/*
Plugin Name: Custom Plugin
Description: Custom Plugin for filter posts by title and category, Pagination(prev, next) and Filter by Custom Field through ajax handling.
Author: SK
*/
function my_theme_enqueue_script()
{
wp_enqueue_style('bootstrap-css', 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css', array(), '5.3.2', 'all');
wp_enqueue_script('bootstrap-js', 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js', array('jquery'), '5.3.2', true);
wp_enqueue_script(
'custom-js',
plugin_dir_url(https://medium.com/__FILE__) . '/asset/js/script.js',
array('jquery'),
'1.0',
true
);
wp_enqueue_script(
'custom-css',
plugin_dir_url(https://medium.com/__FILE__) . '/asset/css/style.css',
);
wp_localize_script(
'custom-js',
'ajax_object',
array('ajax_url' => admin_url(https://medium.com/'admin-ajax.php'),)
);
wp_enqueue_script('jquery');
wp_enqueue_script(
'custom-js',
get_stylesheet_directory_uri() . '/Js/custom-script.js',
array('jquery'),
'1.0',
true
);
wp_enqueue_script(
'jquery-validate',
'https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.5/jquery.validate.min.js',
array('jquery',),
'1.19.5',
true
);
}
add_action('wp_enqueue_scripts', 'my_theme_enqueue_script');
function display_cpt_cards($atts)
{
$paged = isset($_POST['paged']) ? intval($_POST['paged']) : (get_query_var('paged') ? get_query_var('paged') : 1);
$atts = shortcode_atts(array(
'post_type' => 'movie',
'posts_per_page' => 3,
's' => '',
'cpt_cat' => '',
), $atts);
$search = !empty($atts['s']) ? sanitize_text_field($atts['s']) : '';
$category = !empty($atts['cpt_cat']) ? sanitize_text_field($atts['cpt_cat']) : '';
$args = array(
'post_type' => $atts['post_type'],
'posts_per_page' => $atts['posts_per_page'],
'post_status' => 'publish',
'paged' => $paged,
's' => $search,
);
if (!empty($category)) {
$args['tax_query'] = array(
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => $category,
),
);
}
$query = new WP_Query($args);
ob_start();
?>
<div class="movie-list-wrapper"
data-s="<?php echo esc_attr($search); ?>"
data-cpt-cat="<?php echo esc_attr($category); ?>"
data-post-type="<?php echo esc_attr($atts['post_type']); ?>"
data-posts-per-page="<?php echo esc_attr($atts['posts_per_page']); ?>">
<?php if ($query->have_posts()) : ?>
<div class="movie-grid d-flex justify-content-evenly flex-wrap">
<?php while ($query->have_posts()) : $query->the_post(); ?>
<div class="movie-card">
<?php if (has_post_thumbnail()) : ?>
<div class="movie-thumb"><?php the_post_thumbnail('medium'); ?></div>
<?php endif; ?>
<h3><?php the_title(); ?></h3>
<?php the_excerpt(); ?>
</div>
<?php endwhile; ?>
</div>
<?php
$total_pages = $query->max_num_pages;
if ($total_pages > 1) : ?>
<div class="movie-pagination" style="display:flex; align-items:center; justify-content:space-between; margin-top:20px;">
<?php if ($paged > 1) : ?>
<button class="movie-prev" data-page="<?php echo ($paged - 1); ?>">« Prev</button>
<?php else : ?>
<span></span>
<?php endif; ?>
<div class="movie-page-numbers">
<?php for ($i = 1; $i <= $total_pages; $i++) :
$active = ($i == $paged) ? 'active' : ''; ?>
<button class="movie-page-link <?php echo $active; ?>" data-page="<?php echo $i; ?>">
<?php echo $i; ?>
</button>
<?php endfor; ?>
</div>
<?php if ($paged < $total_pages) : ?>
<button class="movie-next" data-page="<?php echo ($paged + 1); ?>">Next »</button>
<?php else : ?>
<span></span>
<?php endif; ?>
</div>
<?php endif; ?>
<?php else : ?>
<div class="no-results">No movies found.</div>
<?php endif; ?>
</div>
<?php
wp_reset_postdata();
return ob_get_clean();
}
add_shortcode('cpt_cards', 'display_cpt_cards');
add_action('wp_ajax_load_movies', 'load_movies_ajax');
add_action('wp_ajax_nopriv_load_movies', 'load_movies_ajax');
function load_movies_ajax()
{
echo display_cpt_cards($_POST);
wp_die();
}
function custom_cpt_search_shortcode()
{
ob_start();
$s = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : '';
$category_slug = isset($_GET['cpt_cat']) ? sanitize_text_field($_GET['cpt_cat']) : '';
?>
<form role="search" method="get" class="custom-search-form">
<input type="search" id="s" placeholder="Search by title..." value="<?php echo esc_attr($s); ?>" name="s" />
<?php
$categories = get_terms(array('taxonomy' => 'category', 'hide_empty' => true));
if ($categories && !is_wp_error($categories)) :
?>
<select name="cpt_cat" id="cpt_cat">
<option value="">All Categories</option>
<?php foreach ($categories as $category) : ?>
<option value="<?php echo esc_attr($category->slug); ?>" <?php selected($category_slug, $category->slug); ?>>
<?php echo esc_html($category->name); ?>
</option>
<?php endforeach; ?>
</select>
<?php endif; ?>
<input type="submit" value="Search" />
<button type="button" id="clear-search">Reset</button>
</form>
<?php
return ob_get_clean();
}
add_shortcode('custom_cpt_filter', 'custom_cpt_search_shortcode');
function display_cpt_posts_with_custom_fields($atts)
{
$atts = shortcode_atts(array(
'post_type' => 'job',
'posts_per_page' => -1,
'order' => 'DESC',
'orderby' => 'date',
), $atts, 'cpt_posts_with_fields');
$today = current_time('Ymd');
$args = array(
'post_type' => $atts['post_type'],
'posts_per_page' => $atts['posts_per_page'],
'post_status' => 'publish',
'orderby' => 'meta_value',
'meta_key' => 'application_deadline',
'meta_type' => 'DATE',
'order' => 'DSC',
);
$query = new WP_Query($args);
$job_types = array();
$job_locations = array();
ob_start();
if ($query->have_posts()) :
while ($query->have_posts()) : $query->the_post();
$job_location = get_field('job_location');
$job_type = get_field('job_type');
$deadline = get_field('application_deadline');
if (!empty($job_type)) {
$job_types[$job_type] = $job_type;
}
if (!empty($job_location)) {
$job_locations[$job_location] = $job_location;
}
?>
<div class="cpt-item" <?php echo esc_attr($job_type); ?>>
<h3><?php the_title(); ?></h3>
<p>Location: <?php echo esc_html($job_location); ?></p>
<?php if ($job_type) : ?>
<p style="color:<?php echo ($job_type === 'Remote') ? 'green' : 'black'; ?>">
Job Type: <?php echo esc_html($job_type); ?>
</p>
<?php endif; ?>
<?php
if ($deadline) {
$deadline_clean = DateTime::createFromFormat('d/m/Y', $deadline)->format('Ymd');
if ($deadline_clean < $today) {
echo '<span class="job-expired">Expired</span>';
} else {
echo '<a href="javascript:void(0)" class="job-apply" style="text-decoration:none">Apply Now</a>';
}
}
?>
</div>
<?php
endwhile;
else :
echo '<p>No jobs found.</p>';
endif;
wp_reset_postdata();
$posts_html = ob_get_clean();
$job_types_dropdown = '<select id="job-type-filter">';
$job_types_dropdown .= '<option value="">Select Job Type</option>';
foreach ($job_types as $type) {
$job_types_dropdown .= '<option value="' . esc_attr($type) . '">' . esc_html($type) . '</option>';
}
$job_types_dropdown .= '</select>';
$job_locations_dropdown = '<select id="job-location-filter">';
$job_locations_dropdown .= '<option value="">Select Job Location</option>';
foreach ($job_locations as $location) {
$job_locations_dropdown .= '<option value="' . esc_attr($location) . '">' . esc_html($location) . '</option>';
}
$job_locations_dropdown .= '</select>';
$search_box='<button id ="search-btn">Search</button>';
return '<div class="filters">' . $job_types_dropdown . $job_locations_dropdown . $search_box. '</div>' .
'<div class="cpt-wrapper">' . $posts_html . '</div>';
}
add_shortcode('cpt_posts_with_fields', 'display_cpt_posts_with_custom_fields');
function filter_jobs_ajax() {
$job_type = sanitize_text_field($_POST['job_type']);
$job_location = sanitize_text_field($_POST['job_location']);
$meta_query = array('relation' => 'AND');
if (!empty($job_type)) {
$meta_query[] = array(
'key' => 'job_type',
'value' => $job_type,
'compare' => '='
);
}
if (!empty($job_location)) {
$meta_query[] = array(
'key' => 'job_location',
'value' => $job_location,
'compare' => '='
);
}
$args = array(
'post_type' => 'job',
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => $meta_query,
);
$query = new WP_Query($args);
if ($query->have_posts()) :
while ($query->have_posts()) : $query->the_post();
$job_location = get_field('job_location');
$job_type = get_field('job_type');
?>
<div class="cpt-item"
data-job-type="<?php echo esc_attr($job_type); ?>"
data-job-location="<?php echo esc_attr($job_location); ?>">
<h3><?php the_title(); ?></h3>
<p>Location: <?php echo esc_html($job_location); ?></p>
<p>Job Type: <?php echo esc_html($job_type); ?></p>
</div>
<?php
endwhile;
else :
echo '<p>No jobs found.</p>';
endif;
wp_die();
}
add_action('wp_ajax_filter_jobs', 'filter_jobs_ajax');
add_action('wp_ajax_nopriv_filter_jobs', 'filter_jobs_ajax');
assets/movie.jsGet developer_word’s stories in your inbox
Join Medium for free to get updates from this writer.
jQuery(function($){
function fetch_movies(page, search, category){
$.post(ajax_object.ajax_url, {
action: 'load_movies',
paged: page,
s: search,
cpt_cat: category
}, function(response){
if(response !== "0"){
$('.movie-list-wrapper').replaceWith(response);
}
});
}
$(document).on('click', '.movie-prev, .movie-next, .movie-page-link', function(e){
e.preventDefault();
var page = $(this).data('page');
var wrapper = $(this).closest('.movie-list-wrapper');
fetch_movies(page, wrapper.data('s'), wrapper.data('cpt-cat'));
});
$(document).on('submit', '.custom-search-form', function(e){
e.preventDefault();
var search = $(this).find('input[name="s"]').val();
var category = $(this).find('select[name="cpt_cat"]').val();
fetch_movies(1, search, category);
});
$(document).on('click', '#clear-search', function(){
$('.custom-search-form')[0].reset();
fetch_movies(1, '', '');
});
$('#search-btn').on('click', function(){
console.log('sadf');
let jobType=$('#job-type-filter').val();
console.log('Job type',jobType);
let jobLocation= $('#job-location-filter').val();
console.log('Job location',jobLocation);
$.ajax({
url:ajax_object.ajax_url,
type:'POST',
data:{
action:'filter_jobs',
job_type:jobType,
job_location:jobLocation,
},
beforeSend: function(){
$('.cpt-wrapper').text('Loading Jobs');
},
success:function(response){
$('.cpt-wrapper').html(response);
}
})
})
});
aasets/movie.css
.movie-filter-form {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.movie-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
}
.movie-card {
border: 1px solid #ddd;
padding: 10px;
border-radius: 10px;
text-align: center;
}
.movie-card img {
width: 100%;
height: 250px;
object-fit: cover;
border-radius: 10px;
}
.movie-pagination {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20px;
}
.movie-page-numbers {
display: flex;
gap: 5px;
}
.movie-page-link,
.movie-prev,
.movie-next {
padding: 6px 12px;
border: none;
border-radius: 3px;
background: #0073aa;
color: #fff;
cursor: pointer;
}
.movie-page-link.active {
background: #005177;
}
.movie-page-link:hover,
.movie-prev:hover,
.movie-next:hover {
background: #005177;
}



