'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'wp_kses_post', 'auth_callback' => 'skrift_ratgeber_meta_auth', ) ); register_post_meta( 'post', 'cta_ziel', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'esc_url_raw', 'auth_callback' => 'skrift_ratgeber_meta_auth', ) ); register_post_meta( 'post', 'stand_datum', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'skrift_ratgeber_datum', 'auth_callback' => 'skrift_ratgeber_meta_auth', ) ); register_post_meta( 'post', 'faq', array( 'type' => 'array', 'single' => true, 'default' => array(), 'show_in_rest' => array( 'schema' => array( 'type' => 'array', 'items' => array( 'type' => 'object', 'properties' => array( 'frage' => array( 'type' => 'string' ), 'antwort' => array( 'type' => 'string' ), ), 'additionalProperties' => false, ), ), ), 'auth_callback' => 'skrift_ratgeber_meta_auth', ) ); } ); function skrift_ratgeber_datum( $wert ) { return preg_match( '/^\d{4}-\d{2}-\d{2}$/', (string) $wert ) ? $wert : ''; } /* ------------------------------------------------------------------------ * 2. Eingabebox im Beitragseditor (Gutenberg und klassisch) * --------------------------------------------------------------------- */ add_action( 'add_meta_boxes_post', function () { add_meta_box( 'skrift_ratgeber', 'Ratgeber: Kurzantwort, CTA und FAQ', 'skrift_ratgeber_metabox', 'post', 'normal', 'high' ); } ); function skrift_ratgeber_metabox( $post ) { wp_nonce_field( 'skrift_ratgeber_speichern', 'skrift_ratgeber_nonce' ); $kurz = (string) get_post_meta( $post->ID, 'kurzantwort', true ); $cta = (string) get_post_meta( $post->ID, 'cta_ziel', true ); $stand = (string) get_post_meta( $post->ID, 'stand_datum', true ); $faq = get_post_meta( $post->ID, 'faq', true ); if ( ! is_array( $faq ) ) { $faq = array(); } ?>

Zwei bis drei Saetze, Preise nur per [skrift_preis key="..."].

$e ) : ?>
Leere Fragen werden beim Speichern entfernt.
Frage entfernen
$frage, 'antwort' => wp_kses_post( $e['antwort'] ?? '' ), ); } update_post_meta( $post_id, 'faq', $faq ); } ); /* ------------------------------------------------------------------------ * 3. Ausgabe: gemeinsamer Renderer fuer Shortcode und Elementor-Widget * --------------------------------------------------------------------- */ function skrift_faq_eintraege( $post_id = 0 ) { $post_id = $post_id ? (int) $post_id : get_the_ID(); $faq = get_post_meta( $post_id, 'faq', true ); if ( ! is_array( $faq ) ) { return array(); } $raus = array(); foreach ( $faq as $e ) { if ( ! empty( $e['frage'] ) ) { $raus[] = $e; } } return $raus; } function skrift_faq_basis_css() { static $fertig = false; if ( $fertig ) { return ''; } $fertig = true; return ''; } function skrift_faq_schema( $faq ) { $fragen = array(); foreach ( $faq as $e ) { $fragen[] = array( '@type' => 'Question', 'name' => wp_strip_all_tags( $e['frage'] ), 'acceptedAnswer' => array( '@type' => 'Answer', 'text' => wp_strip_all_tags( do_shortcode( $e['antwort'] ?? '' ) ), ), ); } return ''; } function skrift_faq_html( $faq, $args = array() ) { $args = wp_parse_args( $args, array( 'titel' => '', 'titel_tag' => 'h2', 'erste_offen' => false, 'schema' => true, ) ); if ( empty( $faq ) ) { return ''; } $tag = in_array( $args['titel_tag'], array( 'h2', 'h3', 'h4', 'div' ), true ) ? $args['titel_tag'] : 'h2'; $html = skrift_faq_basis_css() . '
'; if ( '' !== $args['titel'] ) { $html .= sprintf( '<%1$s class="skrift-faq__titel">%2$s', $tag, esc_html( $args['titel'] ) ); } foreach ( array_values( $faq ) as $i => $e ) { $offen = ( $args['erste_offen'] && 0 === $i ) ? ' open' : ''; $html .= '
'; $html .= '' . esc_html( $e['frage'] ) . ''; $html .= '
' . wp_kses_post( wpautop( do_shortcode( $e['antwort'] ?? '' ) ) ) . '
'; $html .= '
'; } $html .= '
'; if ( $args['schema'] ) { $html .= skrift_faq_schema( $faq ); } return $html; } function skrift_kurzantwort_html( $post_id = 0 ) { $post_id = $post_id ? (int) $post_id : get_the_ID(); $text = (string) get_post_meta( $post_id, 'kurzantwort', true ); if ( '' === trim( $text ) ) { return ''; } return '
' . wp_kses_post( wpautop( do_shortcode( $text ) ) ) . '
'; } /* Shortcodes, z. B. fuer das Elementor-Shortcode-Widget oder klassische Themes */ add_shortcode( 'skrift_faq', function ( $atts ) { $atts = shortcode_atts( array( 'titel' => '', 'erste_offen' => '0', 'schema' => '1', 'post_id' => 0, ), $atts, 'skrift_faq' ); return skrift_faq_html( skrift_faq_eintraege( $atts['post_id'] ), array( 'titel' => $atts['titel'], 'erste_offen' => '1' === (string) $atts['erste_offen'], 'schema' => '1' === (string) $atts['schema'], ) ); } ); add_shortcode( 'skrift_kurzantwort', function ( $atts ) { $atts = shortcode_atts( array( 'post_id' => 0 ), $atts, 'skrift_kurzantwort' ); return skrift_kurzantwort_html( $atts['post_id'] ); } ); /* ------------------------------------------------------------------------ * 4. Elementor-Widgets: Skrift FAQ und Skrift Kurzantwort * Einmal ins Single-Post-Template (Theme Builder) setzen, dann zeigt * jeder Beitrag automatisch seine eigenen Fragen. * --------------------------------------------------------------------- */ function skrift_elementor_bearbeitungsmodus() { if ( ! class_exists( '\Elementor\Plugin' ) ) { return false; } $e = \Elementor\Plugin::$instance; if ( isset( $e->editor ) && $e->editor->is_edit_mode() ) { return true; } return isset( $e->preview ) && $e->preview->is_preview_mode(); } add_action( 'elementor/widgets/register', function ( $widgets_manager ) { if ( ! class_exists( '\Elementor\Widget_Base' ) ) { return; } if ( ! class_exists( 'Skrift_FAQ_Widget' ) ) { class Skrift_FAQ_Widget extends \Elementor\Widget_Base { public function get_name() { return 'skrift_faq'; } public function get_title() { return 'Skrift FAQ'; } public function get_icon() { return 'eicon-accordion'; } public function get_categories() { return array( 'general' ); } public function get_keywords() { return array( 'faq', 'fragen', 'skrift', 'akkordeon', 'umschalter', 'toggle' ); } protected function register_controls() { $C = '\Elementor\Controls_Manager'; $this->start_controls_section( 'inhalt', array( 'label' => 'Inhalt' ) ); $this->add_control( 'hinweis', array( 'type' => $C::RAW_HTML, 'raw' => 'Fragen und Antworten kommen aus dem Meta-Feld faq des jeweiligen Beitrags.', ) ); $this->add_control( 'titel', array( 'label' => 'Ueberschrift', 'type' => $C::TEXT, 'default' => 'Häufige Fragen', ) ); $this->add_control( 'titel_tag', array( 'label' => 'HTML-Tag der Ueberschrift', 'type' => $C::SELECT, 'default' => 'h2', 'options' => array( 'h2' => 'H2', 'h3' => 'H3', 'h4' => 'H4', 'div' => 'div' ), ) ); $this->add_control( 'erste_offen', array( 'label' => 'Erste Frage geoeffnet', 'type' => $C::SWITCHER, 'default' => '', ) ); $this->add_control( 'schema', array( 'label' => 'FAQ-Schema ausgeben', 'type' => $C::SWITCHER, 'default' => 'yes', ) ); $this->end_controls_section(); $this->start_controls_section( 'stil_titel', array( 'label' => 'Ueberschrift', 'tab' => $C::TAB_STYLE ) ); $this->add_group_control( \Elementor\Group_Control_Typography::get_type(), array( 'name' => 'titel_typo', 'selector' => '{{WRAPPER}} .skrift-faq__titel', ) ); $this->add_control( 'titel_farbe', array( 'label' => 'Farbe', 'type' => $C::COLOR, 'selectors' => array( '{{WRAPPER}} .skrift-faq__titel' => 'color: {{VALUE}};' ), ) ); $this->add_responsive_control( 'titel_abstand', array( 'label' => 'Abstand darunter', 'type' => $C::SLIDER, 'size_units' => array( 'px', 'em' ), 'selectors' => array( '{{WRAPPER}} .skrift-faq__titel' => 'margin-bottom: {{SIZE}}{{UNIT}};' ), ) ); $this->end_controls_section(); $this->start_controls_section( 'stil_frage', array( 'label' => 'Frage', 'tab' => $C::TAB_STYLE ) ); $this->add_group_control( \Elementor\Group_Control_Typography::get_type(), array( 'name' => 'frage_typo', 'selector' => '{{WRAPPER}} .skrift-faq__frage', ) ); $this->add_control( 'frage_farbe', array( 'label' => 'Farbe', 'type' => $C::COLOR, 'selectors' => array( '{{WRAPPER}} .skrift-faq__frage' => 'color: {{VALUE}};' ), ) ); $this->add_control( 'frage_farbe_offen', array( 'label' => 'Farbe geoeffnet', 'type' => $C::COLOR, 'selectors' => array( '{{WRAPPER}} .skrift-faq__eintrag[open] .skrift-faq__frage' => 'color: {{VALUE}};' ), ) ); $this->add_control( 'frage_hintergrund', array( 'label' => 'Hintergrund', 'type' => $C::COLOR, 'selectors' => array( '{{WRAPPER}} .skrift-faq__frage' => 'background-color: {{VALUE}};' ), ) ); $this->add_responsive_control( 'frage_innenabstand', array( 'label' => 'Innenabstand', 'type' => $C::DIMENSIONS, 'size_units' => array( 'px', 'em' ), 'selectors' => array( '{{WRAPPER}} .skrift-faq__frage' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ), ) ); $this->end_controls_section(); $this->start_controls_section( 'stil_antwort', array( 'label' => 'Antwort', 'tab' => $C::TAB_STYLE ) ); $this->add_group_control( \Elementor\Group_Control_Typography::get_type(), array( 'name' => 'antwort_typo', 'selector' => '{{WRAPPER}} .skrift-faq__antwort', ) ); $this->add_control( 'antwort_farbe', array( 'label' => 'Farbe', 'type' => $C::COLOR, 'selectors' => array( '{{WRAPPER}} .skrift-faq__antwort' => 'color: {{VALUE}};' ), ) ); $this->add_responsive_control( 'antwort_innenabstand', array( 'label' => 'Innenabstand', 'type' => $C::DIMENSIONS, 'size_units' => array( 'px', 'em' ), 'selectors' => array( '{{WRAPPER}} .skrift-faq__antwort' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ), ) ); $this->end_controls_section(); $this->start_controls_section( 'stil_eintrag', array( 'label' => 'Eintrag', 'tab' => $C::TAB_STYLE ) ); $this->add_group_control( \Elementor\Group_Control_Border::get_type(), array( 'name' => 'eintrag_rahmen', 'selector' => '{{WRAPPER}} .skrift-faq__eintrag', ) ); $this->add_control( 'eintrag_radius', array( 'label' => 'Eckenradius', 'type' => $C::DIMENSIONS, 'size_units' => array( 'px' ), 'selectors' => array( '{{WRAPPER}} .skrift-faq__eintrag' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}}; overflow: hidden;' ), ) ); $this->add_control( 'eintrag_hintergrund', array( 'label' => 'Hintergrund', 'type' => $C::COLOR, 'selectors' => array( '{{WRAPPER}} .skrift-faq__eintrag' => 'background-color: {{VALUE}};' ), ) ); $this->add_responsive_control( 'eintrag_abstand', array( 'label' => 'Abstand zwischen Eintraegen', 'type' => $C::SLIDER, 'size_units' => array( 'px', 'em' ), 'selectors' => array( '{{WRAPPER}} .skrift-faq__eintrag + .skrift-faq__eintrag' => 'margin-top: {{SIZE}}{{UNIT}};' ), ) ); $this->end_controls_section(); } protected function render() { $s = $this->get_settings_for_display(); $faq = skrift_faq_eintraege(); $bearbeiten = skrift_elementor_bearbeitungsmodus(); // Im Theme-Builder-Template gibt es keinen Beitrag mit FAQ, // deshalb dort Platzhalter zum Gestalten. if ( empty( $faq ) && $bearbeiten ) { $faq = array( array( 'frage' => 'Beispielfrage aus dem Feld faq', 'antwort' => 'Im Beitrag erscheinen hier die Antworten aus dem Meta-Feld faq.' ), array( 'frage' => 'Zweite Beispielfrage', 'antwort' => 'Die Gestaltung legen Sie hier im Widget fest, sie gilt fuer alle Beitraege.' ), array( 'frage' => 'Dritte Beispielfrage', 'antwort' => 'Beitraege ohne FAQ zeigen an dieser Stelle nichts an.' ), ); } echo skrift_faq_html( $faq, array( // phpcs:ignore WordPress.Security.EscapeOutput 'titel' => (string) ( $s['titel'] ?? '' ), 'titel_tag' => (string) ( $s['titel_tag'] ?? 'h2' ), 'erste_offen' => 'yes' === ( $s['erste_offen'] ?? '' ), 'schema' => 'yes' === ( $s['schema'] ?? '' ) && ! $bearbeiten, ) ); } } } if ( ! class_exists( 'Skrift_Kurzantwort_Widget' ) ) { class Skrift_Kurzantwort_Widget extends \Elementor\Widget_Base { public function get_name() { return 'skrift_kurzantwort'; } public function get_title() { return 'Skrift Kurzantwort'; } public function get_icon() { return 'eicon-text'; } public function get_categories() { return array( 'general' ); } public function get_keywords() { return array( 'kurzantwort', 'skrift', 'zusammenfassung', 'box' ); } protected function register_controls() { $C = '\Elementor\Controls_Manager'; $this->start_controls_section( 'inhalt', array( 'label' => 'Inhalt' ) ); $this->add_control( 'hinweis', array( 'type' => $C::RAW_HTML, 'raw' => 'Der Text kommt aus dem Meta-Feld kurzantwort. Preis-Shortcodes darin werden aufgeloest.', ) ); $this->end_controls_section(); $this->start_controls_section( 'stil_box', array( 'label' => 'Box', 'tab' => $C::TAB_STYLE ) ); $this->add_group_control( \Elementor\Group_Control_Typography::get_type(), array( 'name' => 'box_typo', 'selector' => '{{WRAPPER}} .skrift-kurzantwort', ) ); $this->add_control( 'box_farbe', array( 'label' => 'Textfarbe', 'type' => $C::COLOR, 'selectors' => array( '{{WRAPPER}} .skrift-kurzantwort' => 'color: {{VALUE}};' ), ) ); $this->add_control( 'box_hintergrund', array( 'label' => 'Hintergrund', 'type' => $C::COLOR, 'selectors' => array( '{{WRAPPER}} .skrift-kurzantwort' => 'background-color: {{VALUE}};' ), ) ); $this->add_group_control( \Elementor\Group_Control_Border::get_type(), array( 'name' => 'box_rahmen', 'selector' => '{{WRAPPER}} .skrift-kurzantwort', ) ); $this->add_control( 'box_radius', array( 'label' => 'Eckenradius', 'type' => $C::DIMENSIONS, 'size_units' => array( 'px' ), 'selectors' => array( '{{WRAPPER}} .skrift-kurzantwort' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ), ) ); $this->add_responsive_control( 'box_innenabstand', array( 'label' => 'Innenabstand', 'type' => $C::DIMENSIONS, 'size_units' => array( 'px', 'em' ), 'selectors' => array( '{{WRAPPER}} .skrift-kurzantwort' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ), ) ); $this->end_controls_section(); } protected function render() { $html = skrift_kurzantwort_html(); if ( '' === $html && skrift_elementor_bearbeitungsmodus() ) { $html = '

Platzhalter: Hier erscheint die Kurzantwort des jeweiligen Beitrags.

'; } echo $html; // phpcs:ignore WordPress.Security.EscapeOutput } } } $widgets_manager->register( new Skrift_FAQ_Widget() ); $widgets_manager->register( new Skrift_Kurzantwort_Widget() ); } );