webentwicklung-frage-antwort-db.com.de

AJAX / Weitere Informationen: mehrere check_ajax_referer () und wp_create_nonce () funktionieren nicht unabhängig voneinander

Ich habe mehrere wp_query's auf derselben Seite. Jede dieser Abfragen hat eine AJAX Schaltfläche "Weitere Informationen" am unteren Rand. Das Problem ist, dass ich immer nur einen zur Arbeit bringen kann. Unabhängig davon, welche Funktion zuerst in die functions.php eingefügt wird, funktioniert die eine - die andere erhält einen 403-Fehler für die admin-ajax.php.

Ich bin ziemlich neu in AJAX, also habe ich wahrscheinlich einen vollständigen Hash daraus gemacht, und ich bin mir sicher, dass es eine Möglichkeit gibt, dies in einer einzigen Funktion zu kombinieren (bevorzugt!), Aber wenn ich nur einen Weg für sie finden kann Alle arbeiten unabhängig, das funktioniert gut.

Hier ist mein Code:

Die 2 WP_Queries in einer benutzerdefinierten page-work.php-Vorlage:

Erster:

<?php
    //Find out how many posts 
    $total_posts = wp_count_posts('smart_maps');
    $total_posts = $total_posts->publish;
    $number_shown = 0;


     $the_query = new WP_Query( $args ); ?>
    <?php if ( $the_query->have_posts() ) : ?>
    <div id="smartmaps" class="smartmaps col xs-col-14 xs-offset-1 md-col-12 md-offset-2" style="display:none;">
        <div class="in-here-smartmaps">
            <?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
            <a href="<?php echo get_permalink(get_the_ID());?>">
                <div class="single-smartmap col xs-col-16 md-col-8">
                    <div class="col xs-col-8 xs-offset-4 md-col-4 md-offset-0 center">
                        <div class="image-element">
                            <img src="<?php the_field('thumbnail_image');?>" class="circle">
                            <div class="image-overlay circle"></div>
                        </div>
                    </div>
                    <div class="col xs-col-14 xs-offset-1 md-col-10 md-offset-1">
                        <h5 class="smart-map-title"><?php the_title();?></h5>
                        <?php if(get_field('icons')) :?>
                            <div class="block-icons">
                                <?php if(in_array('Heart', get_field('icons'))) :?>
                                    <span class="icon-heart"></span>
                                <?php endif;?>
                                <?php if(in_array('Plant', get_field('icons'))) :?>
                                    <span class="icon-plant"></span>
                                <?php endif; ?>
                                <?php if(in_array('Cup', get_field('icons'))) :?>
                                    <span class="icon-cup"></span>
                                <?php endif;?>
                                <?php if(in_array('Book', get_field('icons'))) :?>
                                    <span class="icon-book"></span>
                                <?php endif;?>
                            </div>
                        <?php endif;?>
                    </div>
                </div>
            </a>
                <?php $number_shown++; 
            endwhile; ?>
        <?php endif;?>
        </div>
    <?php if($number_shown != $total_posts) :?>
        <div class="loadmore smarties col xs-col-14 xs-offset-1 md-col-8 md-offset-4 center">
            <h3><a href="#">LOAD MORE</a></h3>
        </div>
    <?php endif;?>

    </div>
<div clas="clearfix"></div>

Die zweite 1:

<div id="strategic-events" class="strategicevents col xs-col-14 xs-offset-1 md-col-12 md-offset-2" style="display:none;">
    <div class="in-here-strats">
    <?php
    //Find out how many posts 
    $total_posts = wp_count_posts('strategic_events');
    $total_posts = $total_posts->publish;
    $number_shown = 0;

    $args = array( 'post_type' => 'strategic_events', 'posts_per_page' => 10, 'offset' => $the_offset );


     $the_query2 = new WP_Query( $args ); ?>
    <?php if ( $the_query2->have_posts() ) : 
        while ( $the_query2->have_posts() ) : $the_query2->the_post(); ?>
        <a href="<?php echo get_permalink(get_the_ID());?>">    
            <div class="single-strategicevent col xs-col-16 md-col-8">
                <div class="col xs-col-8 xs-offset-4 md-col-4 md-offset-0 center">
                    <div class="image-element">
                        <img src="<?php the_field('strategic_event_image');?>" class="circle">
                        <div class="image-overlay circle"></div>
                    </div>
                </div>
                <div class="col xs-col-14 xs-offset-1 md-col-10 md-offset-1">
                    <h5 class="strategic-event-title"><?php the_title();?></h5>
                    <?php if(get_field('subtitle')) :?>
                        <p><?php the_field('subtitle');?></p>   
                        <small><?php the_field('location_text');?></small>          
                    <?php endif;?>
                </div>
            </div>
        </a>
            <?php $number_shown++; 
        endwhile; 
    endif; ?>
    </div>
    <?php if($number_shown != $total_posts) :?>
        <div class="loadmore strats col xs-col-14 xs-offset-1 md-col-8 md-offset-4 center">
            <h3><a href="#">LOAD MORE</a></h3>
        </div>
    <?php endif;?>

</div>
<div class="clearfix"></div>

Mein JS-Code (beides vorerst auch in der page-work.php) ...

<script>
var ajaxurl = "<?php echo admin_url( 'admin-ajax.php' ); ?>";
var page = 2;
jQuery(function($) {
    $('body').on('click', '.loadmore.strats', function(e) {
        e.preventDefault();
        var data = {
            'action': 'load_posts_by_ajax',
            'page': page,
            'security': '<?php echo wp_create_nonce("load_strats_posts"); ?>',
            'max_page': '<?php global $wp_query; echo $wp_query->max_num_pages;?>'
        };

        $.post(ajaxurl, data, function(response) {
            $('.in-here-strats').append(response);
            page++;
        });
    });
});
<script>
var ajaxurl = "<?php echo admin_url( 'admin-ajax.php' ); ?>";
var page = 2;
jQuery(function($) {
    $('body').on('click', '.loadmore.smarties', function(e) {
        e.preventDefault();
        var data = {
            'action': 'load_posts_by_ajax',
            'page': page,
            'security2': '<?php echo wp_create_nonce("load_smartmaps_posts"); ?>',
            'max_page': '<?php global $wp_query; echo $wp_query->max_num_pages;?>'
        };

        $.post(ajaxurl, data, function(response) {
            $('.in-here-smartmaps').append(response);
            page++;
        });
    });
});
</script>

Und das AJAX funktioniert in meiner function.php:

//Load More Smart Maps 
add_action('wp_ajax_load_posts_by_ajax', 'load_smart_maps_by_ajax_callback');
add_action('wp_ajax_nopriv_load_posts_by_ajax', 'load_smart_maps_by_ajax_callback');
function load_smart_maps_by_ajax_callback() {
check_ajax_referer('load_smartmaps_posts', 'security2');
$paged = $_POST['page'];
$args = array(
    'post_type' => 'smart_maps',
    'post_status' => 'publish',
    'posts_per_page' => '10',
    'paged' => $paged,
);
$my_posts = new WP_Query( $args );
if ( $my_posts->have_posts() ) :
    ?>
    <?php 
        $total_posts = wp_count_posts('smart_maps');
        $total_posts = $total_posts->publish;
        $number_shown = $paged * 10 - 10;?>
    <?php while ( $my_posts->have_posts() ) : $my_posts->the_post() ?>

            <a href="<?php echo get_permalink(get_the_ID());?>">
                <div class="single-smartmap col xs-col-16 md-col-8">
                    <div class="col xs-col-8 xs-offset-4 md-col-4 md-offset-0 center">
                        <div class="image-element">
                            <img src="<?php the_field('thumbnail_image');?>" class="circle">
                            <div class="image-overlay circle"></div>
                        </div>
                    </div>
                    <div class="col xs-col-14 xs-offset-1 md-col-10 md-offset-1">
                        <h5 class="smart-map-title"><?php the_title();?></h5>
                        <?php if(get_field('icons')) :?>
                            <div class="block-icons">
                                <?php if(in_array('Heart', get_field('icons'))) :?>
                                    <span class="icon-heart"></span>
                                <?php endif;?>
                                <?php if(in_array('Plant', get_field('icons'))) :?>
                                    <span class="icon-plant"></span>
                                <?php endif; ?>
                                <?php if(in_array('Cup', get_field('icons'))) :?>
                                    <span class="icon-cup"></span>
                                <?php endif;?>
                                <?php if(in_array('Book', get_field('icons'))) :?>
                                    <span class="icon-book"></span>
                                <?php endif;?>
                            </div>
                        <?php endif;?>
                    </div>
                </div>
            </a>
            <?php $number_shown++;
                if ( $number_shown == $total_posts ) {
                    echo '<style>.loadmore.smarties {display:none;}</style>';
                }
            endwhile ?>
    <?php endif;

wp_die();
}


//Load More Strategic Events
add_action('wp_ajax_load_posts_by_ajax', 'load_strats_by_ajax_callback');
add_action('wp_ajax_nopriv_load_posts_by_ajax', 'load_strats_by_ajax_callback');
function load_strats_by_ajax_callback() {
check_ajax_referer('load_strats_posts', 'security');
$paged = $_POST['page'];
$args = array(
    'post_type' => 'strategic_events',
    'post_status' => 'publish',
    'posts_per_page' => '10',
    'paged' => $paged,
);
$my_posts = new WP_Query( $args );
if ( $my_posts->have_posts() ) :
    ?>
    <?php 
        $total_posts = wp_count_posts('strategic_events');
        $total_posts = $total_posts->publish;
        $number_shown = $paged * 10 - 10;?>
    <?php while ( $my_posts->have_posts() ) : $my_posts->the_post() ?>

            <a href="<?php echo get_permalink(get_the_ID());?>">    
            <div class="single-strategicevent col xs-col-16 md-col-8">
                <div class="col xs-col-8 xs-offset-4 md-col-4 md-offset-0 center">
                    <div class="image-element">
                        <img src="<?php the_field('strategic_event_image');?>" class="circle">
                        <div class="image-overlay circle"></div>
                    </div>
                </div>
                <div class="col xs-col-14 xs-offset-1 md-col-10 md-offset-1">
                    <h5 class="strategic-event-title"><?php the_title();?></h5>
                    <?php if(get_field('subtitle')) :?>
                        <p><?php the_field('subtitle');?></p>   
                        <small><?php the_field('location_text');?></small>          
                    <?php endif;?>
                </div>
            </div>
        </a>
            <?php $number_shown++; 
                if ( $number_shown == $total_posts ) {
                    echo '<style>.loadmore.strats {display:none;}</style>';
                }
            endwhile ?>
    <?php endif;

wp_die();
}

Ich bin alle bereit, dies in eine einzige Funktion zu vereinfachen, wenn möglich, oder wenn nicht, zumindest, um es selbstständig zum Laufen zu bringen. Ich vermute, dass es nur 1 wp_nonce's anzeigt und es gegen beide AJAX Aufrufe prüft, so dass das erste, das es liest, in Ordnung ist, das zweite mit einem 403 aufkommt?

1
user2115227

Das Problem ist, dass ich immer nur einen zur Arbeit bringen kann. Unabhängig davon, welche Funktion zuerst in die functions.php eingefügt wird, funktioniert die eine - die andere erhält einen 403-Fehler für die admin-ajax.php.

Ja, da Ihre beiden PHP Funktionen (oder AJAX Rückrufe) mit der Aktion same AJAX verknüpft sind, die load_posts_by_ajax lautet:

// #1 AJAX action = load_posts_by_ajax
add_action('wp_ajax_load_posts_by_ajax', 'load_smart_maps_by_ajax_callback');
add_action('wp_ajax_nopriv_load_posts_by_ajax', 'load_smart_maps_by_ajax_callback');

// #2 AJAX action = load_posts_by_ajax
add_action('wp_ajax_load_posts_by_ajax', 'load_strats_by_ajax_callback');
add_action('wp_ajax_nopriv_load_posts_by_ajax', 'load_strats_by_ajax_callback');

Und check_ajax_referer() verlässt die Seite standardmäßig mit dem Status 403 ("forbidden"), wenn beispielsweise die Nonce nicht angegeben ist oder bereits abgelaufen ist:

// #1 $_REQUEST['security2'] will be checked for the load_smartmaps_posts nonce action.
check_ajax_referer('load_smartmaps_posts', 'security2');

// #2 $_REQUEST['security'] will be checked for the load_strats_posts nonce action.
check_ajax_referer('load_strats_posts', 'security');

Sie können beide Nonces senden (obwohl dies niemand tun würde), oder Sie können denselben Nonce und denselben $_REQUEST-Schlüssel (z. B. security) verwenden, aber Sie würden trotzdem unerwartete Ergebnisse/Antworten erhalten.

Wenn Sie also eine "einzelne Funktion" möchten, können Sie eine sekundäre "Aktion" verwenden :

  1. PHP-Teil in functions.php:

    // #1 Load More Smart Maps
    // No add_action( 'wp_ajax_...' ) calls here.
    function load_smart_maps_by_ajax_callback() {
        // No need to call check_ajax_referer()
        ...your code here...
    }
    
    
    // #2 Load More Strategic Events
    // No add_action( 'wp_ajax_...' ) calls here.
    function load_strats_by_ajax_callback() {
        // No need to call check_ajax_referer()
        ...your code here...
    }
    
    add_action( 'wp_ajax_load_posts_by_ajax', 'load_posts_by_ajax' );
    add_action( 'wp_ajax_nopriv_load_posts_by_ajax', 'load_posts_by_ajax' );
    function load_posts_by_ajax() {
        check_ajax_referer( 'load_posts_by_ajax', 'security' );
    
        switch ( filter_input( INPUT_POST, 'action2' ) ) {
            case 'load_smartmaps_posts':
                load_smart_maps_by_ajax_callback();
                break;
    
            case 'load_strats_posts':
                load_strats_by_ajax_callback();
                break;
        }
    
        wp_die();
    }
    
  2. JS-Teil - das Objekt data:

    // #1 On click of `.loadmore.smarties`
    var data = {
        'action': 'load_posts_by_ajax',
        'action2': 'load_smartmaps_posts',
        'security': '<?php echo wp_create_nonce( "load_posts_by_ajax" ); ?>', // same nonce
        ...other properties...
    };
    
    // #2 On click of `.loadmore.strats`
    var data = {
        'action': 'load_posts_by_ajax',
        'action2': 'load_strats_posts',
        'security': '<?php echo wp_create_nonce( "load_posts_by_ajax" ); ?>', // same nonce
        ...other properties...
    };
    

Aber warum nicht die Rückrufe zu ihrer eigenen spezifischen AJAX Aktion einbinden:

// #1 AJAX action = load_smart_maps_posts_by_ajax
add_action('wp_ajax_load_smart_maps_posts_by_ajax', 'load_smart_maps_by_ajax_callback');
add_action('wp_ajax_nopriv_load_smart_maps_posts_by_ajax', 'load_smart_maps_by_ajax_callback');

// #2 AJAX action = load_strats_posts_by_ajax
add_action('wp_ajax_load_strats_posts_by_ajax', 'load_strats_by_ajax_callback');
add_action('wp_ajax_nopriv_load_strats_posts_by_ajax', 'load_strats_by_ajax_callback');
1
Sally CJ

WP Ajax ist ein bisschen seltsam. Sie stellen das Skript in eine Warteschlange, damit es auf der Seite angezeigt wird. Sie können Ihr Skript auch LOKALISIEREN, um Variablen in die Seite einzufügen, die das Skript benötigt, z. B. Nonces, Ajax-Adressen oder andere seltsame Dinge, die Sie möglicherweise nützlich finden.

Registrieren und lokalisieren Sie das Skript wie folgt:

    wp_enqueue_script( 'name_of_function', get_stylesheet_directory_uri() . '/js/my_special_script.js', array( 'jquery' ), '1.0', true );
    wp_localize_script( 'name_of_function',
                       'name_the_script_will_see',
                       array(
                           'ajax_url' => admin_url('admin-ajax.php'),
                           'ajax_nonce' => wp_create_nonce('your_nonce'),
                       ));

Und dann müssen Sie die Ajax-Aktion ZWEIMAL hinzufügen, einmal für öffentliche und einmal für Admin-Seiten.

add_action('wp_ajax_this_is_the_ajax_name', 'function_name_in_php' );
add_action('wp_ajax_nopriv_this_is_the_ajax_name', 'function_name_in_php' );

Dann nehmen Sie in Ihrem Skript die folgenden Werte auf:

var data = {
                'action': 'this_is_the_ajax_name',
                'post_nonce': name_the_script_will_see.ajax_nonce,
                'other_value_needed': value_generated_by_script,
            };
$.post( name_the_script_will_see.ajax_url, data, function( response_data ) { 

            if ( response_data.success ) {
                alert ("Success");
            } else {
                alert ("Error");
            }

Ihr PHP-Skript wird die Daten als Post-Daten erhalten:

function function_name_in_php(){
     $nonce = $_POST['post_nonce'];
     $other_data = $_POST['other_value_needed'];
     if ( ! wp_verify_nonce( $nonce, 'your_nonce' ) ) {
    wp_send_json_error(array(
        'message'=>'Security Token Failure',
    )); // sends json_encoded success=false
}

Ich werde eine Nonce in vielen verschiedenen Skripten verwenden. Ich stelle nur sicher, dass mein Anforderer tatsächlich von meiner Website kommt. Es hat keinen Sinn, dafür 17 verschiedene Nonces zu generieren. Oft stecke ich die Nonce als Datenattribut in einen Submission-Button und ziehe sie dann aus diesem und nicht aus dem WordPress-Lokalisierungsschema. Es ist praktischer, wenn eine Seite viele Skripte enthält und sie auf einige der gleichen Back-End-Funktionen zugreifen.

var postData = {};
 var nonce = $('#register_button').attr('data-nonce');
 postData.nonce = nonce;
 postData.action = 'this_is_the_ajax_name';
$.post( name_the_script_will_see.ajax_url, postData, function( response_data ) { 

        if ( response_data.success ) {
            alert ("success");
        } else {
            alert ("Error");
        }

Hoffe das hilft!

2
Elkrat