AJAX handler throws 400 (Bad request) - why? - javascript

I am trying to apply a "Load more posts" function to a post loop, but I am dealing with a 400 Bad request, when admin-ajax.php is referred to.
The reference I used is this - https://rudrastyh.com/wordpress/load-more-posts-ajax.html
Following function (in functions.php) is passing query parameters to javascript:
function wordpress_my_load_more_scripts()
{
global $wp_query;
wp_enqueue_script('jquery');
wp_register_script( 'my_loadmore', get_stylesheet_directory_uri() . '/myloadmore.js', array('jquery') );
wp_localize_script( 'my_loadmore', 'wordpress_loadmore_params', array(
'ajaxurl' => admin_url() . 'admin-ajax.php',
'posts' => json_encode( $wp_query->query_vars ),
'current_page' => get_query_var( 'paged' ) ? get_query_var('paged') : 1,
'max_page' => $wp_query->max_num_pages
) );
wp_enqueue_script( 'my_loadmore' );
}
add_action( 'wp_enqueue_scripts', 'wordpress_my_load_more_scripts' );
Parameters are passed to following jQuery script named "myloadmore.js":
jQuery(function($){
$('.wordpress_loadmore').click(function()
{
var button = $(this),
data = {
'action': 'loadmore',
'query': wordpress_loadmore_params.posts,
'page' : wordpress_loadmore_params.current_page
};
console.log(wordpress_loadmore_params.ajaxurl);
$.ajax({
url : wordpress_loadmore_params.ajaxurl, // AJAX handler
data : data,
type : 'POST',
beforeSend : function ( xhr )
{
button.text('Loading...');
},
success : function( data ){
if( data ) {
button.text( 'More posts' ).prev().before(data);
wordpress_loadmore_params.current_page++;
if ( wordpress_loadmore_params.current_page == wordpress_loadmore_params.max_page )
button.remove(); // if last page, remove the button
} else {
button.remove(); // if no data, remove the button as well
}
}
});
});
});
Following function inside functions.php is expected to provide three more posts inside while loop:
function wordpress_loadmore_ajax_handler()
{
$args = json_decode( stripslashes( $_POST['query'] ), true );
$args['paged'] = $_POST['page'] + 1;
$args['post_status'] = 'publish';
query_posts( $args );
if(have_posts() ) :
echo "We have post(s)!";
while( have_posts() ): the_post();
echo "A post!";
endwhile;
endif;
die;
}
add_action('wp_ajax_loadmore', 'wordpress_loadmore_ajax_handler');
add_action('wp_ajax_nopriv_loadmore', 'wordpress_loadmore_ajax_handler');
The post loop is this:
<ul class="products columns-3">
<?php
$query_params = array(
'post_type' => 'post',
'posts_per_page' => 3
);
$wp_query = new WP_Query( $query_params);
if( $wp_query->have_posts() ) :
while ($wp_query->have_posts()) : $wp_query->the_post(); ?>
<li class="product post-item">
<span class="post-image">
<a href="<?php the_permalink(); ?>">
<?php
if ( has_post_thumbnail())
{
the_post_thumbnail();
}
?>
</a>
</span>
<h2 class="post-title"><?php the_title(); ?></h2>
<span class="post-category"><?php the_category(', ');?></span>
</li>
<?php endwhile; ?>
<?php endif; ?>
</ul>
<nav>
<?php
global $wp_query; // you can remove this line if everything works for you
// don't display the button if there are not enough posts
if ( $wp_query->max_num_pages > 1 )
echo '
<div class="wordpress_wrapper">
<div class="wordpress_loadmore">More posts</div>
</div>'; // you can use <a> as well
?>
</nav>
<?php wp_reset_postdata(); ?>
Clicking the button to load more posts results in following message:
https://www.uvjagtpro.dk/wp-admin/admin-ajax.php
jquery.js?ver=1.12.4:4 POST https://www.uvjagtpro.dk/wp-admin/admin-ajax.php 400 ()
send # jquery.js?ver=1.12.4:4
ajax # jquery.js?ver=1.12.4:4
(anonymous) # myloadmore.js:13
dispatch # jquery.js?ver=1.12.4:3
r.handle # jquery.js?ver=1.12.4:3
Why can't I parse variable in Array named "wordpress_loadmore_params.ajaxurl" without it causing a 400 bad request?
Link to page is here - https://www.uvjagtpro.dk/arkiv/

There are only 3 cases where WordPress will return a 400 on an AJAX request to
.../wp-admin/admin-ajax.php
$_REQUEST['action'] variable is empty
has_action( 'wp_ajax_' . $_REQUEST['action'] ) is false
has_action( 'wp_ajax_nopriv_' . $_REQUEST['action'] ) is false
So, you should verify that your code
add_action('wp_ajax_loadmore', 'wordpress_loadmore_ajax_handler');
add_action('wp_ajax_nopriv_loadmore', 'wordpress_loadmore_ajax_handler');
is really executed and the query does contain a $_REQUEST['action'] with contents 'loadmore'. This is easiest to do if you know how to use a PHP debugger otherwise I would use error_log() to display relevant messages after the add_action statements. You can also display the value of the has_action() functions.
Your code looks correct to me so I think the error is not the code itself but maybe its location.

Related

Speed up admin-ajax.php request in CPT filters

I have custom post types with JS filtering (based on category). There are simple html boxes + php code with ACF fields what display after select category.
Problem is it take 1 second or more to load all this html boxes so its not so smooth.
This is my JS (file filters.js):
(function($){
$(document).ready(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', category: category },
type: 'post',
success: function(result) {
$('.js-filter').html(result);
},
error: function(result) {
console.warn(result);
}
});
});
});
})(jQuery);
This is html of box what is loaded (file content_pozice_box.php)
<a href="<?php echo get_permalink();?>"><div class="vypis_pozice">
<div class="projekt-wrapper">
<?php
$projekt = get_field('projekt');
if( get_field('projekt') == 'XXX' ) {
?>
<div class="logo-wrapper">
<img src="https://YYY.png" class="logo-wrapper-img">
</div><?php
}
if( get_field('projekt') == 'YYY' ) {
?>
<div class="logo-wrapper">
<img src="https://XXX.png" class="logo-wrapper-img">
</div>
<?php
}
?>
<div class="field_projekt"><h3><?php the_field('projekt');?></h3><div class="field_AAA">AAA:
<?php if ( get_field( 'AAA' ) ): ?>
<?php the_field('AAA');?>
<?php else: // field_name returned false ?>
dohodou
<?php endif; // end of if field_name logic ?>
</div></div>
</div>
<?php the_title('<h3>', '</h3>'); ?>
<div class="location-wrapper">
<div class="BBB"><img src="https://BBB.png"><?php the_field('BBB');?></div>
<div class="CCC"><img src="https://CCC.png"><?php the_field('CCC');?></div>
</div>
<div class="DDD"><?php $cat = get_the_category(); echo $cat[0]->cat_name; ?></div><div class="job-button">Otevřít</div>
</div></a>
PHP (loading JS, Ajax, function)
function load_scripts() {
wp_enqueue_script('ajax', get_stylesheet_directory_uri() . '/' . 'template-parts/' .'filters.js', array('jquery'), NULL, true);
wp_localize_script('ajax' , 'wp_ajax',
array('ajax_url' => admin_url('admin-ajax.php'))
);
}
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'];
$args = array(
'post_type' => 'pozice',
'posts_per_page' => -1
);
if(isset($category)) {
$args['category__in'] = array($category);
}
$query = new WP_Query($args);
if($query->have_posts()) :
while($query->have_posts()) : $query->the_post();
include("content_pozice_box.php");
endwhile;
endif;
wp_reset_postdata();
die();
}
This won't solve all your problems but the first thing you should do is reduce your database calls. get_field('projekt') is called 4 times, which runs for every iteration of your loop. Oddly, you've already set it to a variable:
$projekt = get_field('projekt');
But you're not using the variable anywhere. So try replacing that first, so that it only runs once per iteration:
if ( $projekt ) {...}
While you're at it you should always escape output for security's sake. I.E. Instead of <h3><?php the_field('projekt');?></h3> replace with <h3><?php echo esc_html( $projekt ); ?></h3>.
To find other sources of inefficiencies you might try the Query Monitor plugin, as well as your browser's dev tools. I'm not sure about your JS. It looks fine to me but perhaps someone else here will notice something.

get posts using taxonomy in wordpress

I have a wordpress app locally setup in my computer. In the wordpress admin i have a Countries tab under the Posts. I'll attach an image for better understanding.
I want to write a function to get the country values for my front-end. For that i have written a function like this
public function get_destinations()
{
$bookings = get_posts(
array(
'taxonomy'=> 'country',
'numberposts' => -1,
)
);
return $bookings;
}
But for some reason this function returns all the posts in the database. I want to get only the country names.
i found the taxonomy from my local url which is
http://localhost/my_project/wp-admin/edit-tags.php?taxonomy=country
I'm very new to wordpress and dont have a clue on how to retrieve these data to my front end. What am i doing wrong here?
If you want to show the only category or taxonomy name instead of get_posts you have to use get_terms
check this code.
// Get the taxonomy's terms
$terms = get_terms(
array(
'taxonomy' => 'country',
'hide_empty' => false, // show category even if dont have any post.
)
);
// Check if any term exists
if ( ! empty( $terms ) && is_array( $terms ) ) {
// Run a loop and print them all
foreach ( $terms as $term ) { ?>
<a href="<?php echo esc_url( get_term_link( $term ) ) ?>">
<?php echo $term->name; ?>
</a><?php
}
}

Troubleshooting Ajax Post Filter in WordPress - Not responding to WP_Query

I've created an Ajax post filter for a blog. When you click a category to filter the posts below, what happens is odd. The markup of the current page is injected rather than the results of my WP_Query arguments. So you end up with the page nested within itself.
Here's my post filter bar with the initial query populating the response div:
Here's the form:
<form action="<?php echo admin_url('admin-ajax.php'); ?>" method="POST" id="filter">
<label><input type="radio" name="category" value="" checked="checked"><div>All</div></label>
<!-- Loop Selected Categories -->
<label><input type="radio" name="category" value="Category_ID"><div>Category Name</div></label>
<!-- End Loop Selected Categories -->
<input type="submit" value="Submit">
<input type="hidden" name="action" value="myfilter">
</form>
Below is my JavaScript:
jQuery(document).ready(function($) {
$('#filter').submit(function(){
var filter = $('#filter');
$.ajax({
url:ajax_object.ajaxurl,
data:filter.serialize(), // form data
type:filter.attr('method'), // POST
success:function(data){
$('#response').html(data); // insert data
}
});
console.log('form submitted');
return false;
});
$('#filter input[type=radio]').on('change', function() {
$("#filter").submit();
});
});
Below the filter form there's a response div that contains the initial/default query results:
<div class="post-grid" id="response">
<?php
$args = array(
'posts_per_page' => 5,
'post_status' => array('publish')
);
$query = new WP_Query( $args );
if( $query->have_posts() ) :
while( $query->have_posts() ): $query->the_post();
return get_template_part( 'template-parts/content-card' );
endwhile;
wp_reset_postdata();
else :
echo 'No posts found';
endif;
?>
</div>
I have the following code to query the selected category in my functions.php:
// In my enqueued scripts
wp_enqueue_script( 'post_filter_js', get_template_directory_uri() . '/dist/js/post-filter.min.js', array('jquery'), '', true );
wp_localize_script( 'post_filter_js', 'ajax_object', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
// Function to query the selected category
add_action('wp_ajax_myfilter', 'filter_post_by_cat');
add_action('wp_ajax_nopriv_myfilter', 'filter_post_by_cat');
function filter_post_by_cat(){
// for taxonomies / categories
if( isset( $_POST['category'] ) ):
$args = array(
'category__in' => $_POST['category'],
'posts_per_page' => 5,
'post_status' => array('publish')
);
endif;
$query = new WP_Query( $args );
if( $query->have_posts() ) :
while( $query->have_posts() ): $query->the_post();
echo get_template_part( 'template-parts/content-card' );
endwhile;
wp_reset_postdata();
else :
echo 'No posts found';
endif;
die();
}

AJAX Interfering with if statement in while loop?

I am trying to load my sidebars in my while loop by using if statements that call them after a certain number of posts. It's important to note that I am using AJAX code (provided below) to load in posts on scroll and I believe it may be causing the issue.
Though they are sidebars, they are not physically a sidebar but rather content loaded between posts.
I've tried for a week to locate the problem but I cannot seem to get the sidebars to load with AJAX as a if statement in the while loop.
Important to note: The sidebar will load after the number of posts if it's not loaded through AJAX. So if it's in the initial load, the sidebars load. But when you continue to scroll to say the third or fourth bar it will not load and the AJAX will only load the (parts/content).
I need to either be able to resolve the if statement so it works within the while loop that loads through AJAX or I'm open to an alternate solution as long as it doesn't remove the AJAX.
A lot of work has been put into making this loop work and help is greatly appreciated!
front-page.php
<?php
$current_page = max( 1, get_query_var( 'paged' ) );
$the_query = new WP_Query( array(
'cat' => '-21',
'post_type' => 'post',
'posts_per_page' => 5,
'paged' => $current_page,
'tax_query' => array(
array(
'taxonomy' => 'topics',
'operator' => 'NOT EXISTS',
'field' => 'term_id',
'terms' => $term_id
)
)
) );
wp_localize_script( 'my_loadmore', 'misha_loadmore_params', array(
'ajaxurl' => admin_url( 'admin-ajax.php', 'relative' ),
'posts' => json_encode( $the_query->query_vars ),
'current_page' => $current_page,
'max_page' => $the_query->max_num_pages
) );
?>
<div id="main" class="container-fluid">
<?php if ($the_query->have_posts()) : ?>
<?php $count = 0; ?>
<?php while ($the_query->have_posts()) : $the_query->the_post(); get_template_part( 'parts/content', get_post_format() ); ?> <!-- This parts/content loads -->
<?php $count++; ?>
<!-- the dynamic_sidebar does not load -->
<?php if ($count == 2 && is_active_sidebar('sidebar1') ) : ?>
<div class="side-container first-side">
<?php dynamic_sidebar('sidebar1'); ?>
</div>
<?php endif; ?>
<?php if ($count == 10 && is_active_sidebar('sidebar2') ) : ?>
<div class="side-container first-side">
<?php dynamic_sidebar('sidebar2'); ?>
</div>
<?php endif; ?>
<?php if ($count == 20 && is_active_sidebar('sidebar3') ) : ?>
<div class="side-container third-side">
<?php dynamic_sidebar('sidebar3'); ?>
</div>
<?php endif; ?>
<?php endwhile; ?>
<?php endif; ?>
<?php wp_reset_postdata(); ?>
<?php get_footer(); ?>
</div><!-- END CONTAINER -->
parts/content -- this loads as expected including code if it's helpful
<div class="row post"> <!-- Post is mentioned in the below JS to load -->
<div class="col-sm-5">
<h2>Text</h2>
</div>
<div class="col-sm-7">
<h3>text</h3>
</div>
</div><!-- END ROW-->
sidebar code - works when initially loaded but doesn't when AJAX calls on this code such as the last two sidebars in front-page.php
<?php
$term = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) ); ?>
<?php while( $flexible_posts->have_posts() ) : $flexible_posts->the_post(); global $post; ?>
<div class="sidebar-area">
//sidebar code here
}
endwhile;
?>
myloadmore.js - AJAX Call
jQuery(function($){
var canBeLoaded = true,
bottomOffset = 2000;
$(window).scroll(function(){
if ( misha_loadmore_params.current_page >= misha_loadmore_params.max_page ) {
return;
}
var data = {
'action': 'loadmore',
'query': misha_loadmore_params.posts,
'page' : misha_loadmore_params.current_page
};
if( $(document).scrollTop() > ( $(document).height() - bottomOffset ) && canBeLoaded == true ){
$.ajax({
url : misha_loadmore_params.ajaxurl,
data: data,
type: 'POST',
beforeSend: function( xhr ){
// AJAX call is in process, we shouldn't run it again until complete
canBeLoaded = false;
},
success:function(data){
if( data ) {
$('#main').find('div.post:last-of-type').after( data ); // where to insert posts
canBeLoaded = true; // the ajax is completed, now we can run it again
misha_loadmore_params.current_page++;
bottomOffset = ( $( '#main > div.post:last' ).offset() || {} ).top
}
}
});
}
});
});
functions.php - Added for further context
function misha_my_load_more_scripts() {
wp_register_script( 'my_loadmore', get_stylesheet_directory_uri() . '/js/myloadmore.js',
array( 'jquery' ), '', true );
wp_enqueue_script( 'my_loadmore' );
}
add_action( 'wp_enqueue_scripts', 'misha_my_load_more_scripts' );
function misha_loadmore_ajax_handler() {
$args = json_decode( wp_unslash( $_POST['query'] ), true );
$args['paged'] = $_POST['page'] + 1; // load the next page
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) :
while ( $the_query->have_posts() ) : $the_query->the_post();
get_template_part( 'parts/content', get_post_format() );
endwhile;
endif;
wp_die();
}
add_action( 'wp_ajax_loadmore', 'misha_loadmore_ajax_handler' ); // Authenticated users
add_action( 'wp_ajax_nopriv_loadmore', 'misha_loadmore_ajax_handler' ); // Non-authenticated users
The trick here was to add the if statements inside of the AJAX handlers as well. Perhaps someone with AJAX experience can add to this one day to explain why it works, but all I know is that it does. All the code from my question is the same below is the difference from the functions.php ajax handler function.
function misha_loadmore_ajax_handler() {
$args = json_decode( wp_unslash( $_POST['query'] ), true );
$args['paged'] = $_POST['page'] + 1; // load the next page
$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) :
while ( $the_query->have_posts() ) : $the_query->the_post();
get_template_part( 'parts/content', get_post_format() );
<?php if ($count == 2 && is_active_sidebar('sidebar1') ) : ?>
<div class="side-container first-side">
<?php dynamic_sidebar('sidebar1'); ?>
</div>
<?php endif; ?>
<?php if ($count == 10 && is_active_sidebar('sidebar2') ) : ?>
<div class="side-container first-side">
<?php dynamic_sidebar('sidebar2'); ?>
</div>
<?php endif; ?>
<?php if ($count == 20 && is_active_sidebar('sidebar3') ) : ?>
<div class="side-container third-side">
<?php dynamic_sidebar('sidebar3'); ?>
</div>
<?php endif;
endwhile;
endif;
wp_die();
}

Deleting WordPress posts in front-end with AJAX

I am trying to remove WordPress posts from front end using AJAX.
My code removes post, but displays blank page with "success", when i want to just fade out this post without page reloading and displaying blank page.
PHP code:
<?php if( current_user_can( 'delete_post' ) ) : ?>
<?php $nonce = wp_create_nonce('my_delete_post_nonce') ?>
delete
<?php endif ?>
Functions.php code:
function my_frontend_script() {
wp_enqueue_script( 'my_script', get_template_directory_uri() . '/js/my_script.js', array( 'jquery' ), '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'my_frontend_script' );
wp_localize_script( 'js/my_script.js', 'MyAjax2', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'ajaxnonce' => wp_create_nonce('ajax-nonce') ) );
add_action( 'wp_ajax_my_delete_post', 'my_delete_post' );
function my_delete_post(){
$permission = check_ajax_referer( 'my_delete_post_nonce', 'nonce', false );
if( $permission == false ) {
echo 'error';
}
else {
wp_delete_post( $_REQUEST['id'] );
echo 'success';
}
die();
}
my_script.js code:
jQuery( document ).ready( function($) {
$(document).on( 'click', '.delete-post', function() {
var id = $(this).data('id');
var nonce = $(this).data('nonce');
var post = $(this).parents('.post:first');
$.ajax({
type: 'post',
url: MyAjax2.ajaxurl,
data: {
action: 'my_delete_post',
nonce: nonce,
id: id
},
success: function( result ) {
if( result == 'success7' ) {
post.fadeOut( function(){
post.remove();
});
}
}
})
return false;
})
})
The problem is page is reloading to a blank page with "success" text, when it should just fade out and remove post from current page, without reloading.
It looks like my_script.js is not even used at all :(
Any help much appreciated.
delete
it's reloading because it loads first the url in your href attribute, then executing your ajax-call. thats not what you want. you want to execute only the onclick. this should solve the problem. just put a # in your href
delete
or make buttons
<button data-id="<?php the_ID() ?>" data-nonce="<?php echo $nonce ?>" class="delete-post">delete</button>
edit: if it's still not working, it's because you got a typo here
if( result == 'success7' )
success7 instead of success

Categories

Resources