0

I have two different AJAX load more functions in my website. One for my archive page, the second for the taxonomy page.

The issue is, there is a conflict when both AJAX handler functions are in my functions.php. When there is only one handler function, the latter works fine.

The JS code for both AJAX action:

/*
 * AJAX Load More for archive page
 */
 $('.load-more-archive').click(function(){
  var button = $(this),
    data = {
    'action': handler,
    'query': posts_myajax,
    'page' : current_page_myajax
  };

  $.ajax({
    url : '../wp-admin/admin-ajax.php', // AJAX handler
    data : data,
    type : 'POST',
    beforeSend : function ( xhr ) {
      button.hide();
    },
    success : function( data ){
      if( data ) {
        $('.wrapper-archive').append(data);

        button.show();

        current_page_myajax++;

        if ( current_page_myajax == max_page_myajax )
          button.remove();
      } else {
        //button.remove();
      }
    }
  });
});

/*
 * AJAX Load More for taxonomy page
 */
 $('.load-more-tax').click(function(){
  var button = $(this),
    data = {
    'action': handler,
    'tax_post_type': current_post_type,
    'tax_term': tax_term_id,
    'query': posts_myajax,
    'page' : current_page_myajax,
  };

  $.ajax({
    url : '../wp-admin/admin-ajax.php',
    data : data,
    type : 'POST',
    beforeSend : function ( xhr ) {
      button.hide();
    },
    success : function( data ){
      if( data ) {
        $('.wrapper-taxonomy').append(data);

        button.show();

        current_page_myajax++;

        if ( current_page_myajax == max_page_myajax )
          button.remove();
      } else {
        //button.remove();
      }
    }
  });
});

Here is PHP code of both AJAX handler:

/**
 * AJAX handler for archive page
 */
function archive_loadmore_ajax_handler(){

    $args = json_decode( stripslashes( $_POST['query'] ), true );
    $args['paged'] = $_POST['page'] + 1;
    $args['post_type'] = $_POST['action'];
    $args['posts_per_page'] = 4;

    $the_query = new WP_Query( $args );

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

        get_template_part( 'template-parts/content', 'cpt-archive' );

    endwhile;

    endif;
    die;
}
add_action('wp_ajax_'. $_POST['action'] .'', 'archive_loadmore_ajax_handler');
add_action('wp_ajax_nopriv_'. $_POST['action'] .'', 'archive_loadmore_ajax_handler');



/**
 * AJAX handler for taxonomy page
 */
function taxonomy_loadmore_ajax_handler(){

    $args = json_decode( stripslashes( $_POST['query'] ), true );
    $args['paged'] = $_POST['page'] + 1;
    $args['post_type'] = $_POST['tax_post_type'];
    $args['posts_per_page'] = 4;
    $args['tax_query'] = array(
        array (
            'taxonomy' => $_POST['action'],
            'field' => 'id',
            'terms' => $_POST['tax_term']
        )
    );

    $the_query = new WP_Query( $args );

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

        get_template_part( 'template-parts/content', 'cpt-archive' );

    endwhile;

    endif;
    die;
}
add_action('wp_ajax_'. $_POST['action'] .'', 'taxonomy_loadmore_ajax_handler');
add_action('wp_ajax_nopriv_'. $_POST['action'] .'', 'taxonomy_loadmore_ajax_handler');

I understand that there is a conflict when calling the AJAX script, but I don't find the way how to solve it. Any help would be much appreciated. Thank you!

EDIT

I updated the PHP AJAX and JS AJAX following the recommendations:

The JS

$('.load-more-archive').click(function(){
 var button = $(this),
   data = {
   'action': 'load_archive',
   'my_post_type': current_post_type,
   'query': posts_myajax,
   'page' : current_page_myajax
 };

 $.ajax({
   url : 'http://localhost:8888/sites/mysite/wp-admin/admin-ajax.php',
   data : data,
   type : 'POST',
   beforeSend : function ( xhr ) {
     button.hide();
   },
   success : function( data ){
     if( data ) {
       $('.wrapper-archive').append(data);

       isLoaded();

       button.show(); // Insert new posts

       current_page_myajax++;

       if ( current_page_myajax == max_page_myajax )
         button.remove();
     } else {
       //button.remove();
     }
   }
 });
});

THE PHP

function mysite_archive_loadmore_ajax_handler(){

    $args = json_decode( stripslashes( $_POST['query'] ), true );
    $args['paged'] = $_POST['page'] + 1;
    $args['post_type'] = $_POST['my_post_type']; 
    $args['posts_per_page'] = 4;

    $the_query = new WP_Query( $args );

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

        get_template_part( 'template-parts/content', 'cpt-archive' );

    endwhile;

    endif;
    die;
}
add_action('wp_ajax_load_archive', 'mysite_archive_loadmore_ajax_handler'); 
add_action('wp_ajax_nopriv_load_archive', 'mysite_archive_loadmore_ajax_handler'); 
8
  • You shouldn't be allowing POST variables into the action names, your AJAX handlers will run on all AJAX requests, you need to whitelist/hardcode, and there's probably security consequences of what has been done here
    – Tom J Nowell
    Jul 16, 2021 at 10:52
  • I understand it's not the best way but I need the PHP function to be dynamic when the AJAX handler is related to its custom post type. I'm aware if you have a better solution to that. Jul 16, 2021 at 10:55
  • Also, allowing anybody to pass in WP_Query arguments like that is an effective way to expose private information, or trigger resource exhaustion attacks, these AJAX handlers are very insecure. I also see you're reusing the action as the post type, do not do that. Also don't use relative paths for admin-ajax.php. Have you considered using the REST API instead for fetching the data?
    – Tom J Nowell
    Jul 16, 2021 at 10:55
  • It's not a case of best practice, this way is insecure and dangerous. An AJAX handler that allows arbitrary query parameters and arbitrary action names is wildly insecure. If you have this handler on a production site you should remove it immediately before there is a data breach. At the very least, use prefixes for the action names
    – Tom J Nowell
    Jul 16, 2021 at 10:58
  • The website is in local development. I'm a newbie in PHP and AJAX. I see there are a lot of issues but my level skills is not enough on how to resolve them. I don't use 'post_type' because I have 5 different post types using the AJAX load more function. That's for why I tried to make it bit more dynamic and not duplicate the code 5 times. Jul 16, 2021 at 11:02

1 Answer 1

0

The use of $_POST['action'] in the WP_Query and as a dynamic action name is dangerous, and in the code triggers the handler on all AJAX requests even those you don't want. This is unavoidable and a dead end that cannot be fixed. Alternatives are mandatory.

Instead, use a static non-dynamic action name, E.g. mathieu_loadmode_post_archive or mathieu_loadmode_taxonomy_archive, then pass the post type or taxonomy name in your javascripts AJAX the same way you're passing tax_term or tax_post_type.

Other notes:

  • do not use relative paths for admin-ajax.php, the examples use localised data or absolute paths for a reason, your code will fail if your URL structure needs more than on .. with relative paths
  • whitelist those options, only allow a limited subset of values, right now I could request any data I want from your site, or ask it for something extremely slow and expensive. User data is not trustworthy, don't pass it into APIs/classes without checks. E.g. what's to stop me adding a meta_value parameter, or one of the __not_in parameters. Or requesting all posts by an author for an internal post type that's not meant to be accessible.
4
  • I edited the questions with some code updated following your recommendations. Please let me know if it's better, worse or whatever ; ) Thanks Jul 16, 2021 at 11:33
  • mysite_archive_loadmore_ajax_handler is a big improvement, you're on the right track!
    – Tom J Nowell
    Jul 16, 2021 at 12:28
  • Applying that to both AJAX handlers and JS is way much better, thank you. I'm also creating the variable of the post_type from my page template, then I declare the data inside the AJAX JS. I opened a new thread about the common code that I use for my page templates (it includes the custom post type loop). I will appreciate if you take a look at it and if you see some breach: link. Thanks again. Jul 16, 2021 at 12:42
  • Just keep in mind this isn't a forum and questions aren't discussion threads. You'll need to ask specific questions that people can write solutions/answers for, not just replies
    – Tom J Nowell
    Jul 17, 2021 at 1:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.