PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.1.0
Post Grid Gutenberg Blocks – PostX v5.1.0
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 +60 -10 5.0.38 → 5.1.0 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;
@@ -748,10 +750,58 @@
748 750 );
749 751 }
750 752
751 753 /**
752 - * Nonce Generation Callback
754 + * Verify the front-end AJAX nonce, or end the request.
753 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;
786 + }
787 +
788 + /**
789 + * Vends the front-end AJAX nonce.
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 + *
754 804 * @since v.5.0.6
755 805 *
756 806 * @return STRING The AJAX response.
757 807 */
@@ -758,9 +808,9 @@
758 808 public function ultp_get_nonce_callback() {
759 809 nocache_headers();
760 810 wp_send_json_success(
761 811 array(
762 - 'nonce' => wp_create_nonce( 'ultp-nonce' ),
812 + 'nonce' => wp_create_nonce( 'ultp-public-nonce' ),
763 813 )
764 814 );
765 815 }
766 816 }