commit d36023a4a3ce4324345168cc7798519face55647 Author: Ronny Grobel Date: Sun Apr 12 22:50:16 2026 +0200 Initial plugin commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b6e650 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +Thumbs.db +*.zip diff --git a/assets/admin.css b/assets/admin.css new file mode 100755 index 0000000..f2e232c --- /dev/null +++ b/assets/admin.css @@ -0,0 +1,22 @@ +.post-type-kgv_faq #post-body-content .editor-post-title, +.post-type-kgv_faq #titlediv #title { + font-weight: 600; +} + +.post-type-kgv_faq .misc-pub-section.misc-pub-post-status, +.post-type-kgv_faq .misc-pub-section.curtime { + display: block; +} + +.post-type-kgv_faq .column-kgv_faq_order { + width: 90px; +} + +.post-type-kgv_faq .column-kgv_faq_answer { + width: 35%; +} + +.taxonomy-kgv_faq_cat .wrap h1, +.post-type-kgv_faq .wrap h1 { + margin-bottom: 12px; +} diff --git a/assets/front.css b/assets/front.css new file mode 100755 index 0000000..3ce3b31 --- /dev/null +++ b/assets/front.css @@ -0,0 +1,91 @@ +.kgv-faq-wrapper { + margin: 30px 0; +} + +.kgv-faq-filter { + margin-bottom: 20px; +} + +.kgv-faq-filter select, +.kgv-faq-search { + min-width: 240px; + max-width: 100%; + padding: 10px 12px; + border: 1px solid #d0d7de; + border-radius: 8px; + background: #fff; +} + +.kgv-faq-search-wrap { + margin-bottom: 20px; +} + +.kgv-faq-list { + display: grid; + gap: 14px; +} + +.kgv-faq-item { + border: 1px solid #e5e7eb; + border-radius: 12px; + background: #fff; + overflow: hidden; +} + +.kgv-faq-question { + margin: 0; +} + +.kgv-faq-toggle { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 16px 18px; + background: #fff; + border: 0; + cursor: pointer; + text-align: left; + font-size: 18px; + font-weight: 600; + color: #111827; +} + +.kgv-faq-toggle:hover, +.kgv-faq-toggle:focus { + background: #f9fafb; + outline: none; +} + +.kgv-faq-icon { + flex: 0 0 auto; + font-size: 22px; + line-height: 1; + color: #6b7280; +} + +.kgv-faq-toggle.is-open .kgv-faq-icon { + transform: rotate(45deg); +} + +.kgv-faq-answer { + border-top: 1px solid #eef2f7; +} + +.kgv-faq-answer__inner { + padding: 16px 18px 18px; + color: #374151; +} + +.kgv-faq-answer__inner > *:first-child { + margin-top: 0; +} + +.kgv-faq-answer__inner > *:last-child { + margin-bottom: 0; +} + +.kgv-faq-item.is-hidden { + display: none; +} diff --git a/assets/front.js b/assets/front.js new file mode 100755 index 0000000..bd741d1 --- /dev/null +++ b/assets/front.js @@ -0,0 +1,44 @@ +document.addEventListener('click', function (event) { + const button = event.target.closest('[data-kgv-faq-toggle]'); + if (!button) { + return; + } + + const panelId = button.getAttribute('aria-controls'); + const panel = document.getElementById(panelId); + if (!panel) { + return; + } + + const isOpen = button.getAttribute('aria-expanded') === 'true'; + + button.setAttribute('aria-expanded', isOpen ? 'false' : 'true'); + button.classList.toggle('is-open', !isOpen); + panel.classList.toggle('is-open', !isOpen); + + if (isOpen) { + panel.setAttribute('hidden', ''); + } else { + panel.removeAttribute('hidden'); + } +}); + +document.addEventListener('input', function (event) { + const input = event.target.closest('[data-kgv-faq-search]'); + if (!input) { + return; + } + + const wrapper = input.closest('[data-kgv-faq]'); + if (!wrapper) { + return; + } + + const value = input.value.trim().toLowerCase(); + const items = wrapper.querySelectorAll('[data-kgv-faq-item]'); + + items.forEach(function (item) { + const text = item.textContent.toLowerCase(); + item.classList.toggle('is-hidden', value && !text.includes(value)); + }); +}); diff --git a/kgv-faq.php b/kgv-faq.php new file mode 100755 index 0000000..1d42a36 --- /dev/null +++ b/kgv-faq.php @@ -0,0 +1,303 @@ +register_post_type(); + $this->register_taxonomy(); + flush_rewrite_rules(); + } + + public function deactivate() { + flush_rewrite_rules(); + } + + public function register_post_type() { + register_post_type(self::POST_TYPE, [ + 'labels' => [ + 'name' => 'FAQ', + 'singular_name' => 'FAQ', + 'add_new' => 'Neu hinzufügen', + 'add_new_item' => 'Neue Frage hinzufügen', + 'edit_item' => 'Frage bearbeiten', + 'new_item' => 'Neue Frage', + 'view_item' => 'Frage ansehen', + 'search_items' => 'Fragen durchsuchen', + 'not_found' => 'Keine Fragen gefunden', + 'not_found_in_trash' => 'Keine Fragen im Papierkorb gefunden', + 'menu_name' => 'FAQ', + ], + 'public' => false, + 'publicly_queryable' => false, + 'exclude_from_search' => true, + 'has_archive' => false, + 'rewrite' => false, + 'query_var' => false, + 'show_ui' => true, + 'show_in_menu' => true, + 'show_in_nav_menus' => false, + 'show_in_admin_bar' => true, + 'show_in_rest' => true, + 'menu_icon' => 'dashicons-editor-help', + 'supports' => ['title', 'editor', 'excerpt', 'page-attributes'], + ]); + } + + public function register_taxonomy() { + register_taxonomy(self::TAXONOMY, [self::POST_TYPE], [ + 'labels' => [ + 'name' => 'FAQ-Kategorien', + 'singular_name' => 'FAQ-Kategorie', + 'search_items' => 'Kategorien durchsuchen', + 'all_items' => 'Alle Kategorien', + 'edit_item' => 'Kategorie bearbeiten', + 'update_item' => 'Kategorie aktualisieren', + 'add_new_item' => 'Neue Kategorie hinzufügen', + 'new_item_name' => 'Neuer Kategoriename', + 'menu_name' => 'Kategorien', + ], + 'public' => false, + 'publicly_queryable' => false, + 'hierarchical' => true, + 'show_ui' => true, + 'show_admin_column' => true, + 'rewrite' => false, + 'query_var' => false, + 'show_in_rest' => true, + ]); + } + + public function enqueue_admin_assets($hook) { + global $post_type; + + $allowed = ['post.php', 'post-new.php', 'edit.php', 'term.php', 'edit-tags.php']; + + if (!in_array($hook, $allowed, true)) { + return; + } + + if ($post_type !== self::POST_TYPE && (!isset($_GET['taxonomy']) || sanitize_key(wp_unslash($_GET['taxonomy'])) !== self::TAXONOMY)) { + return; + } + + wp_enqueue_style( + 'kgv-faq-admin', + plugin_dir_url(__FILE__) . 'assets/admin.css', + [], + self::VERSION + ); + } + + public function enqueue_front_assets() { + wp_enqueue_style( + 'kgv-faq-front', + plugin_dir_url(__FILE__) . 'assets/front.css', + [], + self::VERSION + ); + + wp_enqueue_script( + 'kgv-faq-front', + plugin_dir_url(__FILE__) . 'assets/front.js', + [], + self::VERSION, + true + ); + } + + public function admin_columns($columns) { + $new_columns = []; + + foreach ($columns as $key => $label) { + if ($key === 'date') { + continue; + } + + $new_columns[$key] = $label; + + if ($key === 'title') { + $new_columns['kgv_faq_order'] = 'Reihenfolge'; + $new_columns['kgv_faq_answer'] = 'Antwort'; + } + } + + $new_columns['date'] = 'Datum'; + + return $new_columns; + } + + public function admin_column_content($column, $post_id) { + if ($column === 'kgv_faq_order') { + echo (int) get_post_field('menu_order', $post_id); + return; + } + + if ($column === 'kgv_faq_answer') { + $content = get_post_field('post_content', $post_id); + $text = wp_strip_all_tags($content); + $text = mb_substr($text, 0, 120); + echo esc_html($text ? $text . '…' : '—'); + } + } + + public function sortable_columns($columns) { + $columns['kgv_faq_order'] = 'menu_order'; + return $columns; + } + + public function faq_shortcode($atts) { + $atts = shortcode_atts([ + 'category' => '', + 'limit' => 100, + 'show_filter' => '1', + 'open_first' => '0', + 'search' => '0', + ], $atts, 'kgv_faq'); + + $selected_category = ''; + + if (!empty($_GET['faq_cat'])) { + $selected_category = sanitize_title(wp_unslash($_GET['faq_cat'])); + } elseif (!empty($atts['category'])) { + $selected_category = sanitize_title($atts['category']); + } + + $query_args = [ + 'post_type' => self::POST_TYPE, + 'post_status' => 'publish', + 'posts_per_page' => max(1, (int) $atts['limit']), + 'orderby' => ['menu_order' => 'ASC', 'title' => 'ASC'], + 'order' => 'ASC', + ]; + + if ($selected_category) { + $query_args['tax_query'] = [[ + 'taxonomy' => self::TAXONOMY, + 'field' => 'slug', + 'terms' => $selected_category, + ]]; + } + + $faq_query = new WP_Query($query_args); + $terms = get_terms([ + 'taxonomy' => self::TAXONOMY, + 'hide_empty' => true, + ]); + + $uid = wp_unique_id('kgv-faq-'); + $open_first = $atts['open_first'] === '1'; + $show_search = $atts['search'] === '1'; + + ob_start(); + + echo '
'; + + if ($atts['show_filter'] === '1' && !is_wp_error($terms) && !empty($terms)) { + echo '
'; + + foreach ($_GET as $key => $value) { + if ($key === 'faq_cat' || is_array($value)) { + continue; + } + + echo ''; + } + + echo ' '; + echo ''; + echo '
'; + } + + if ($show_search) { + echo '
'; + echo ''; + echo '
'; + } + + if ($faq_query->have_posts()) { + echo '
'; + + $index = 0; + + while ($faq_query->have_posts()) { + $faq_query->the_post(); + + $faq_id = get_the_ID(); + $button_id = $uid . '-button-' . $faq_id; + $panel_id = $uid . '-panel-' . $faq_id; + $is_open = $open_first && $index === 0; + + echo '
'; + echo '

'; + echo ''; + echo '

'; + + echo '
'; + echo '
'; + echo wp_kses_post(wpautop(get_the_content())); + echo '
'; + echo '
'; + + echo '
'; + + $index++; + } + + echo '
'; + wp_reset_postdata(); + } else { + echo '

Keine Fragen gefunden.

'; + } + + echo '
'; + + return ob_get_clean(); + } +} + +new KGV_FAQ_Plugin(); diff --git a/readme.txt b/readme.txt new file mode 100755 index 0000000..9e94a70 --- /dev/null +++ b/readme.txt @@ -0,0 +1,28 @@ +KGV FAQ – WordPress Plugin + +Beschreibung: +KGV FAQ ist ein WordPress-Plugin für einen strukturierten FAQ-Bereich im Backend und die Ausgabe im Frontend per Shortcode. + +Installation: +1. ZIP in WordPress unter `Plugins > Installieren > Plugin hochladen` hochladen +2. Plugin aktivieren +3. Danach einmal `Einstellungen > Permalinks > Speichern` ausführen + +Funktionen: +- eigener FAQ-Bereich im WordPress-Backend +- Fragen als Titel +- Antworten über den Editor +- FAQ-Kategorien +- Reihenfolge über Seitenattribute / Reihenfolge +- Ausgabe im Frontend per Shortcode + +Shortcodes: +- `[kgv_faq]` +- `[kgv_faq category="allgemein"]` +- `[kgv_faq show_filter="0"]` +- `[kgv_faq open_first="1"]` +- `[kgv_faq search="1"]` + +Empfohlene Nutzung: +- eine normale WordPress-Seite `FAQ` anlegen +- dort den Shortcode `[kgv_faq]` einfügen