post_type === 'aevent') { // Vorschau-Link so umbauen, dass NICHT die Preview-Revision geladen wird // sondern der echte Beitrag mit ?preview=true return add_query_arg('preview', 'true', get_permalink($post->ID)); } return $link; } /** * Registers the metabox for the Aevent post type. * * @return void */ public function register_meta_boxes(): void { add_meta_box( 'aevent_details', __('Event Details', 'one-aeventure'), [$this, 'render_meta_box'], 'aevent', 'normal', 'high' ); } /** * Renders the metabox form fields. * * @param \WP_Post $post The current post object. * @return void */ public function render_meta_box(\WP_Post $post): void { $startMeta = get_post_meta($post->ID, '_aevent_start', true); $start = is_scalar($startMeta) ? (string) $startMeta : ''; $endMeta = get_post_meta($post->ID, '_aevent_end', true); $end = is_scalar($endMeta) ? (string) $endMeta : ''; $locationMeta = get_post_meta($post->ID, '_aevent_location', true); $location = is_scalar($locationMeta) ? (string) $locationMeta : ''; $descriptionMeta = get_post_meta($post->ID, '_aevent_description', true); $description = is_scalar($descriptionMeta) ? (string) $descriptionMeta : ''; wp_nonce_field('aevent_meta_save', 'aevent_meta_nonce'); echo '
'; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo '' . esc_html(__('Use the Featured Image panel on the right to set the event image.', 'one-aeventure')) . '
'; } /** * Saves the meta fields when the post is saved. * * @param int $postId The ID of the post being saved. * @return void */ public function save_meta(int $postId): void { // Autosave? -> abbrechen if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } // Revision? -> abbrechen if (wp_is_post_revision($postId)) { return; } if (!current_user_can('edit_post', $postId)) { return; } $nonce = isset($_POST['aevent_meta_nonce']) ? sanitize_text_field(wp_unslash($_POST['aevent_meta_nonce'])) : ''; if (!wp_verify_nonce($nonce, 'aevent_meta_save')) { return; } remove_action('save_post', [$this, 'save_meta']); // IMMER in den echten Beitrag speichern $this->save_field($postId, 'aevent_start', '_aevent_start'); $this->save_field($postId, 'aevent_end', '_aevent_end'); $this->save_field($postId, 'aevent_location', '_aevent_location'); $this->save_field($postId, 'aevent_description', '_aevent_description'); // IMMER Content für den echten Beitrag generieren $this->generate_post_content($postId); add_action('save_post', [$this, 'save_meta']); } /** * Helper method to sanitize and save a single meta field. * * @param int $postId The post ID. * @param string $inputKey The $_POST key. * @param string $metaKey The meta key to save. * @return void */ private function save_field(int $postId, string $inputKey, string $metaKey): void { $nonce = isset($_POST['aevent_meta_nonce']) ? sanitize_text_field(wp_unslash($_POST['aevent_meta_nonce'])) : ''; if (! wp_verify_nonce($nonce, 'aevent_meta_save')) { return; } if (!isset($_POST[$inputKey])) { return; } // WP-CS: first sanitize and unslash, then use it $rawInput = sanitize_text_field(wp_unslash($_POST[$inputKey])); $raw = is_scalar($rawInput) ? (string) $rawInput : ''; // Description uses textarea sanitization if ($inputKey === 'aevent_description') { $value = sanitize_textarea_field($raw); } else { $value = sanitize_text_field($raw); } update_post_meta($postId, $metaKey, $value); } private function generate_post_content(int $postId): void { $title = get_the_title($postId); $startMeta = get_post_meta($postId, '_aevent_start', true); $start = is_scalar($startMeta) ? (string) $startMeta : ''; $endMeta = get_post_meta($postId, '_aevent_end', true); $end = is_scalar($endMeta) ? (string) $endMeta : ''; $startFormatted = mysql2date( get_option('date_format') . ' ' . get_option('time_format'), $start ); $endFormatted = mysql2date( get_option('date_format') . ' ' . get_option('time_format'), $end ); $locationMeta = get_post_meta($postId, '_aevent_location', true); $location = is_scalar($locationMeta) ? (string) $locationMeta : ''; $descriptionMeta = get_post_meta($postId, '_aevent_description', true); $description = is_scalar($descriptionMeta) ? (string) $descriptionMeta : ''; $imageId = get_post_thumbnail_id($postId); $imageUrl = $imageId !== false ? (string) (wp_get_attachment_url($imageId) ?: '') : ''; $content = $this->build_gutenberg_content($title, $startFormatted, $endFormatted, $location, $description, $imageUrl); // Prevent recursion remove_action('save_post', [$this, 'save_meta']); wp_update_post([ 'ID' => $postId, 'post_content' => $content, ]); // Re-enable hook add_action('save_post', [$this, 'save_meta']); } /** * Builds Gutenberg-compatible block content for the event. * * @param string $title * @param string $start * @param string $end * @param string $location * @param string $description * @param string $imageUrl * @return string */ private function build_gutenberg_content( string $title, string $start, string $end, string $location, string $description, string $imageUrl ): string { $content = '' . esc_html(__('Start:', 'one-aeventure')) . ' ' . esc_html($start) . '
'; $content .= '' . esc_html(__('End:', 'one-aeventure')) . ' ' . esc_html($end) . '
'; $content .= '' . esc_html(__('Location:', 'one-aeventure')) . ' ' . esc_html($location) . '
'; if ($description !== '') { $content .= '' . esc_html($description) . '
'; } $content .= '