I am doing filtering posts using ajax.
I wish $ array was different for pages "Products" and "Faq"
If this is executed within an ajax request, is_page() won't be set. the page you're making the request from was a previous request. you need to set something on the originating page to pass with your ajax request to let it know it's for your special case page.
functions.php
function load_scripts() {
wp_enqueue_script( 'ajax', get_template_directory_uri() . '/vendor/jquery/main.js', array( 'jquery' ), NULL, true );
wp_localize_script( 'ajax', 'wp_ajax',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'is_page' => is_page( 420 ), // Whatever you want to pass. Add as many key pairs as needed.
)
);
}
add_action( 'wp_enqueue_scripts', 'load_scripts');
add_action( 'wp_ajax_nopriv_filter', 'filter_ajax' );
add_action( 'wp_ajax_filter', 'filter_ajax' );
function filter_ajax() {
$category = $_POST['category'];
if(isset($_POST['is_page']) && $_POST['is_page'] === 'faq'){
$cat__in = 10;
print_r( $_POST );
echo "FAQ";
} else{
$cat__in = 4;
print_r( $_POST );
echo "Products";
}
$args = array(
'post_type' => 'post',
'posts_per_page' => 50,
'category__in' => $cat__in,
);
if(isset($category)) {
$args['category__in'] = array($category);
}
$query = new WP_Query($args);
if($query->have_posts()) :
while($query->have_posts()) : $query->the_post();
the_title('<h2>', '</h2>');
the_content('<p>', '</p>');
endwhile;
endif;
wp_reset_postdata();
die();
}
faq.php
<div class="js-filter">
<?php
$args = array(
'post_type' => 'post',
'posts_per_page' => 100,
'child_of' => 10,
'exclude' => array(1),
);
$query = new WP_Query(array( 'cat' => 10 ));
if($query->have_posts()) :
while($query->have_posts()) : $query->the_post();
the_title('<h2>', '</h2>');
the_content('<p>', '</p>');
endwhile;
endif;
wp_reset_postdata(); ?>
</div>
<div class="categories">
<ul>
<?php
$cat_args = array(
'exclude' => array(1),
'child_of' => 10
);
?>
<?php
global $post;
$category = reset(get_the_category($post->ID));
$category_id = $category->cat_ID;
?>
<li class="js-filter-item">All</li>
<?php $categories = get_categories($cat_args); foreach($categories as $cat) : ?>
<li class="js-filter-item"><a data-category="<?= $cat->term_id; ?>" href="<?= get_category_link($cat->term_id); ?>"><?= $cat->name; ?></a></li>
<?php endforeach; ?>
</ul>
</div>
products.php
<div class="js-filter">
<?php
$args = array(
'post_type' => 'post',
'posts_per_page' => 100,
'child_of' => 6,
'exclude' => array(1,10),
);
$query = new WP_Query(array( 'cat' => 6 ));
if($query->have_posts()) :
while($query->have_posts()) : $query->the_post();
the_title('<h2>', '</h2>');
the_content('<p>', '</p>');
endwhile;
endif;
wp_reset_postdata(); ?>
</div>
<div class="categories">
<ul>
<?php
$cat_args = array(
'exclude' => array(1,10),
'child_of' => 6
);
?>
<?php
global $post;
$category = reset(get_the_category($post->ID));
$category_id = $category->cat_ID;
?>
<li class="js-filter-item">All</li>
<?php $categories = get_categories($cat_args); foreach($categories as $cat) : ?>
<li class="js-filter-item"><a data-category="<?= $cat->term_id; ?>" href="<?= get_category_link($cat->term_id); ?>"><?= $cat->name; ?></a></li>
<?php endforeach; ?>
</ul>
</div>
main.js
jQuery(function($){
$(document).on('click', '.js-filter-item > a', function(e){
e.preventDefault();
var category = $(this).data('category');
$.ajax({
url: wp_ajax.ajax_url,
data: {
action: 'filter',
is_page: wp_ajax.is_page, // This param will be passed to your ajax function.
category: category,
pageslug: location.pathname.replace(/\//g,'')
},
type: 'post',
success: function(result) {
$('.js-filter').html(result);
},
error: function(result) {
console.warn(result);
}
});
});
});
do you have any idea how to solve it? After clicking on the "All" button, it displays posts from the "ID = 6" category
You can pass your parameter by using the localize script feature. Since the page isn't passed to your ajax function, you need to set your params in localize script, then pass to your ajax as part of the localized array.
function load_scripts() {
wp_enqueue_script( 'ajax', get_template_directory_uri() . '/vendor/jquery/main.js', array( 'jquery' ), NULL, true );
wp_localize_script( 'ajax', 'wp_ajax',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'is_page' => is_page( 420 ), // Whatever you want to pass. Add as many key pairs as needed.
)
);
}
add_action( 'wp_enqueue_scripts', 'load_scripts');
In the case above, is_page is either true or false, and will pass to your javascript via the localized script. So in the JS file, wp_ajax.is_page will be either true or false (you can view this by inspecting your js object on the page. It should be a 0 or a 1.
If you wanted to pass other objects, you can create as many items to your array and then pass to your js template.
Your AJAX:
jQuery(function($){
$(document).on('click', '.js-filter-item > a', function(e){
e.preventDefault();
var category = $(this).data('category');
$.ajax({
url: wp_ajax.ajax_url,
data: {
action: 'filter',
is_page: wp_ajax.is_page, // This param will be passed to your ajax function.
category: category,
pageslug: location.pathname.replace(/\//g,'')
},
type: 'post',
success: function(result) {
$('.js-filter').html(result);
},
error: function(result) {
console.warn(result);
}
});
});
});
Then in your updated php ajax action.
function filter_ajax() {
$category = $_POST['category'];
// If it's page 420... then $_POST['is_page'] will equal a string 1.
if ( isset( $_POST['is_page'] ) && $_POST['is_page'] === '1' ) {
$cat__in = 10;
print_r( $_POST );
echo "FAQ";
} else {
$cat__in = 4;
print_r( $_POST );
echo "Products";
}
// .... rest of function
}
is_page() is not supposed to work in wp_ajax_ functions.
Check this answer: Why doesn't is_page(id) work in functions.php?
is_page() relies on a complete global $wp_query object. If you call it before the action template_redirect has been fired, it might be impossible to get that data.
Instead of using is_page(), you can pass the slug as ajax data array value.
To pass as slug, edit main.js to replace
data: { action: 'filter', category: category },
with
data: {
action: 'filter',
category: category,
pageslug: location.pathname.replace(/\//g,'')
},
Then, in functions.php in filter_ajax() function, replace
if (is_page('faq'))
with
if(isset($_POST['pageslug']) && $_POST['pageslug'] === 'faq')
Related
Edited for Clarity:
I'm using the misha_filter_function from: https://rudrastyh.com/wordpress/ajax-post-filters.html to filter posts.
The initial array is displaying the correct posts by the location_and_season (made with ACF) tag. But something weird is going on with the second array because when I click my dropdown select to sort the posts by category it's filtering all of the posts within the post type, and effectively ignoring 'tag' => $value,
I'm relatively new to Wordpress PHP and JS, so my Google-Fu hasn't been too helpful since I don't really know what to search. Any help would be appreciated. Thanks!
Here's the filter Code:
<?php
add_action('wp_ajax_myfilter', 'misha_filter_function'); //
wp_ajax_{ACTION HERE}
add_action('wp_ajax_nopriv_myfilter', 'misha_filter_function');
function misha_filter_function()
{
$value = get_field('location_and_season');
$args = array(
'post_type' => 'shows',
'tag' => $value,
'posts_per_page' => - 1, // show all posts.
'orderby' => 'name', // we will sort posts by name
'order' => 'ASC'
//$_POST['name'] // ASC or DESC
);
// for taxonomies / categories
// IMPORTANT! Adding && !empty( $_POST['categoryfilter'] ) fixes the no posts found for All Categories
if (isset($_POST['categoryfilter']) &&
!empty($_POST['categoryfilter'])) $args['tax_query'] = array(
array(
'taxonomy' => 'category',
'field' => 'id',
'terms' => $_POST['categoryfilter']
)
);
$query = new WP_Query($args);
// The Query
query_posts($args);
// The Loop
while (have_posts()):
the_post(); ?>
Here's the front end dropdown code:
<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php"
method="POST" id="filter" style="float:right; margin-right: 15px;">
<?php
if ($terms = get_terms(array(
'taxonomy' => 'category',
'orderby' => 'name'
))):
echo '<select name="categoryfilter"><option id="refresh" value="all"
class="dropdown-select">All Topics...</option>';
foreach ($terms as $term):
echo '<option value="' . $term->term_id . '">' . $term->name .
'</option>';
endforeach;
echo '</select>';
endif;
?>
<div class="processing" style="height:30px;"></div>
<input type="hidden" name="action" value="myfilter">
</form>
And the JS
jQuery(function ($) {
$('#filter').change(function () {
var filter = $('#filter');
$.ajax({
url: filter.attr('action'),
data: filter.serialize(), // form data
type: filter.attr('method'), // POST
beforeSend: function (xhr) {
filter.find('.processing').html('<img src="spinner.gif" class="spinner">'); // changing the button label
},
success: function (data) {
filter.find('.processing').text(''); // changing the button label back
$('#response').html(data); // insert data
}
});
$(document).ready(function () {
$('#filter').on("click", function () {
$('.post-section').toggleClass("active");
});
});
return false;
});
I don't see anything that actually calls your php function. Wordpress ajax calls require an action in the data.
$.ajax({
url: filter.attr('action'),
type: filter.attr('method'), // POST
data: {
action: 'misha_filter_function',
categoryfilter: $(select['name ="categoryfilter"]').val()
},
beforeSend: function (xhr) {
filter.find('.processing').html('<img src="spinner.gif" class="spinner">'); // changing the button label
},
success: function (data) {
filter.find('.processing').text(''); // changing the button label back
$('#response').html(data); // insert data
},
failure: function(response){
console.log(response); //Debug only
}
});
Also, do you enqueue the js script with wp_localize_script?
I'm trying to create a load more button that loads more custom post types on click, however, I keep receiving a 400 (Bad Request) error. Here is the code i'm using.
// Header.php
<!doctype html>
<html <?php language_attributes(); class="no-js">
<head>
<!-- meta tags & links --->
<script type="text/javascript">
ajaxurl = <?php echo admin_url('admin-ajax.php'); ?>;
// HTML:
<div class="project">
<?php
$posts_array = array(
'post_type' => 'project',
'status' => 'publish',
'order' => 'ASC',
'posts_per_page' => -1,
'paged' => $paged
);
$posts = get_posts($posts_array);
$count = 0;
?>
<?php foreach ($posts as $post) : $count++; ?>
<div class="project">
<php echo the_title(); ?>
</div>
<?php endforeach; wp_reset_query(); ?>
</div>
<button id="more_posts">Load More</button>
// JavaScript:
$("#more_posts").on("click", function() {
// When btn is pressed.
$.ajax({
url: ajaxurl,
action: "more_post_ajax",
offset: page * ppp + 1,
ppp: ppp
}).success(function(posts) {
page++;
$(".projects").append(posts);
});
});
// Functions.php
function more_post_ajax(){
$offset = $_POST["offset"];
$ppp = $_POST["ppp"];
header("Content-Type: text/html");
$args = array(
'post_type' => 'project',
'status' => 'publish',
'posts_per_page' => $ppp,
'order' => 'ASC',
'offset' => $offset,
);
$loop = new WP_Query($args);
while ($loop->have_posts()) { $loop->the_post();
the_title();
}
exit;
}
add_action('wp_ajax_nopriv_more_post_ajax', 'more_post_ajax');
add_action('wp_ajax_more_post_ajax', 'more_post_ajax');
There is a good amount here to fix.
Your Ajax is syntax is off a bit. Also, you can specify posts per page for the return with PHP, so you don't need to send that, you can keep your page attribute on the frontend.
$("#more_posts").on("click", function(e) {
$.ajax({
// use the ajax object url
url: ajax_object.ajax_url,
data: {
action: "more_post_ajax", // add your action to the data object
offset: page * 4 // page # x your default posts per page
},
success: function(data) {
// add the posts to the container and add to your page count
page++;
$('.projects').append(data);
},
error: function(data) {
// test to see what you get back on error
console.log(data);
}
});
});
For your initial PHP function, you should only specify the amount of posts you want to show at first. If you use -1 it will just show all posts at the start, which you don't want. You also don't need to use the paged parameter. You only need offsets.
<?php
$args = array(
'post_type' => 'project',
'status' => 'publish',
'order' => 'ASC',
'posts_per_page' => 4,
);
$posts = new WP_Query($args);
?>
<div class="projects">
<?php
while ($posts->have_posts()) {
$posts->the_post(); ?>
<div class="project">
<?php the_title(); ?>
</div>
<?php
wp_reset_postdata();
}; ?>
</div>
For your more posts function, you only need to specify an offset, and can add your additional posts right in that function.
function more_post_ajax(){
$offset = $_POST["offset"];
$args = array(
'post_type' => 'project',
'status' => 'publish',
'posts_per_page' => 4,
'order' => 'ASC',
'offset' => $offset,
);
$post = new WP_Query($args);
while ($post->have_posts()) { $post->the_post();
<div class="project">the_title();</div>
}
wp_reset_postdata();
die(); // use die instead of exit
}
add_action('wp_ajax_nopriv_more_post_ajax', 'more_post_ajax');
add_action('wp_ajax_more_post_ajax', 'more_post_ajax');
I have not tested this, but this should get you closer to a working set.
Just in case anyone is looking at this in the future and aren't sure on why they can't make it work theres a couple of things that need changing in the above code for starters in the js you need to define the variable page before the on click function...
var page = 1;
$("#more_posts").on("click", function(e) {
$.ajax({
// use the ajax object url
url: ajax_object.ajax_url,
data: {
action: "more_post_ajax", // add your action to the data object
offset: page * 4 // page # x your default posts per page
},
success: function(data) {
// add the posts to the container and add to your page count
page++;
$('.projects').append(data);
},
error: function(data) {
// test to see what you get back on error
console.log(data);
}
});
});
This code appends the data to the admin-ajax url which means you have to use $_GET not $_POST to retrieve the offset variable in your php function:
$offset = $_GET["offset"];
I'm trying to load post with ajax using a variable to get posts by year. I've found this great tutorial https://www.creare.co.uk/blog/simple-wp_query-ajax and I'm trying to modify it to my needs but I have 0 experience with Ajax and not so much with jquery...
this is my modified code but the year is not passed and I don't know how to do it, I appreciate any help
js
//If input is changed, load posts
$('#genre-filter input').live('change', function(){
genre_get_posts(); //Load Posts
});
//Find Selected Genres
function getSelectedGenres()
{
var genres = [];
$("#genre-filter div").click(function() {
var genres = $(this).attr('value');
console.log(genres);
});
return genres;
}
//Main ajax function
function genre_get_posts(paged)
{
var ajax_url = ajax_genre_params.ajax_url;
$.ajax({
type: 'GET',
url: ajax_url,
data: {
action: 'genre_filter',
genres: getSelectedGenres,
},
beforeSend: function ()
{
//Show loader here
},
success: function(data)
{
//Hide loader here
$('#genre-results').html(data);
},
error: function()
{
$("#genre-results").html('<p>There has been an error</p>');
}
});
}
template
<section id="primary" class="content-area">
<div id="content" class="site-content" role="main">
<?php
if ( have_posts() ):
while ( have_posts() ): the_post();
get_template_part( 'content' );
endwhile;
endif;
?>
<div class="entry-content">
<div id="genre-filter">
<div id="2018" value="2018" name="filter_genre[]">2018</div>
<div id="2017" value="2017" name="filter_genre[]">2017</div>
</div>
<div id="genre-results"></div>
</div>
</div>
functions.php
function ajax_genre_filter() {
$query_data = $_GET;
$genre_terms = ( $query_data[ 'genres' ] ) ? explode( ',', $query_data[ 'genres' ] ) : false;
$book_args = array(
'post_type' => 'book',
'posts_per_page' => 2,
'year' => $genre_terms,
);
$book_loop = new WP_Query( $book_args );
if ( $book_loop->have_posts() ):
while ( $book_loop->have_posts() ): $book_loop->the_post();
get_template_part( 'content' );
endwhile;
echo $query_data;
else :
get_template_part( 'content-none' );
endif;
wp_reset_postdata();
die();
}
Your first issue is variable scoping in getSelectedGenres. I would imaging you're always getting an empty array due to the 2nd var in your event handler. Try the modified version below.
function getSelectedGenres()
{
var genres = [];
$("#genre-filter div").click(function() {
var g = $(this).attr('value');
genres.push(g);
console.log(g);
});
return genres;
}
Additionally, it looks like ajax_genre_filter reads the year from the genres query string genres based on the mapping 'year' => $genre_terms so try including the selected year in your function getSelectedGenres.
Here is HTML Nav:
<ul class="sub-menu side-nav page-sidebar child-pages">
<li class="menu-item menu-item-type-post_type menu-item-object-post menu-item-9045" data-id="105"><span class="menu-image-title">History</span></li>
<li class="menu-item menu-item-type-post_type menu-item-object-post menu-item-9046" data-id="185"><span class="menu-image-title">Strategic Plan</span></li>
<li class="menu-item menu-item-type-post_type menu-item-object-post menu-item-9047" data-id="183"><span class="menu-image-title">Financial Statements</span></li>
</ul>
Here is my PHP function:
add_action ( 'wp_ajax_nopriv_load-content', 'my_load_ajax_content' );
add_action ( 'wp_ajax_load-content', 'my_load_ajax_content' );
function my_load_ajax_content(){
$post_id = $_POST[ 'post_id' ];
$post = get_post( $post_id, OBJECT);
$response = array( apply_filters( 'the_content', $post->post_title ), apply_filters( 'the_content', $post->post_content ) );
echo '<div class="entry-header"><h1 class="entry-title">'.$response[0].'</h1></div><div class="entry-content">'.$response[1].'</div>';
die(1);
}
wp_enqueue_script( 'my-ajax-request', get_template_directory_uri() . '/js/ajax.js', array( 'jquery' ) );
wp_localize_script( 'my-ajax-request', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
Here's what's in ajax.js:
jQuery(document).ready(function($) {
$(window).on('load',Foundation.utils.throttle(function(e){
if($('.current-menu-item > .sub-menu')){
$('#sidebar-b').append($('.current-menu-item > .sub-menu').addClass('side-nav page-sidebar child-pages'));
$("#sidebar-b .menu-item a:not(.pdf)").each(function(){
var link_text = $(this).children('.menu-image-title').html();
$(this).attr('href','#'+link_text);
});
}
},300));
$("#sidebar-b .menu-item .menu-image-title-after").click(function(e) {
$("#loading-animation").show();
var post_id = $(this).parent("li").attr("data-id");
var ajaxURL = MyAjax.ajaxurl;
$.ajax({
type: 'POST',
url: ajaxURL,
data: {"action":"load-content",post_id:post_id},
success: function(response){
$("#content > article").html(response);
$("#loading-animation").hide();
return false;
}
});
});
});
Additionally, when checking the <head> I noticed that my ajax.js script is not even loading even though it's being enqueued in my PHP function. Any ideas on what I'm doing wrong? I've scoured Google for the last 3 hours and haven't found an exact answer.
1, you have to make sure that your script is triggered at the right element
2, you should change : "action":"load-content" to action: 'load-content' ( remove the double quote at action )
You need to enqueue the scripts by using below mentioned way, then it will be hooked with wp_enqueue_scripts hook and load properly :
function load_scripts() {
wp_enqueue_script( 'my-ajax-request', get_template_directory_uri() . '/js/ajax.js', array( 'jquery' ) );
wp_localize_script( 'my-ajax-request', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
}
add_action( 'wp_enqueue_scripts', 'load_scripts' );
Hope it helps you.
Ultimately, after days and days of trial and error, I FINALLY got AJAX working! The secret was making my ajax.js an anonymous function.
(function($){
$(document).on('click','.ajax-click',function(e){
e.preventDefault();
var post_id = $(this).parent().attr('data-id');
var ajaxURL = MyAjax.ajaxurl;
$.ajax({
cache: false,
type: "POST",
url: ajaxURL,
data:{ action: "load_content", post_id: post_id },
beforeSend: function(){
$("#loading-animation").show();
$("#content > article").fadeOut();
},
success: function(response){
$("#content > article").html(response).fadeIn();
$("#loading-animation").hide();
return false;
}
});
});
})(jQuery);
I kept everything in my ajaxify.php file as follows:
add_action ( 'wp_ajax_nopriv_load_content', 'my_ajax_load_content', 99 );
add_action ( 'wp_ajax_load_content', 'my_ajax_load_content', 99 );
function my_ajax_load_content(){
$post_id = $_POST[ 'post_id' ];
$post = get_post( $post_id );
$response = array( apply_filters( 'the_content', $post->post_title ), apply_filters( 'the_content', $post->post_content ) );
echo '<div class="entry-header"><h1 class="entry-title">'.$response[0].'</h1></div><div class="entry-content">'.$response[1].'</div>';
die(0);
}
wp_enqueue_script( 'my-ajax-request', get_template_directory_uri() . '/js/ajax.js', array( 'jquery' ) );
wp_localize_script( 'my-ajax-request', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
Quick reminder: Your action in PHP MUST match your action inside you jQuery. In my case it was load_content (e.g. wp_ajax_nopriv_load_content, wp_ajax_load_content, data:{ action: "load_content" }).
Hopefully this helps someone going through a similar issue with WordPress AJAX.
I am planning to create a menu to sort my products dynamically. Each time a sorting method is selected (i.e. by price) I want to refresh the products and have an ajax call load in a new WP_Query.
I am successful so far at loading the products via a button which triggers an AJAX call, but my problem is that once the products load there are some issues with their normal functionality.
The products are variables, and usually when you have selected which variable options you like a price will be outputted. This no longer happens and I'm wondering how I can refresh the variable product's JS so that it works.
Here is what my functions.php look like.
//Enqueue Ajax Scripts
function enqueue_product_show_ajax() {
wp_register_script( 'product-show-ajax-js', get_template_directory_uri() . '/js/product-show-ajax.js', array( 'jquery' ), '', true );
wp_localize_script( 'product-show-ajax-js', 'product_show_ajax', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
wp_enqueue_script( 'product-show-ajax-js' );
}
add_action('wp_enqueue_scripts', 'enqueue_product_show_ajax');
function ajax_show_product() {
$args = array(
'post_type' => 'product',
'posts_per_page' => 12,
// Indicate the product category - in this case "Training"
'product_cat' => 'training',
'orderby' => '_price',
'order' => 'desc'
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post(); ?>
<div class="product-node">
<?php wc_get_template_part( 'content', 'single-product' ); ?>
</div>
<?php endwhile;
}
wp_reset_postdata();
die();
}
//Add Ajax Actions
add_action('wp_ajax_show_product', 'ajax_show_product');
add_action('wp_ajax_nopriv_show_product', 'ajax_show_product');
Here is my AJAX call in my product-show-ajax.js
$('.ajax').on('click', function(){
show_products();
});
//Main ajax function
function show_products() {
$.ajax({
type: 'GET',
url: product_show_ajax.ajax_url,
data: {
action: 'show_product',
},
beforeSend: function ()
{
//Eventually show a loader here
},
success: function(data)
{
//Eventually hide loader here
$( '.product-container' ).html(data);;
},
error: function()
{
//If an ajax error has occured, do something here...
$(".product-container").html('<p>There has been an error</p>');
}
});
}
So to recap, my problem is that WooCommerce specific JS to do with variable products isn't running, I'm guessing because it's loaded before the products and so when the ajax function shows the products the JS that was loaded for them hasn't binded to any of the elements.
How can I make sure WooCommerce specific JS is reloaded once my product loads?
Thanks All!