extra_rules_top as $rule => $query ) { if ( str_contains( $query, 'cardfaro_slug=' ) ) { unset( $wp_rewrite->extra_rules_top[ $rule ] ); } } flush_rewrite_rules( false ); } public static function record(): array { $record = get_option( self::OPTION, null ); if ( null === $record ) { add_option( self::OPTION, Record::defaults(), '', false ); $record = get_option( self::OPTION ); } if ( ! is_array( $record ) || ! isset( $record['id'], $record['revision'], $record['slug'] ) ) { throw new \RuntimeException( 'Invalid CardFaro contact storage.' ); } return $record; } public static function routes(): void { add_rewrite_rule( '^card/([a-z0-9-]+)/kontakt\.vcf$', 'index.php?cardfaro_slug=$matches[1]&cardfaro_vcf=1', 'top' ); add_rewrite_rule( '^card/([a-z0-9-]+)/?$', 'index.php?cardfaro_slug=$matches[1]', 'top' ); } public static function queryVars( array $vars ): array { $vars[] = 'cardfaro_slug'; $vars[] = 'cardfaro_vcf'; return $vars; } public static function base_url(): string { return untrailingslashit( home_url( '/card' ) ); } public static function public_url( array $record, bool $vcard = false ): string { if ( ! get_option( 'permalink_structure' ) ) { $args = array( 'cardfaro_slug' => $record['slug'] ); if ( $vcard ) { $args['cardfaro_vcf'] = '1'; } return add_query_arg( $args, home_url( '/' ) ); } return self::base_url() . '/' . $record['slug'] . '/' . ( $vcard ? 'kontakt.vcf' : '' ); } public static function display_name( array $record ): string { return Record::name( $record ); } public static function language(): string { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public read-only language preference. $query = isset( $_GET['lang'] ) && is_string( $_GET['lang'] ) ? sanitize_text_field( wp_unslash( $_GET['lang'] ) ) : ''; $header = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : ''; return Record::language( $query, $header ); } public static function localized( array $record, string $lang ): array { foreach ( array( 'role', 'note', 'slogan1', 'slogan2' ) as $key ) { if ( 'en' === $lang && '' !== $record[ $key . '_en' ] ) { $record[ $key ] = $record[ $key . '_en' ]; } } $defaults = 'de' === $lang ? array( 'Ein Kontakt.', 'Viele Möglichkeiten.' ) : array( 'One contact.', 'Many possibilities.' ); foreach ( array( 'slogan1', 'slogan2' ) as $index => $key ) { if ( '' === $record[ $key ] ) { $record[ $key ] = $defaults[ $index ]; } } return $record; } public static function menu(): void { add_menu_page( 'CardFaro', 'CardFaro', 'manage_options', 'cardfaro', array( self::class, 'editor' ), 'dashicons-id-alt', 58 ); } public static function adminAssets( string $hook ): void { if ( 'toplevel_page_cardfaro' !== $hook ) { return; } wp_enqueue_media(); wp_enqueue_style( 'cardfaro-editor', plugins_url( 'assets/editor.css', self::$file ), array(), self::VERSION ); wp_enqueue_script( 'cardfaro-editor', plugins_url( 'assets/editor.js', self::$file ), array(), self::VERSION, true ); } public static function editor(): void { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You are not allowed to edit this contact.', 'cardfaro' ), '', array( 'response' => 403 ) ); } $record = self::record(); include __DIR__ . '/../views/editor.php'; } public static function save(): void { if ( 'POST' !== sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ?? '' ) ) || ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You are not allowed to edit this contact.', 'cardfaro' ), '', array( 'response' => 403 ) ); } check_admin_referer( 'cardfaro_save' ); // Fields are checked for scalar types and sanitized in Record::clean after unslashing. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Dedicated field validator below. $input = wp_unslash( $_POST ); $old = self::record(); if ( ! isset( $input['revision'] ) || ! is_string( $input['revision'] ) || $input['revision'] !== (string) $old['revision'] ) { wp_die( esc_html__( 'The contact changed in another tab. Reload before saving.', 'cardfaro' ), '', array( 'response' => 409, 'back_link' => true ) ); } try { $new = Record::clean( $input, $old ); } catch ( \InvalidArgumentException $error ) { wp_die( esc_html( $error->getMessage() ), '', array( 'response' => 400, 'back_link' => true ) ); } global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Atomic compare-and-swap prevents lost updates. $affected = $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND BINARY option_value = %s", maybe_serialize( $new ), self::OPTION, maybe_serialize( $old ) ) ); if ( false === $affected ) { wp_die( esc_html__( 'Could not save the contact. Please try again.', 'cardfaro' ), '', array( 'response' => 503, 'back_link' => true ) ); } if ( 1 !== $affected ) { wp_die( esc_html__( 'The contact changed in another tab. Reload before saving.', 'cardfaro' ), '', array( 'response' => 409, 'back_link' => true ) ); } wp_cache_delete( self::OPTION, 'options' ); wp_cache_delete( 'alloptions', 'options' ); wp_cache_delete( 'notoptions', 'options' ); wp_safe_redirect( admin_url( 'admin.php?page=cardfaro&saved=1' ), 303 ); exit; } public static function dispatch(): void { $slug = get_query_var( 'cardfaro_slug' ); if ( ! $slug ) { return; } $record = self::record(); $lang = self::language(); nocache_headers(); header( 'Content-Language: ' . $lang ); header( 'Vary: Accept-Language' ); header( 'X-Robots-Tag: noindex, nofollow' ); header( 'X-Content-Type-Options: nosniff' ); header( 'Referrer-Policy: same-origin' ); if ( $slug !== $record['slug'] || ! $record['published'] ) { status_header( 404 ); wp_die( esc_html__( 'This contact is not available.', 'cardfaro' ), '', array( 'response' => 404 ) ); } $p = self::localized( $record, $lang ); if ( get_query_var( 'cardfaro_vcf' ) ) { header( 'Content-Type: text/vcard; charset=UTF-8' ); header( 'Content-Disposition: attachment; filename="' . $record['slug'] . '-contact.vcf"' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped vCard stream, not HTML. echo Record::vcard( $p ); exit; } $p['photo'] = $p['photo_id'] ? ( wp_get_attachment_image_url( $p['photo_id'], 'medium' ) ?: '' ) : ''; $s = array( 'brand' => $p['brand'], 'logo' => $p['logo_id'] ? ( wp_get_attachment_image_url( $p['logo_id'], 'medium' ) ?: '' ) : '', 'accent' => $p['accent'], 'ink' => $p['ink'], 'privacy' => $p['privacy'], 'legal' => $p['legal'] ); wp_enqueue_style( 'cardfaro-card', plugins_url( 'assets/card.css', self::$file ), array(), self::VERSION ); wp_enqueue_style( 'cardfaro-public', plugins_url( 'assets/public.css', self::$file ), array( 'cardfaro-card' ), self::VERSION ); wp_enqueue_script( 'cardfaro-qr', plugins_url( 'assets/qrcodegen.js', self::$file ), array(), self::VERSION, true ); wp_enqueue_script( 'cardfaro-public', plugins_url( 'assets/public.js', self::$file ), array( 'cardfaro-qr' ), self::VERSION, true ); status_header( 200 ); include __DIR__ . '/../views/public.php'; exit; } }