service = $service; } /** Register only authenticated actions and owner-scoped wallet content. */ public function register() { add_filter( 'devoynx_rewards_admin_tabs', array( $this, 'tabs' ) ); add_action( 'devoynx_rewards_admin_tab', array( $this, 'render_admin' ) ); add_action( 'admin_post_devoynx_rewards_guest_settings', array( $this, 'save' ) ); add_action( 'admin_post_devoynx_rewards_guest_challenge', array( $this, 'submit' ) ); add_action( 'admin_post_devoynx_rewards_guest_claim', array( $this, 'submit' ) ); add_action( 'devoynx_rewards_wallet_after_activity', array( $this, 'render_wallet' ), 20 ); } /** * Add merchant configuration. * * @param array $tabs Navigation. * @return array */ public function tabs( $tabs ) { $tabs['guest-claims'] = __( 'Guest claims', 'devoynx-rewards' ); return $tabs; } /** Save only bounded settings after capability and CSRF checks. */ public function save() { $this->authorize( true ); check_admin_referer( 'devoynx_rewards_guest_settings' ); $days = isset( $_POST['window_days'] ) && is_scalar( $_POST['window_days'] ) ? absint( $_POST['window_days'] ) : 30; update_option( GuestClaims::OPTION, array( 'enabled' => isset( $_POST['enabled'] ) ? 1 : 0, 'window_days' => min( 90, max( 1, $days ) ), ), false ); wp_safe_redirect( add_query_arg( array( 'page' => 'devoynx-rewards', 'tab' => 'guest-claims', 'guest_saved' => '1', ), admin_url( 'admin.php' ) ) ); exit; } /** Issue a proof or claim, without trusting posted recipient or point amounts. */ public function submit() { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Read only the action allowlist to select the nonce checked below, before processing any claim data. $action = isset( $_POST['action'] ) && is_string( $_POST['action'] ) ? sanitize_key( wp_unslash( $_POST['action'] ) ) : ''; if ( ! in_array( $action, array( 'devoynx_rewards_guest_challenge', 'devoynx_rewards_guest_claim' ), true ) ) { wp_die( esc_html__( 'Permission denied.', 'devoynx-rewards' ), 403 ); } $this->authorize(); check_admin_referer( $action ); $order_id = isset( $_POST['order_id'] ) && is_scalar( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0; $token = isset( $_POST['claim_code'] ) && is_string( $_POST['claim_code'] ) ? sanitize_text_field( wp_unslash( $_POST['claim_code'] ) ) : ''; $challenge = 'devoynx_rewards_guest_challenge' === $action; $result = $challenge ? $this->service->challenge( $order_id ) : $this->service->claim( $order_id, $token ); $query = array( 'guest_order' => $order_id, 'guest_status' => is_wp_error( $result ) ? $result->get_error_code() : ( $challenge ? 'sent' : 'claimed' ), ); wp_safe_redirect( add_query_arg( $query, wc_get_account_endpoint_url( 'rewards' ) ) . '#devoynx-guest-claims' ); exit; } /** * Central POST, session and capability gate; each handler then verifies its nonce. * * @param bool $merchant Whether merchant permission is required. */ private function authorize( $merchant = false ) { if ( 'POST' !== sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ?? '' ) ) || ! get_current_user_id() || ( $merchant && ! current_user_can( 'manage_devoynx_rewards' ) ) ) { wp_die( esc_html__( 'Permission denied.', 'devoynx-rewards' ), 403 ); } } /** * Render honest opt-in scope and security limits. * * @param string $tab Merchant tab. */ public function render_admin( $tab ) { if ( 'guest-claims' !== $tab || ! current_user_can( 'manage_devoynx_rewards' ) ) { return; } $config = $this->service->settings(); ?> /> service->settings()['enabled'] ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only form prefill; never an ownership assertion. $order_id = isset( $_GET['guest_order'] ) && is_scalar( $_GET['guest_order'] ) ? absint( $_GET['guest_order'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Allowlisted read-only status; success is checked against the owner receipt below. $status = isset( $_GET['guest_status'] ) && is_string( $_GET['guest_status'] ) ? sanitize_key( wp_unslash( $_GET['guest_status'] ) ) : ''; $row = $order_id ? ( new \Devoynx\Rewards\Database\ProgramStore() )->find( 'guest:order:' . $order_id ) : null; $claimed = $row && 'claimed' === $row['status'] && (int) $row['user_id'] === (int) $user_id; ?> service->error( $status )->get_error_message() ); ?>
service->error( $status )->get_error_message() ); ?>