'GET', 'callback' => [ $this, 'get_info' ], 'permission_callback' => '__return_true', ] ); register_rest_route( $namespace, '/services', [ 'methods' => 'GET', 'callback' => [ $this, 'get_services' ], 'permission_callback' => '__return_true', ] ); register_rest_route( $namespace, '/contact', [ 'methods' => 'POST', 'callback' => [ $this, 'submit_contact' ], 'permission_callback' => '__return_true', 'args' => [ 'name' => [ 'required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', ], 'email' => [ 'required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_email', 'validate_callback' => fn( $val ) => is_email( $val ), ], 'message' => [ 'required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_textarea_field', ], // Honeypot: must be empty. Bots fill this in. 'website' => [ 'required' => false, 'type' => 'string', 'default' => '', ], ], ] ); register_rest_route( $namespace, '/readiness', [ 'methods' => 'GET', 'callback' => [ $this, 'get_readiness' ], 'permission_callback' => '__return_true', ] ); } /** * GET /airewp/v1/info — Business information for AI agents. */ public function get_info(): \WP_REST_Response { $settings = AI_Ready_WP::get_settings(); $data = [ 'name' => $settings['company_name'], 'description' => $settings['company_desc'], 'url' => home_url(), 'industry' => $settings['industry'], 'contact' => [ 'email' => $settings['company_email'], 'phone' => $settings['company_phone'], ], ]; if ( ! empty( $settings['company_address'] ) ) { $data['address'] = [ 'street' => $settings['company_address'], 'city' => $settings['company_city'], 'zip' => $settings['company_zip'], 'country' => $settings['company_country'], ]; } if ( ! empty( $settings['services'] ) ) { $data['services'] = array_map( 'trim', explode( ',', $settings['services'] ) ); } $social = []; foreach ( [ 'social_x', 'social_linkedin', 'social_instagram', 'social_facebook', 'social_github' ] as $field ) { if ( ! empty( $settings[ $field ] ) ) { $key = str_replace( 'social_', '', $field ); $social[ $key ] = $settings[ $field ]; } } if ( ! empty( $social ) ) { $data['social'] = $social; } $data['ai_discovery'] = [ 'agents_json' => home_url( '/.well-known/agents.json' ), 'agent_card' => home_url( '/.well-known/agent-card.json' ), 'llms_txt' => home_url( '/llms.txt' ), 'llms_full_txt' => home_url( '/llms-full.txt' ), ]; return new \WP_REST_Response( $data, 200 ); } /** * GET /airewp/v1/services — Service listing. */ public function get_services(): \WP_REST_Response { $settings = AI_Ready_WP::get_settings(); if ( empty( $settings['services'] ) ) { return new \WP_REST_Response( [ 'services' => [] ], 200 ); } $services = array_map( 'trim', explode( ',', $settings['services'] ) ); $result = []; foreach ( $services as $service ) { $result[] = [ 'name' => $service, ]; } return new \WP_REST_Response( [ 'company' => $settings['company_name'], 'services' => $result, ], 200 ); } /** * POST /airewp/v1/contact — Contact form submission from AI agents. */ public function submit_contact( \WP_REST_Request $request ): \WP_REST_Response { $name = $request->get_param( 'name' ); $email = $request->get_param( 'email' ); $message = $request->get_param( 'message' ); // Honeypot: reject silently if bot-trap field is filled if ( ! empty( $request->get_param( 'website' ) ) ) { return new \WP_REST_Response( [ 'success' => true, 'message' => 'Your message has been sent. We will get back to you soon.', ], 200 ); } // Rate limiting: 5 submissions per IP per hour $ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : 'unknown'; $transient = 'airewp_contact_' . md5( $ip ); $count = (int) get_transient( $transient ); if ( $count >= 5 ) { return new \WP_REST_Response( [ 'success' => false, 'message' => 'Rate limit exceeded. Please try again later.', ], 429 ); } set_transient( $transient, $count + 1, HOUR_IN_SECONDS ); // Send email to admin $settings = AI_Ready_WP::get_settings(); $to = $settings['company_email'] ?: get_option( 'admin_email' ); $subject = sprintf( '[%s] AI Agent Contact: %s', $settings['company_name'], $name ); $body = sprintf( "New contact via AI agent:\n\nName: %s\nEmail: %s\n\nMessage:\n%s\n\n---\nSubmitted via AI-Ready WP contact endpoint", $name, $email, $message ); $safe_name = str_replace( [ "\r", "\n" ], '', $name ); $sent = wp_mail( $to, $subject, $body, [ 'Reply-To: ' . $safe_name . ' <' . $email . '>', ] ); if ( ! $sent ) { return new \WP_REST_Response( [ 'success' => false, 'message' => 'Could not send message. Please try again later.', ], 500 ); } return new \WP_REST_Response( [ 'success' => true, 'message' => 'Your message has been sent. We will get back to you soon.', ], 200 ); } /** * GET /airewp/v1/readiness — AI-Readiness score for external auditing. */ public function get_readiness(): \WP_REST_Response { $settings = AI_Ready_WP::get_settings(); $checks = AIREWP_Dashboard::get_checks( $settings ); $score = AIREWP_Dashboard::calculate_score( $settings ); $result = []; foreach ( $checks as $check ) { $result[] = [ 'check' => $check['label'], 'passed' => $check['pass'], ]; } return new \WP_REST_Response( [ 'score' => $score, 'max' => 10, 'checks' => $result, 'version' => AIREWP_VERSION, 'site' => home_url(), ], 200 ); } }