PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.1.1
Post Grid Gutenberg Blocks – PostX v5.1.1
5.1.1 5.1.0 5.0.41 5.0.39 5.0.38 5.0.37 5.0.36 5.0.35 5.0.34 5.0.33 5.0.32 5.0.31 5.0.30 5.0.29 5.0.28 5.0.27 5.0.26 5.0.25 5.0.23 5.0.24 5.0.22 5.0.21 5.0.20 5.0.19 5.0.18 All 240 releases
← All changes | classes/Blocks.php +83 -13 5.0.23 → 5.1.1 View file →
@@ -39,10 +39,12 @@
39 39 add_action( 'wp_ajax_nopriv_ultp_pagination', array( $this, 'ultp_pagination_callback' ) ); // Page Number AJAX Call Logout User .
40 40
41 41 add_action( 'wp_ajax_ultp_share_count', array( $this, 'ultp_share_count_callback' ) ); // share Count save .
42 42 add_action( 'wp_ajax_nopriv_ultp_share_count', array( $this, 'ultp_share_count_callback' ) ); // share Count save .
43 - add_action( 'wp_ajax_ultp_get_nonce', array( $this, 'ultp_get_nonce_callback' ) ); // Nonce Generating Callback
44 - add_action( 'wp_ajax_nopriv_ultp_get_nonce', array( $this, 'ultp_get_nonce_callback' ) ); // Nonce Generating Callback
43 + // Public by design — see ultp_get_nonce_callback() for why, and for what
44 + // 'ultp-public-nonce' does and does not protect.
45 + add_action( 'wp_ajax_ultp_get_nonce', array( $this, 'ultp_get_nonce_callback' ) );
46 + add_action( 'wp_ajax_nopriv_ultp_get_nonce', array( $this, 'ultp_get_nonce_callback' ) );
45 47 }
46 48
47 49 /**
48 50 * Require Blocks
@@ -227,9 +229,9 @@
227 229 );
228 230 $value['attrs']['queryExclude'] = wp_json_encode( $queryArr );
229 231 }
230 232 $attr = array_merge( $attr, $value['attrs'] );
231 - echo $objectBlock->content($attr, true); //phpcs:ignore
233 + echo $objectBlock->content( $attr, true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Block render output; each block escapes its own markup.
232 234 die();
233 235 }
234 236 }
235 237 if ( ! empty( $value['innerBlocks'] ) ) {
@@ -246,9 +248,9 @@
246 248 *
247 249 * @return STRING The AJAX response.
248 250 */
249 251 public function ultp_next_prev_callback() {
250 - if ( ! ( isset( $_REQUEST['wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['wpnonce'] ) ), 'ultp-nonce' ) ) ) {
252 + if ( ! $this->verify_public_nonce() ) {
251 253 return;
252 254 }
253 255
254 256 $paged = isset( $_POST['paged'] ) ? sanitize_text_field( $_POST['paged'] ) : '';
@@ -340,9 +342,9 @@
340 342 *
341 343 * @return STRING The AJAX response.
342 344 */
343 345 public function ultp_filter_callback() {
344 - if ( ! ( isset( $_REQUEST['wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['wpnonce'] ) ), 'ultp-nonce' ) ) ) {
346 + if ( ! $this->verify_public_nonce() ) {
345 347 return;
346 348 }
347 349
348 350 $taxtype = isset( $_POST['taxtype'] ) ? sanitize_text_field( $_POST['taxtype'] ) : '';
@@ -380,9 +382,9 @@
380 382 *
381 383 * @return STRING The AJAX response.
382 384 */
383 385 public function ultp_adv_filter_callback() {
384 - if ( ! ( isset( $_REQUEST['wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['wpnonce'] ) ), 'ultp-nonce' ) ) ) {
386 + if ( ! $this->verify_public_nonce() ) {
385 387 return;
386 388 }
387 389
388 390 $blockId = isset( $_POST['blockId'] ) ? sanitize_text_field( $_POST['blockId'] ) : '';
@@ -438,9 +440,9 @@
438 440 *
439 441 * @return STRING The AJAX response.
440 442 */
441 443 public function ultp_pagination_callback() {
442 - if ( ! ( isset( $_REQUEST['wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['wpnonce'] ) ), 'ultp-nonce' ) ) ) {
444 + if ( ! $this->verify_public_nonce() ) {
443 445 return;
444 446 }
445 447
446 448 $paged = isset( $_POST['paged'] ) ? sanitize_text_field( $_POST['paged'] ) : '';
@@ -511,9 +513,9 @@
511 513 *
512 514 * @return void
513 515 */
514 516 public function ultp_share_count_callback() {
515 - if ( ! ( isset( $_REQUEST['wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['wpnonce'] ) ), 'ultp-nonce' ) ) ) {
517 + if ( ! $this->verify_public_nonce() ) {
516 518 return;
517 519 }
518 520
519 521 $post_id = isset( $_POST['postId'] ) ? absint( $_POST['postId'] ) : 0;
@@ -661,13 +663,15 @@
661 663 $filter_attributes['queryQuick'] = $adv_filter_data['adv_sort'];
662 664 $filter_attributes['queryOrderBy'] =
663 665 ! empty( $adv_filter_data['orderby'] ) ? $adv_filter_data['orderby'] : ( $value['attrs']['queryOrderBy'] ?? '' );
664 666 }
665 -
667 + $pagination = $this->pagination_for_filter( $attr, $postId, $blockRaw, $filter_attributes );
666 668 $toReturn = array(
667 669 'blocks' => $objectBlock->content( $attr, true ),
668 670 'notFound' => isset( $attr['notFoundMessage'] ) ? $attr['notFoundMessage'] : '',
669 - 'pagination' => $this->pagination_for_filter( $attr, $postId, $blockRaw, $filter_attributes ),
671 + 'pagination' => $pagination['pagination_content'],
672 + 'data_attrs' => $pagination['data_attrs'],
673 + 'data_all_attrs' => $pagination['data_attrs'],
670 674 'paginationType' => $attr['paginationType'],
671 675 'paginationShow' => $attr['paginationShow'],
672 676 );
673 677 }
@@ -723,15 +727,81 @@
723 727
724 728 $wraper_after .= '</div>';
725 729 }
726 730 wp_reset_query();
731 +
732 + // queryQuick
733 + return array(
734 + 'pagination_content' => $wraper_after,
735 + 'data_attrs' => wp_json_encode( array(
736 + 'paged' => 1,
737 + 'blockid' => $attr['blockId'],
738 + 'postid' => $postId,
739 + 'pages' => $pageNum,
740 + 'blockname' => $blockRaw,
741 + 'filter_value' => isset( $filter_attributes['queryTaxValue'] ) ? $filter_attributes['queryTaxValue'] : '',
742 + 'filter_type' => isset( $filter_attributes['queryTax'] ) ? $filter_attributes['queryTax'] : '',
743 + 'filter_author' => isset( $filter_attributes['queryAuthor'] ) ? $filter_attributes['queryAuthor'] : '',
744 + 'filter_order' => isset( $filter_attributes['queryOrder'] ) ? $filter_attributes['queryOrder'] : 'DESC',
745 + 'filter_orderby' => isset( $filter_attributes['queryOrderBy'] ) ? $filter_attributes['queryOrderBy'] : '',
746 + 'filter_search' => isset( $filter_attributes['querySearch'] ) ? $filter_attributes['querySearch'] : '',
747 + 'filter_queryQuick' => isset( $filter_attributes['queryQuick'] ) ? $filter_attributes['queryQuick'] : '',
748 + 'filter_for' => 'ultp-block-' . $attr['blockId'],
749 + )),
750 + );
751 + }
727 752
728 - return $wraper_after;
753 + /**
754 + * Verify the front-end AJAX nonce, or end the request.
755 + *
756 + * Fails with a machine-readable 403 rather than the bare `return` these
757 + * handlers used to do. A bare return lets admin-ajax emit "0" at HTTP 200,
758 + * which the client cannot tell apart from a real response — ultp_next_prev's
759 + * success handler treated that "0" as markup and rendered it into the block.
760 + *
761 + * The 'ultp_invalid_nonce' code is a contract with assets/js/ultp.js: on
762 + * seeing it the client discards its cached nonce, fetches a fresh one and
763 + * retries once. A nonce legitimately expires while a tab is open (WordPress
764 + * nonces last 12-24h, tabs last longer), so this is a routine condition and
765 + * not an attack signal. See ultp_get_nonce_callback() for what this nonce
766 + * does and does not protect.
767 + *
768 + * @since v.5.1.0
769 + *
770 + * @return BOOLEAN True when the nonce is valid; otherwise the request ends.
771 + */
772 + private function verify_public_nonce() {
773 + if ( isset( $_REQUEST['wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['wpnonce'] ) ), 'ultp-public-nonce' ) ) {
774 + return true;
775 + }
776 +
777 + wp_send_json_error(
778 + array(
779 + 'code' => 'ultp_invalid_nonce',
780 + 'message' => __( 'Security token expired. Please try again.', 'ultimate-post' ),
781 + ),
782 + 403
783 + );
784 +
785 + return false;
729 786 }
730 787
731 788 /**
732 - * Nonce Generation Callback
789 + * Vends the front-end AJAX nonce.
733 790 *
791 + * Public by design: full-page caching makes a nonce embedded in HTML stale for
792 + * most visitors, so front-end blocks fetch one at runtime instead.
793 + *
794 + * SECURITY: because this endpoint is public, 'ultp-public-nonce' is NOT a CSRF
795 + * control on the front end — anyone can request one. It is a request-shape
796 + * check only. Any nopriv handler that changes state MUST carry its own
797 + * authorisation; see ultp_share_count_callback() for the pattern (post status,
798 + * capability and rate-limit checks, none of which depend on the nonce).
799 + *
800 + * This endpoint vends the PUBLIC nonce only. Admin routes verify the separate
801 + * 'ultp-admin-nonce', which is never vended here and is always paired with a
802 + * capability check. Do not merge the two.
803 + *
734 804 * @since v.5.0.6
735 805 *
736 806 * @return STRING The AJAX response.
737 807 */
@@ -738,9 +808,9 @@
738 808 public function ultp_get_nonce_callback() {
739 809 nocache_headers();
740 810 wp_send_json_success(
741 811 array(
742 - 'nonce' => wp_create_nonce( 'ultp-nonce' ),
812 + 'nonce' => wp_create_nonce( 'ultp-public-nonce' ),
743 813 )
744 814 );
745 815 }
746 816 }