Files
KGV-FAQ/kgv-faq.php
2026-04-13 22:40:29 +02:00

306 lines
10 KiB
PHP
Executable File

<?php
/**
* Plugin Name: KGV FAQ
* Description: FAQ-Verwaltung mit Fragen, Antworten, Kategorien, sauberem Backend und Shortcode-Ausgabe.
* Version: 1.0.2
* Author: Ronny Grobel
* Author URI: https://apex-project.de/
* Plugin URI: https://apex-project.de/
* Update URI: https://git.apex-project.de/Wordpress_Plugins/KGV-FAQ
* Gitea Plugin URI: https://git.apex-project.de/Wordpress_Plugins/KGV-FAQ
*/
if (!defined('ABSPATH')) {
exit;
}
final class KGV_FAQ_Plugin {
const VERSION = '1.0.0';
const POST_TYPE = 'kgv_faq';
const TAXONOMY = 'kgv_faq_cat';
public function __construct() {
add_action('init', [$this, 'register_post_type']);
add_action('init', [$this, 'register_taxonomy']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']);
add_action('wp_enqueue_scripts', [$this, 'enqueue_front_assets']);
add_filter('manage_' . self::POST_TYPE . '_posts_columns', [$this, 'admin_columns']);
add_action('manage_' . self::POST_TYPE . '_posts_custom_column', [$this, 'admin_column_content'], 10, 2);
add_filter('manage_edit-' . self::POST_TYPE . '_sortable_columns', [$this, 'sortable_columns']);
add_shortcode('kgv_faq', [$this, 'faq_shortcode']);
register_activation_hook(__FILE__, [$this, 'activate']);
register_deactivation_hook(__FILE__, [$this, 'deactivate']);
}
public function activate() {
$this->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 '<div class="kgv-faq-wrapper" data-kgv-faq>';
if ($atts['show_filter'] === '1' && !is_wp_error($terms) && !empty($terms)) {
echo '<form class="kgv-faq-filter" method="get">';
foreach ($_GET as $key => $value) {
if ($key === 'faq_cat' || is_array($value)) {
continue;
}
echo '<input type="hidden" name="' . esc_attr($key) . '" value="' . esc_attr(wp_unslash($value)) . '">';
}
echo '<label for="' . esc_attr($uid . '-cat') . '"><strong>Kategorie:</strong></label> ';
echo '<select id="' . esc_attr($uid . '-cat') . '" name="faq_cat" onchange="this.form.submit()">';
echo '<option value="">Alle Fragen</option>';
foreach ($terms as $term) {
echo '<option value="' . esc_attr($term->slug) . '" ' . selected($selected_category, $term->slug, false) . '>';
echo esc_html($term->name);
echo '</option>';
}
echo '</select>';
echo '</form>';
}
if ($show_search) {
echo '<div class="kgv-faq-search-wrap">';
echo '<input type="search" class="kgv-faq-search" placeholder="Frage suchen …" aria-label="Frage suchen" data-kgv-faq-search>';
echo '</div>';
}
if ($faq_query->have_posts()) {
echo '<div class="kgv-faq-list">';
$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 '<article class="kgv-faq-item" data-kgv-faq-item>';
echo '<h3 class="kgv-faq-question">';
echo '<button type="button" class="kgv-faq-toggle' . ($is_open ? ' is-open' : '') . '" id="' . esc_attr($button_id) . '" aria-expanded="' . ($is_open ? 'true' : 'false') . '" aria-controls="' . esc_attr($panel_id) . '" data-kgv-faq-toggle>';
echo '<span>' . esc_html(get_the_title()) . '</span>';
echo '<span class="kgv-faq-icon" aria-hidden="true">+</span>';
echo '</button>';
echo '</h3>';
echo '<div class="kgv-faq-answer' . ($is_open ? ' is-open' : '') . '" id="' . esc_attr($panel_id) . '" role="region" aria-labelledby="' . esc_attr($button_id) . '"' . ($is_open ? '' : ' hidden') . '>';
echo '<div class="kgv-faq-answer__inner">';
echo wp_kses_post(wpautop(get_the_content()));
echo '</div>';
echo '</div>';
echo '</article>';
$index++;
}
echo '</div>';
wp_reset_postdata();
} else {
echo '<p>Keine Fragen gefunden.</p>';
}
echo '</div>';
return ob_get_clean();
}
}
new KGV_FAQ_Plugin();