connection = $connection; } public function register(): void { add_action( 'rest_api_init', array( $this, 'register_routes' ) ); add_action( 'admin_post_nopriv_mowl_subscribe', array( $this, 'handle_admin_post' ) ); add_action( 'admin_post_mowl_subscribe', array( $this, 'handle_admin_post' ) ); // B3: a „készleten van" űrlap. Mindig regisztrált: egy gyorsítótárazott // régi űrlap kikapcsolt állapotban is választ kap (a handler csendes sikert ad). add_action( 'admin_post_nopriv_' . BackInStockForm::ACTION, array( $this, 'handle_back_in_stock_admin_post' ) ); add_action( 'admin_post_' . BackInStockForm::ACTION, array( $this, 'handle_back_in_stock_admin_post' ) ); } public function register_routes(): void { register_rest_route( self::NAMESPACE_, '/subscribe', array( 'methods' => \WP_REST_Server::CREATABLE, // Publikus: a látogató kijelentkezett. A spam-szűrés a handlerben. 'permission_callback' => '__return_true', 'callback' => array( $this, 'subscribe' ), ) ); register_rest_route( self::NAMESPACE_, '/back-in-stock', array( 'methods' => \WP_REST_Server::CREATABLE, // Publikus, mint a /subscribe; a spam-szűrés a handlerben. 'permission_callback' => '__return_true', 'callback' => array( $this, 'back_in_stock' ), ) ); register_rest_route( self::NAMESPACE_, '/tags', array( 'methods' => \WP_REST_Server::READABLE, 'permission_callback' => static function (): bool { return current_user_can( 'edit_posts' ); }, 'callback' => array( $this, 'tags' ), ) ); register_rest_route( self::NAMESPACE_, '/import', array( 'methods' => \WP_REST_Server::READABLE, 'permission_callback' => static function (): bool { return current_user_can( 'manage_options' ); }, 'callback' => array( $this, 'import_status' ), ) ); } public function subscribe( \WP_REST_Request $request ): \WP_REST_Response { $input = SubmissionInput::subscribe( array_merge( (array) $request->get_body_params(), (array) $request->get_json_params() ) ); $result = ( new SubmissionHandler( $this->connection ) )->handle( $input, $this->ip() ); return new \WP_REST_Response( array( 'ok' => $result['ok'], 'status' => $result['public_status'], 'message' => $result['message'], 'hint' => $result['hint'], ), 200 ); } public function back_in_stock( \WP_REST_Request $request ): \WP_REST_Response { $input = SubmissionInput::back_in_stock( array_merge( (array) $request->get_body_params(), (array) $request->get_json_params() ) ); $result = ( new BackInStockHandler( $this->connection ) )->handle( $input, $this->ip() ); return new \WP_REST_Response( array( 'ok' => $result['ok'], 'message' => $result['message'], ), 200 ); } public function tags(): \WP_REST_Response { return new \WP_REST_Response( $this->connection->tags(), 200 ); } /** A backfill haladása az admin haladásjelzőjének. */ public function import_status(): \WP_REST_Response { if ( ! Plugin::has_woocommerce() ) { return new \WP_REST_Response( array( 'status' => BackfillRunner::STATUS_IDLE ), 200 ); } return new \WP_REST_Response( ( new BackfillRunner( $this->connection ) )->status(), 200 ); } /** No-JS: a form POST-ja ide jön, és visszairányítunk az oldalra a státusszal. */ public function handle_admin_post(): void { // Nonce nincs: publikus űrlap, kijelentkezett látogató, gyorsítótárazott oldal (a nonce lejárna); // a védelem a honeypot / időbélyeg / IP-korlát / Turnstile a handlerben. Csak az ismert mezők, sanitizálva. // phpcs:ignore WordPress.Security.NonceVerification.Missing -- lásd fent. $input = SubmissionInput::subscribe( (array) wp_unslash( $_POST ) ); $result = ( new SubmissionHandler( $this->connection ) )->handle( $input, $this->ip() ); $back = esc_url_raw( (string) ( $input['_mowl_page'] ?? '' ) ); if ( '' === $back || wp_parse_url( $back, PHP_URL_HOST ) !== wp_parse_url( home_url(), PHP_URL_HOST ) ) { $back = home_url( '/' ); } $url = add_query_arg( array( 'mowl_status' => rawurlencode( $result['public_status'] ), 'mowl_code' => sanitize_key( $result['code'] ), ), $back ) . '#mowl-form'; Redirect::to( $url ); } /** No-JS „készleten van" beküldés: vissza a termékoldalra, `?mowl_bis=ok|error#mowl-bis`. */ public function handle_back_in_stock_admin_post(): void { // Nonce nincs, mint a feliratkozó űrlapnál (lásd handle_admin_post()). Csak az ismert mezők, sanitizálva. // phpcs:ignore WordPress.Security.NonceVerification.Missing -- lásd fent. $input = SubmissionInput::back_in_stock( (array) wp_unslash( $_POST ) ); $result = ( new BackInStockHandler( $this->connection ) )->handle( $input, $this->ip() ); // Csak saját hostra; a régi fragmentet levágjuk, hogy a sajátunk legyen az egyetlen. $back = strtok( esc_url_raw( (string) ( $input['_mowl_page'] ?? '' ) ), '#' ); $back = wp_validate_redirect( false === $back ? '' : $back, home_url( '/' ) ); $url = add_query_arg( BackInStockForm::STATUS_PARAM, $result['ok'] ? 'ok' : 'error', $back ) . '#mowl-bis'; Redirect::to( $url ); } private function ip(): string { return Spam::client_ip(); } }