'', 'secret' => '', 'site_key' => '', 'orders' => '1', 'forms' => '1', ) ); } public static function webhook_url(): string { return (string) self::all()['webhook_url']; } public static function secret(): string { return (string) self::all()['secret']; } public static function enabled( string $feature ): bool { return '1' === (string) ( self::all()[ $feature ] ?? '0' ); } public static function is_configured(): bool { return '' !== self::webhook_url() && '' !== self::secret(); } /** Random per-site key so external IDs from different sites never collide. */ public static function site_key(): string { $all = self::all(); if ( '' === $all['site_key'] ) { $all['site_key'] = wp_generate_password( 24, false, false ); update_option( self::OPTION, $all, false ); } return $all['site_key']; } /** * Adds a settings error once. WordPress runs the sanitize callback twice the first time the * option is saved (add_option + update_option), which would otherwise show every error twice. */ private static function error( string $code, string $message ): void { foreach ( get_settings_errors( self::OPTION ) as $e ) { if ( $e['code'] === $code ) { return; } } add_settings_error( self::OPTION, $code, $message ); } /** Sanitize callback for the settings form. An empty secret field keeps the stored secret. */ public static function sanitize( $input ): array { $current = self::all(); $input = is_array( $input ) ? $input : array(); $url = esc_url_raw( trim( (string) ( $input['webhook_url'] ?? '' ) ), array( 'https', 'http' ) ); if ( '' !== $url && ! preg_match( '#/v1/webhooks/connectors/[0-9a-f-]{36}$#i', $url ) ) { self::error( 'rootcue_url', __( 'That doesn\'t look like a RootCue webhook URL. Copy it from RootCue → More → Integrations → WordPress.', 'rootcue' ) ); $url = $current['webhook_url']; } if ( '' !== $url && 0 === strpos( $url, 'http://' ) && ! in_array( wp_parse_url( $url, PHP_URL_HOST ), array( 'localhost', '127.0.0.1' ), true ) ) { self::error( 'rootcue_https', __( 'The webhook URL must use https.', 'rootcue' ) ); $url = $current['webhook_url']; } $secret = trim( (string) ( $input['secret'] ?? '' ) ); if ( '' !== $secret && ! preg_match( '/^rcwh_[A-Za-z0-9_-]{20,}$/', $secret ) ) { self::error( 'rootcue_secret', __( 'The signing secret should start with rcwh_.', 'rootcue' ) ); $secret = ''; } return array( 'webhook_url' => $url, 'secret' => '' !== $secret ? $secret : $current['secret'], 'site_key' => $current['site_key'], 'orders' => empty( $input['orders'] ) ? '0' : '1', 'forms' => empty( $input['forms'] ) ? '0' : '1', ); } }