3826 lines
189 KiB
PHP
3826 lines
189 KiB
PHP
<?php
|
||
|
||
// Exit if accessed directly.
|
||
if ( ! defined( 'ABSPATH' ) ) {
|
||
exit;
|
||
}
|
||
|
||
// === Theme Setup ===
|
||
function minecraft_modern_setup() {
|
||
add_theme_support( 'title-tag' );
|
||
add_theme_support( 'post-thumbnails' );
|
||
|
||
add_theme_support( 'custom-logo', array(
|
||
'height' => 9999,
|
||
'width' => 9999,
|
||
'flex-height' => true,
|
||
'flex-width' => true,
|
||
'header_text' => array( 'site-title', 'site-description' ),
|
||
) );
|
||
|
||
add_theme_support( 'custom-background' );
|
||
|
||
register_nav_menus( array(
|
||
'primary' => __( 'Hauptmenü', 'minecraft-modern-theme' ),
|
||
'footer' => __( 'Footer-Menü', 'minecraft-modern-theme' ),
|
||
) );
|
||
|
||
// FIX: 'script' und 'style' ergänzt für sauberes HTML5-Output-Format
|
||
add_theme_support( 'html5', array(
|
||
'search-form', 'comment-form', 'comment-list',
|
||
'gallery', 'caption', 'script', 'style',
|
||
) );
|
||
}
|
||
add_action( 'after_setup_theme', 'minecraft_modern_setup' );
|
||
|
||
|
||
// === Styles & Scripts laden ===
|
||
function minecraft_modern_scripts() {
|
||
// Haupt-Stylesheet
|
||
wp_enqueue_style( 'minecraft-modern-style', get_stylesheet_uri(), array(), filemtime( get_stylesheet_directory() . '/style.css' ) );
|
||
|
||
// Swiper.js CSS
|
||
wp_enqueue_style( 'swiper-css', 'https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.css' );
|
||
|
||
// Header-Scroll + Suche Toggle
|
||
wp_enqueue_script(
|
||
'minecraft-modern-header-script',
|
||
get_template_directory_uri() . '/js/header-scroll.js',
|
||
array(),
|
||
filemtime( get_template_directory() . '/js/header-scroll.js' ),
|
||
true
|
||
);
|
||
|
||
// Navigation (Dropdown + Außenklick-Schließen)
|
||
wp_enqueue_script(
|
||
'minecraft-navigation',
|
||
get_template_directory_uri() . '/js/navigation.js',
|
||
array(),
|
||
'1.1',
|
||
true
|
||
);
|
||
|
||
// Swiper.js
|
||
wp_enqueue_script(
|
||
'swiper-js',
|
||
'https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.js',
|
||
array(),
|
||
'8.0.0',
|
||
true
|
||
);
|
||
|
||
// Slider-Init
|
||
wp_enqueue_script(
|
||
'minecraft-modern-slider-script',
|
||
get_template_directory_uri() . '/js/slider-init.js',
|
||
array( 'swiper-js' ),
|
||
'1.1',
|
||
true
|
||
);
|
||
|
||
// Theme Toggle
|
||
wp_enqueue_script(
|
||
'theme-toggle-script',
|
||
get_template_directory_uri() . '/js/theme-toggle.js',
|
||
array(),
|
||
'1.1',
|
||
true
|
||
);
|
||
|
||
// FAQ Skript
|
||
if ( post_type_exists( 'faq' ) ) {
|
||
wp_enqueue_script(
|
||
'faq-accordion-script',
|
||
get_template_directory_uri() . '/js/faq-accordion.js',
|
||
array(),
|
||
'1.0',
|
||
true
|
||
);
|
||
}
|
||
|
||
// FIX: 'loop' ergänzt – war in slider-init.js als sliderSettings.loop referenziert, aber nie übergeben
|
||
wp_localize_script(
|
||
'minecraft-modern-slider-script',
|
||
'sliderSettings',
|
||
array(
|
||
'hideArrows' => get_theme_mod( 'slider_hide_arrows', false ) ? '1' : '0',
|
||
'hidePagination' => get_theme_mod( 'slider_hide_pagination', false ) ? '1' : '0',
|
||
'effect' => get_theme_mod( 'slider_effect', 'fade' ),
|
||
'direction' => get_theme_mod( 'slider_direction', 'horizontal' ),
|
||
'defaultMode' => get_theme_mod( 'default_theme_mode', 'dark' ),
|
||
'loop' => get_theme_mod( 'slider_loop', true ) ? '1' : '0',
|
||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||
)
|
||
);
|
||
|
||
wp_localize_script(
|
||
'minecraft-modern-header-script',
|
||
'headerSettings',
|
||
array(
|
||
'isCustomizer' => is_customize_preview(),
|
||
)
|
||
);
|
||
}
|
||
add_action( 'wp_enqueue_scripts', 'minecraft_modern_scripts' );
|
||
|
||
|
||
// FIX: Scroll-to-Top via Customizer ein-/ausblendbar
|
||
function minecraft_modern_scroll_to_top_css() {
|
||
if ( ! get_theme_mod( 'show_scroll_to_top', true ) ) {
|
||
wp_add_inline_style( 'minecraft-modern-style', '#scroll-to-top { display: none !important; }' );
|
||
}
|
||
}
|
||
add_action( 'wp_enqueue_scripts', 'minecraft_modern_scroll_to_top_css', 25 );
|
||
|
||
|
||
// === Customizer-Datei laden ===
|
||
require get_template_directory() . '/inc/customizer.php';
|
||
|
||
|
||
|
||
|
||
|
||
// =========================================================================
|
||
// INTELLIGENTER SUPPORT-ASSISTENT
|
||
// =========================================================================
|
||
// Ausgelagert in /inc/assistant-widget.php
|
||
require get_template_directory() . '/inc/assistant-widget.php';
|
||
|
||
|
||
// === Theme-Updater-Datei laden ===
|
||
require get_template_directory() . '/inc/theme-updater.php';
|
||
|
||
|
||
// === Footer-Widgets registrieren ===
|
||
function minecraft_modern_footer_widgets() {
|
||
register_sidebar( array(
|
||
'name' => __( 'Footer Links', 'minecraft-modern-theme' ),
|
||
'id' => 'footer-left',
|
||
'description' => __( 'Widget-Bereich links im Footer.', 'minecraft-modern-theme' ),
|
||
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||
'after_widget' => '</div>',
|
||
'before_title' => '<h4 class="widget-title">',
|
||
'after_title' => '</h4>',
|
||
) );
|
||
for ( $i = 1; $i <= 3; $i++ ) {
|
||
register_sidebar( array(
|
||
'name' => sprintf( __( 'Footer Spalte %d', 'minecraft-modern-theme' ), $i ),
|
||
'id' => 'footer-' . $i,
|
||
'description' => sprintf( __( 'Widget für die %d. Spalte im Footer.', 'minecraft-modern-theme' ), $i ),
|
||
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||
'after_widget' => '</div>',
|
||
'before_title' => '<h4 class="widget-title">',
|
||
'after_title' => '</h4>',
|
||
) );
|
||
}
|
||
register_sidebar( array(
|
||
'name' => __( 'Footer Rechts', 'minecraft-modern-theme' ),
|
||
'id' => 'footer-right',
|
||
'description' => __( 'Widget-Bereich rechts im Footer.', 'minecraft-modern-theme' ),
|
||
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||
'after_widget' => '</div>',
|
||
'before_title' => '<h4 class="widget-title">',
|
||
'after_title' => '</h4>',
|
||
) );
|
||
}
|
||
add_action( 'widgets_init', 'minecraft_modern_footer_widgets' );
|
||
|
||
|
||
// === Homepage Sidebar registrieren ===
|
||
function minecraft_modern_homepage_sidebar() {
|
||
register_sidebar( array(
|
||
'name' => __( 'Startseiten Sidebar - Oben', 'minecraft-modern-theme' ),
|
||
'id' => 'homepage-sidebar-top',
|
||
'description' => __( 'Widget-Bereich oben in der Sidebar (z.B. für wichtige Infos).', 'minecraft-modern-theme' ),
|
||
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||
'after_widget' => '</div>',
|
||
'before_title' => '<h3 class="widget-title">',
|
||
'after_title' => '</h3>',
|
||
) );
|
||
register_sidebar( array(
|
||
'name' => __( 'Startseiten Sidebar - Mitte 1', 'minecraft-modern-theme' ),
|
||
'id' => 'homepage-sidebar-middle-1',
|
||
'description' => __( 'Widget-Bereich in der Mitte der Sidebar.', 'minecraft-modern-theme' ),
|
||
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||
'after_widget' => '</div>',
|
||
'before_title' => '<h3 class="widget-title">',
|
||
'after_title' => '</h3>',
|
||
) );
|
||
register_sidebar( array(
|
||
'name' => __( 'Startseiten Sidebar - Mitte 2', 'minecraft-modern-theme' ),
|
||
'id' => 'homepage-sidebar-middle-2',
|
||
'description' => __( 'Zweiter Widget-Bereich in der Mitte der Sidebar.', 'minecraft-modern-theme' ),
|
||
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||
'after_widget' => '</div>',
|
||
'before_title' => '<h3 class="widget-title">',
|
||
'after_title' => '</h3>',
|
||
) );
|
||
register_sidebar( array(
|
||
'name' => __( 'Startseiten Sidebar - Unten', 'minecraft-modern-theme' ),
|
||
'id' => 'homepage-sidebar-bottom',
|
||
'description' => __( 'Widget-Bereich unten in der Sidebar.', 'minecraft-modern-theme' ),
|
||
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||
'after_widget' => '</div>',
|
||
'before_title' => '<h3 class="widget-title">',
|
||
'after_title' => '</h3>',
|
||
) );
|
||
register_sidebar( array(
|
||
'name' => __( 'Startseiten Sidebar - Extra', 'minecraft-modern-theme' ),
|
||
'id' => 'homepage-sidebar-extra',
|
||
'description' => __( 'Zusätzlicher Widget-Bereich für spezielle Inhalte.', 'minecraft-modern-theme' ),
|
||
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||
'after_widget' => '</div>',
|
||
'before_title' => '<h3 class="widget-title">',
|
||
'after_title' => '</h3>',
|
||
) );
|
||
}
|
||
add_action( 'widgets_init', 'minecraft_modern_homepage_sidebar' );
|
||
|
||
|
||
/**
|
||
* Rendert alle Sidebar-Sections der Homepage.
|
||
* Ersetzt den doppelten Sidebar-Code in front-page.php.
|
||
*/
|
||
function minecraft_modern_render_sidebar_sections() {
|
||
$sections = array(
|
||
'homepage-sidebar-top',
|
||
'homepage-sidebar-middle-1',
|
||
'homepage-sidebar-middle-2',
|
||
'homepage-sidebar-bottom',
|
||
'homepage-sidebar-extra',
|
||
);
|
||
$classes = array(
|
||
'homepage-sidebar-top' => 'sidebar-top',
|
||
'homepage-sidebar-middle-1' => 'sidebar-middle-1',
|
||
'homepage-sidebar-middle-2' => 'sidebar-middle-2',
|
||
'homepage-sidebar-bottom' => 'sidebar-bottom',
|
||
'homepage-sidebar-extra' => 'sidebar-extra',
|
||
);
|
||
foreach ( $sections as $sidebar_id ) {
|
||
if ( is_active_sidebar( $sidebar_id ) ) {
|
||
$class = isset( $classes[ $sidebar_id ] ) ? ' ' . $classes[ $sidebar_id ] : '';
|
||
echo '<div class="sidebar-section' . esc_attr( $class ) . '">';
|
||
dynamic_sidebar( $sidebar_id );
|
||
echo '</div>';
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// === FAQ Custom Post Type & Taxonomy ===
|
||
function create_faq_post_type() {
|
||
if ( get_theme_mod( 'faq_enabled', true ) ) {
|
||
register_post_type( 'faq', array(
|
||
'labels' => array(
|
||
'name' => __( 'FAQs', 'minecraft-modern-theme' ),
|
||
'singular_name' => __( 'FAQ', 'minecraft-modern-theme' ),
|
||
'add_new' => __( 'Neue FAQ hinzufügen', 'minecraft-modern-theme' ),
|
||
'add_new_item' => __( 'Neue FAQ hinzufügen', 'minecraft-modern-theme' ),
|
||
'edit_item' => __( 'FAQ bearbeiten', 'minecraft-modern-theme' ),
|
||
'new_item' => __( 'Neue FAQ', 'minecraft-modern-theme' ),
|
||
'view_item' => __( 'FAQ ansehen', 'minecraft-modern-theme' ),
|
||
'search_items' => __( 'FAQs durchsuchen', 'minecraft-modern-theme' ),
|
||
'not_found' => __( 'Keine FAQs gefunden', 'minecraft-modern-theme' ),
|
||
'not_found_in_trash' => __( 'Keine FAQs im Papierkorb gefunden', 'minecraft-modern-theme' ),
|
||
'all_items' => __( 'Alle FAQs', 'minecraft-modern-theme' ),
|
||
),
|
||
'public' => true,
|
||
'has_archive' => true,
|
||
'menu_icon' => 'dashicons-format-chat',
|
||
'supports' => array( 'title', 'editor', 'page-attributes' ),
|
||
'rewrite' => array( 'slug' => 'faq' ),
|
||
'show_in_rest' => true,
|
||
) );
|
||
register_taxonomy( 'faq_category', 'faq', array(
|
||
'label' => __( 'FAQ Kategorien', 'minecraft-modern-theme' ),
|
||
'rewrite' => array( 'slug' => 'faq-kategorie' ),
|
||
'hierarchical' => true,
|
||
'show_in_rest' => true,
|
||
) );
|
||
}
|
||
}
|
||
add_action( 'init', 'create_faq_post_type' );
|
||
|
||
|
||
// =============================================================================
|
||
// Automatische "Home" Seitenerstellung
|
||
// =============================================================================
|
||
|
||
function set_static_front_page_automatically() {
|
||
if ( 'page' !== get_option( 'show_on_front' ) ) {
|
||
$home_page = get_page_by_title( 'Home' );
|
||
if ( ! $home_page ) {
|
||
$home_page_id = wp_insert_post( array(
|
||
'post_title' => 'Home',
|
||
'post_content' => 'Diese Seite dient als statische Startseite.',
|
||
'post_status' => 'publish',
|
||
'post_type' => 'page',
|
||
'post_author' => 1,
|
||
) );
|
||
} else {
|
||
$home_page_id = $home_page->ID;
|
||
}
|
||
if ( $home_page_id ) {
|
||
update_option( 'show_on_front', 'page' );
|
||
update_option( 'page_on_front', $home_page_id );
|
||
}
|
||
}
|
||
}
|
||
add_action( 'after_switch_theme', 'set_static_front_page_automatically' );
|
||
|
||
|
||
function add_home_body_class( $classes ) {
|
||
if ( is_front_page() && ! get_theme_mod( 'show_home_title', true ) ) {
|
||
$classes[] = 'home-title-hidden';
|
||
}
|
||
return $classes;
|
||
}
|
||
add_filter( 'body_class', 'add_home_body_class' );
|
||
|
||
|
||
// =============================================================================
|
||
// FAQ-Seitenerstellung
|
||
// =============================================================================
|
||
|
||
function create_faq_page_automatically() {
|
||
if ( get_theme_mod( 'faq_enabled', true ) && get_page_by_title( 'FAQ' ) == null ) {
|
||
wp_insert_post( array(
|
||
'post_title' => 'FAQ',
|
||
'post_content' => 'Diese Seite zeigt alle FAQs an. Der Inhalt wird automatisch generiert.',
|
||
'post_status' => 'publish',
|
||
'post_type' => 'page',
|
||
'post_author' => 1,
|
||
) );
|
||
}
|
||
}
|
||
add_action( 'customize_save_after', 'create_faq_page_automatically' );
|
||
|
||
|
||
function load_faq_page_template( $template ) {
|
||
if ( get_theme_mod( 'faq_enabled', true ) && is_page() ) {
|
||
global $post;
|
||
if ( $post && $post->post_title === 'FAQ' ) {
|
||
return get_template_directory() . '/archive-faq.php';
|
||
}
|
||
}
|
||
return $template;
|
||
}
|
||
add_filter( 'template_include', 'load_faq_page_template' );
|
||
|
||
|
||
// =========================================================================
|
||
// CUSTOM LOGIN FUNCTIONS
|
||
// =========================================================================
|
||
|
||
function minecraft_modern_login_assets() {
|
||
wp_enqueue_style( 'minecraft-modern-login-style', get_template_directory_uri() . '/css/login-style.css' );
|
||
wp_enqueue_style( 'font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css' );
|
||
|
||
// FIX: login-slider.js – erster Slide sofort sichtbar (fixiert)
|
||
wp_enqueue_script( 'minecraft-avatar-slider-script', get_template_directory_uri() . '/js/login-slider.js', array( 'jquery' ), '1.1', true );
|
||
wp_enqueue_script( 'minecraft-modern-login-script', get_template_directory_uri() . '/js/login-script.js', array( 'jquery' ), '1.0', true );
|
||
|
||
wp_add_inline_script( 'minecraft-modern-login-script', "
|
||
jQuery(document).ready(function($) {
|
||
$('.forgetmenot, #nav').wrapAll('<div class=\"login-options-container\"></div>');
|
||
});
|
||
" );
|
||
|
||
$slider_speed = get_theme_mod( 'login_avatar_slider_speed', 4 );
|
||
wp_localize_script( 'minecraft-avatar-slider-script', 'avatarSliderSettings', array(
|
||
'speed' => $slider_speed * 1000,
|
||
) );
|
||
|
||
$login_bg_image = get_theme_mod( 'login_background_image' );
|
||
if ( $login_bg_image ) {
|
||
wp_add_inline_style( 'minecraft-modern-login-style', "body.login { background-image: url('" . esc_url( $login_bg_image ) . "') !important; }" );
|
||
}
|
||
$logo_url = get_theme_mod( 'login_logo' );
|
||
if ( $logo_url ) {
|
||
wp_add_inline_style( 'minecraft-modern-login-style', ".login h1 a { background-image: url('" . esc_url( $logo_url ) . "') !important; }" );
|
||
}
|
||
}
|
||
add_action( 'login_enqueue_scripts', 'minecraft_modern_login_assets' );
|
||
|
||
|
||
function add_minecraft_avatar_slider_to_login() {
|
||
$avatar_html = '<div id="minecraft-avatar-slider">';
|
||
$has_avatars = false;
|
||
|
||
for ( $i = 1; $i <= 5; $i++ ) {
|
||
$uuid = get_theme_mod( 'login_avatar_uuid_' . $i );
|
||
if ( ! empty( $uuid ) ) {
|
||
$has_avatars = true;
|
||
$avatar_url = 'https://visage.surgeplay.com/full/' . $uuid . '.png';
|
||
// FIX: Klasse wird hier gesetzt, JS überschreibt sie trotzdem (kompatibel)
|
||
$active_class = ( $i === 1 ) ? 'avatar-slide avatar-slide-active' : 'avatar-slide';
|
||
$avatar_html .= '<img class="' . esc_attr( $active_class ) . '" src="' . esc_url( $avatar_url ) . '" alt="Minecraft Avatar ' . $i . '">';
|
||
}
|
||
}
|
||
$avatar_html .= '</div>';
|
||
|
||
if ( $has_avatars ) {
|
||
echo $avatar_html;
|
||
}
|
||
}
|
||
add_action( 'login_form', 'add_minecraft_avatar_slider_to_login' );
|
||
|
||
|
||
function add_post_login_links() {
|
||
?>
|
||
<div class="post-login-links">
|
||
<a href="<?php echo esc_url( home_url() ); ?>">← Zu <?php bloginfo( 'name' ); ?></a>
|
||
</div>
|
||
<?php
|
||
}
|
||
add_action( 'login_form_bottom', 'add_post_login_links' );
|
||
|
||
|
||
function customize_login_page() {
|
||
add_filter( 'login_display_language_dropdown', '__return_false' );
|
||
add_filter( 'login_display_back_to_blog', '__return_false' );
|
||
}
|
||
add_action( 'login_head', 'customize_login_page' );
|
||
|
||
function custom_login_url() { return home_url(); }
|
||
add_filter( 'login_headerurl', 'custom_login_url' );
|
||
|
||
function custom_login_title() { return get_bloginfo( 'name' ); }
|
||
add_filter( 'login_headertext', 'custom_login_title' );
|
||
|
||
|
||
// =========================================================================
|
||
// SCROLL TO TOP BUTTON
|
||
// =========================================================================
|
||
|
||
// FIX: Button wird jetzt im footer.php direkt ausgegeben (kein doppelter Button mehr).
|
||
// Diese Funktion bleibt als Fallback aber deaktiviert, damit es keinen Konflikt gibt.
|
||
// Falls footer.php NICHT angepasst wurde, diese Zeile auskommentieren:
|
||
// add_action( 'wp_footer', 'add_scroll_to_top_button' );
|
||
|
||
function add_scroll_to_top_button() {
|
||
?>
|
||
<a href="#" id="scroll-to-top" aria-label="<?php esc_attr_e( 'Nach oben scrollen', 'minecraft-modern-theme' ); ?>" title="<?php esc_attr_e( 'Nach oben', 'minecraft-modern-theme' ); ?>">
|
||
<i class="fas fa-chevron-up"></i>
|
||
</a>
|
||
<?php
|
||
}
|
||
|
||
function minecraft_modern_scroll_to_top_script() {
|
||
wp_enqueue_script(
|
||
'minecraft-scroll-to-top-script',
|
||
get_template_directory_uri() . '/js/scroll-to-top.js',
|
||
array( 'jquery' ),
|
||
'1.0',
|
||
true
|
||
);
|
||
}
|
||
add_action( 'wp_enqueue_scripts', 'minecraft_modern_scroll_to_top_script' );
|
||
|
||
|
||
// =============================================================================
|
||
// THEME SETTINGS EXPORT / IMPORT
|
||
// =============================================================================
|
||
|
||
add_action( 'admin_post_export_theme_settings', 'handle_theme_settings_export' );
|
||
|
||
function handle_theme_settings_export() {
|
||
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
||
wp_die( __( 'Du hast keine Berechtigung, diese Aktion auszuführen.', 'minecraft-modern-theme' ) );
|
||
}
|
||
|
||
$theme_slug = get_option( 'stylesheet' );
|
||
$data = array(
|
||
'_version' => '3.0',
|
||
'_exported' => date( 'Y-m-d H:i:s' ),
|
||
'_theme' => $theme_slug,
|
||
);
|
||
|
||
// 1. Alle Customizer-Einstellungen (Theme Mods)
|
||
// Enthält: Farben, Slider, Hero, Social Links, Menü-Design, Login-Einstellungen, Sidebar-Einstellungen usw.
|
||
$data['theme_mods'] = get_theme_mods();
|
||
|
||
// 2. Announcement-Bar (gespeichert als wp_options, nicht als Theme Mod)
|
||
$announcement_keys = array(
|
||
'mm_announcement_enabled', 'mm_announcement_text', 'mm_announcement_bg',
|
||
'mm_announcement_color', 'mm_announcement_font_size', 'mm_announcement_font_family',
|
||
'mm_announcement_position', 'mm_announcement_countdown_enabled',
|
||
'mm_announcement_countdown_label', 'mm_announcement_countdown_date',
|
||
'mm_announcement_countdown_expired_msg',
|
||
);
|
||
foreach ( $announcement_keys as $key ) {
|
||
$data['announcement'][ $key ] = get_option( $key );
|
||
}
|
||
|
||
// 3. Widget-Konfigurationen aller Theme-Sidebars
|
||
$theme_sidebars = array(
|
||
'single-post-sidebar',
|
||
'homepage-sidebar-top', 'homepage-sidebar-middle-1',
|
||
'homepage-sidebar-middle-2', 'homepage-sidebar-bottom',
|
||
'homepage-sidebar-extra', 'footer-1', 'footer-2', 'footer-3',
|
||
);
|
||
$all_sidebars = wp_get_sidebars_widgets();
|
||
$widget_data = array();
|
||
foreach ( $theme_sidebars as $sidebar_id ) {
|
||
$widget_data[ $sidebar_id ] = array();
|
||
if ( empty( $all_sidebars[ $sidebar_id ] ) ) continue;
|
||
foreach ( $all_sidebars[ $sidebar_id ] as $widget_id ) {
|
||
if ( ! preg_match( '/^(.+)-(\d+)$/', $widget_id, $m ) ) continue;
|
||
$type = $m[1];
|
||
$index = intval( $m[2] );
|
||
$all = get_option( 'widget_' . $type, array() );
|
||
$widget_data[ $sidebar_id ][] = array(
|
||
'type' => $type,
|
||
'index' => $index,
|
||
'settings' => isset( $all[ $index ] ) ? $all[ $index ] : array(),
|
||
);
|
||
}
|
||
}
|
||
$data['widgets'] = $widget_data;
|
||
|
||
// 4. Team-Mitglieder (mit UUID, Banner, Thumbnail)
|
||
$team_data = array();
|
||
$team_query = new WP_Query( array(
|
||
'post_type' => 'team_member',
|
||
'posts_per_page' => -1,
|
||
'orderby' => 'menu_order',
|
||
'order' => 'ASC',
|
||
) );
|
||
if ( $team_query->have_posts() ) {
|
||
while ( $team_query->have_posts() ) {
|
||
$team_query->the_post();
|
||
$post_id = get_the_ID();
|
||
$team_data[] = array(
|
||
'title' => get_the_title(),
|
||
'content' => get_the_content(),
|
||
'rank' => get_post_meta( $post_id, '_team_member_rank', true ),
|
||
'uuid' => get_post_meta( $post_id, '_team_member_uuid', true ),
|
||
'banner_id' => get_post_meta( $post_id, '_team_member_banner', true ),
|
||
'thumbnail_id' => get_post_thumbnail_id( $post_id ),
|
||
'menu_order' => get_post_field( 'menu_order', $post_id ),
|
||
);
|
||
}
|
||
wp_reset_postdata();
|
||
}
|
||
$data['team'] = $team_data;
|
||
|
||
// 5. FAQ-Einträge (theme-eigener Custom Post Type)
|
||
$faq_data = array();
|
||
$faq_query = new WP_Query( array(
|
||
'post_type' => 'faq',
|
||
'posts_per_page' => -1,
|
||
'orderby' => 'menu_order',
|
||
'order' => 'ASC',
|
||
) );
|
||
if ( $faq_query->have_posts() ) {
|
||
while ( $faq_query->have_posts() ) {
|
||
$faq_query->the_post();
|
||
$terms = wp_get_post_terms( get_the_ID(), 'faq_category', array( 'fields' => 'names' ) );
|
||
$faq_data[] = array(
|
||
'title' => get_the_title(),
|
||
'content' => get_the_content(),
|
||
'menu_order' => get_post_field( 'menu_order', get_the_ID() ),
|
||
'categories' => is_wp_error( $terms ) ? array() : $terms,
|
||
);
|
||
}
|
||
wp_reset_postdata();
|
||
}
|
||
$data['faqs'] = $faq_data;
|
||
|
||
// 6. Custom CSS (Customizer → Zusätzliches CSS)
|
||
$data['custom_css'] = wp_get_custom_css();
|
||
|
||
// 7. Homepage-Seite (falls eingestellt)
|
||
$homepage_id = get_option( 'page_on_front' );
|
||
if ( $homepage_id ) {
|
||
$homepage = get_post( $homepage_id );
|
||
if ( $homepage ) {
|
||
$data['homepage'] = array(
|
||
'title' => $homepage->post_title,
|
||
'content' => $homepage->post_content,
|
||
'excerpt' => $homepage->post_excerpt,
|
||
'featured_img' => get_post_thumbnail_id( $homepage_id ),
|
||
);
|
||
}
|
||
}
|
||
|
||
// 8. Navigation Menüs mit Items
|
||
$nav_menus = array();
|
||
$all_nav_menus = wp_get_nav_menus();
|
||
foreach ( $all_nav_menus as $menu ) {
|
||
$nav_menus[ $menu->slug ] = array(
|
||
'name' => $menu->name,
|
||
'description' => $menu->description,
|
||
'items' => array(),
|
||
);
|
||
$menu_items = wp_get_nav_menu_items( $menu->term_id );
|
||
if ( $menu_items ) {
|
||
foreach ( $menu_items as $item ) {
|
||
$nav_menus[ $menu->slug ]['items'][] = array(
|
||
'title' => $item->title,
|
||
'url' => $item->url,
|
||
'description' => $item->description,
|
||
'type' => $item->type,
|
||
'type_label' => $item->type_label,
|
||
'object' => $item->object,
|
||
'object_id' => $item->object_id,
|
||
'parent' => $item->menu_item_parent,
|
||
'menu_order' => $item->menu_order,
|
||
'target' => get_post_meta( $item->ID, '_menu_item_target', true ),
|
||
'classes' => implode( ' ', (array) $item->classes ),
|
||
'xfn' => get_post_meta( $item->ID, '_menu_item_xfn', true ),
|
||
);
|
||
}
|
||
}
|
||
}
|
||
$data['nav_menus'] = $nav_menus;
|
||
|
||
// 9. Menü-Positionen (welches Menü ist welchem Theme-Location zugewiesen)
|
||
$data['nav_menu_locations'] = get_theme_mod( 'nav_menu_locations', array() );
|
||
|
||
$json = json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );
|
||
header( 'Content-Type: application/json; charset=utf-8' );
|
||
header( 'Content-Disposition: attachment; filename=' . $theme_slug . '-theme-backup-' . date( 'Y-m-d' ) . '.json' );
|
||
header( 'Pragma: no-cache' );
|
||
header( 'Expires: 0' );
|
||
echo $json;
|
||
exit;
|
||
}
|
||
|
||
|
||
add_action( 'wp_ajax_import_theme_settings', 'handle_theme_settings_import' );
|
||
|
||
function handle_theme_settings_import() {
|
||
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
||
wp_send_json_error( __( 'Keine Berechtigung.', 'minecraft-modern-theme' ) );
|
||
}
|
||
check_ajax_referer( 'theme-import-nonce', 'nonce' );
|
||
|
||
if ( empty( $_FILES['import_file']['tmp_name'] ) ) {
|
||
wp_send_json_error( __( 'Keine Datei hochgeladen.', 'minecraft-modern-theme' ) );
|
||
}
|
||
|
||
$json_content = file_get_contents( $_FILES['import_file']['tmp_name'] );
|
||
$data = json_decode( $json_content, true );
|
||
|
||
if ( json_last_error() !== JSON_ERROR_NONE || ! is_array( $data ) ) {
|
||
wp_send_json_error( __( 'Ungültige JSON-Datei.', 'minecraft-modern-theme' ) );
|
||
}
|
||
|
||
$imported = array();
|
||
$version = isset( $data['_version'] ) ? $data['_version'] : '1.0';
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 1. Customizer / Theme Mods
|
||
// -------------------------------------------------------------------------
|
||
$mods = array();
|
||
if ( $version === '3.0' && isset( $data['theme_mods'] ) ) {
|
||
$mods = $data['theme_mods'];
|
||
} elseif ( $version === '2.0' && isset( $data['theme_mods'] ) ) {
|
||
$mods = $data['theme_mods'];
|
||
} else {
|
||
// Altes v1-Format: alles auf oberster Ebene
|
||
$skip = array( '_version', '_exported', '_theme', 'announcement', 'widgets', 'team', 'faqs', 'menus', 'wp_options', 'custom_css', 'team_data' );
|
||
foreach ( $data as $k => $v ) {
|
||
if ( ! in_array( $k, $skip ) ) $mods[ $k ] = $v;
|
||
}
|
||
}
|
||
foreach ( $mods as $key => $value ) {
|
||
set_theme_mod( $key, $value );
|
||
}
|
||
$imported[] = 'Customizer-Einstellungen';
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 2. Announcement-Bar
|
||
// -------------------------------------------------------------------------
|
||
$announcement_keys = array(
|
||
'mm_announcement_enabled', 'mm_announcement_text', 'mm_announcement_bg',
|
||
'mm_announcement_color', 'mm_announcement_font_size', 'mm_announcement_font_family',
|
||
'mm_announcement_position', 'mm_announcement_countdown_enabled',
|
||
'mm_announcement_countdown_label', 'mm_announcement_countdown_date',
|
||
'mm_announcement_countdown_expired_msg',
|
||
);
|
||
$ann = isset( $data['announcement'] ) ? $data['announcement'] : $data;
|
||
foreach ( $announcement_keys as $key ) {
|
||
if ( array_key_exists( $key, $ann ) ) {
|
||
update_option( $key, $ann[ $key ] );
|
||
}
|
||
}
|
||
$imported[] = 'Ankündigung';
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 3. Widgets
|
||
// -------------------------------------------------------------------------
|
||
if ( ! empty( $data['widgets'] ) ) {
|
||
$current_sidebars = get_option( 'sidebars_widgets', array() );
|
||
foreach ( $data['widgets'] as $sidebar_id => $widgets ) {
|
||
$current_sidebars[ $sidebar_id ] = array();
|
||
foreach ( $widgets as $widget ) {
|
||
$type = sanitize_key( $widget['type'] );
|
||
$index = intval( $widget['index'] );
|
||
$all = get_option( 'widget_' . $type, array() );
|
||
$all[ $index ] = $widget['settings'];
|
||
update_option( 'widget_' . $type, $all );
|
||
$current_sidebars[ $sidebar_id ][] = $type . '-' . $index;
|
||
}
|
||
}
|
||
update_option( 'sidebars_widgets', $current_sidebars );
|
||
$imported[] = 'Widgets';
|
||
}
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 4. Team-Mitglieder
|
||
// -------------------------------------------------------------------------
|
||
$team_data = isset( $data['team'] ) ? $data['team'] : ( isset( $data['team_data'] ) ? $data['team_data'] : array() );
|
||
if ( ! empty( $team_data ) ) {
|
||
$existing = new WP_Query( array( 'post_type' => 'team_member', 'posts_per_page' => -1, 'fields' => 'ids' ) );
|
||
if ( $existing->have_posts() ) {
|
||
foreach ( $existing->posts as $pid ) wp_delete_post( $pid, true );
|
||
}
|
||
wp_reset_postdata();
|
||
foreach ( $team_data as $member ) {
|
||
$id = wp_insert_post( array(
|
||
'post_title' => sanitize_text_field( $member['title'] ),
|
||
'post_content' => wp_kses_post( $member['content'] ),
|
||
'post_type' => 'team_member',
|
||
'post_status' => 'publish',
|
||
'menu_order' => intval( isset( $member['menu_order'] ) ? $member['menu_order'] : 0 ),
|
||
) );
|
||
if ( $id && ! is_wp_error( $id ) ) {
|
||
// Rank
|
||
if ( ! empty( $member['rank'] ) ) {
|
||
update_post_meta( $id, '_team_member_rank', sanitize_text_field( $member['rank'] ) );
|
||
}
|
||
// UUID
|
||
if ( ! empty( $member['uuid'] ) ) {
|
||
update_post_meta( $id, '_team_member_uuid', sanitize_text_field( $member['uuid'] ) );
|
||
}
|
||
// Thumbnail
|
||
if ( ! empty( $member['thumbnail_id'] ) ) {
|
||
set_post_thumbnail( $id, intval( $member['thumbnail_id'] ) );
|
||
}
|
||
// Banner
|
||
if ( ! empty( $member['banner_id'] ) ) {
|
||
update_post_meta( $id, '_team_member_banner', intval( $member['banner_id'] ) );
|
||
}
|
||
}
|
||
}
|
||
$imported[] = count( $team_data ) . ' Team-Mitglieder';
|
||
}
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 5. FAQs
|
||
// -------------------------------------------------------------------------
|
||
if ( ! empty( $data['faqs'] ) ) {
|
||
$existing = new WP_Query( array( 'post_type' => 'faq', 'posts_per_page' => -1, 'fields' => 'ids' ) );
|
||
if ( $existing->have_posts() ) {
|
||
foreach ( $existing->posts as $pid ) wp_delete_post( $pid, true );
|
||
}
|
||
wp_reset_postdata();
|
||
foreach ( $data['faqs'] as $faq ) {
|
||
$id = wp_insert_post( array(
|
||
'post_title' => sanitize_text_field( $faq['title'] ),
|
||
'post_content' => wp_kses_post( $faq['content'] ),
|
||
'post_type' => 'faq',
|
||
'post_status' => 'publish',
|
||
'menu_order' => intval( isset( $faq['menu_order'] ) ? $faq['menu_order'] : 0 ),
|
||
) );
|
||
if ( $id && ! is_wp_error( $id ) && ! empty( $faq['categories'] ) ) {
|
||
foreach ( (array) $faq['categories'] as $cat_name ) {
|
||
$term = term_exists( sanitize_text_field( $cat_name ), 'faq_category' );
|
||
if ( ! $term ) {
|
||
$term = wp_insert_term( sanitize_text_field( $cat_name ), 'faq_category' );
|
||
}
|
||
if ( ! is_wp_error( $term ) ) {
|
||
wp_set_post_terms( $id, array( intval( $term['term_id'] ) ), 'faq_category', true );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
$imported[] = count( $data['faqs'] ) . ' FAQs';
|
||
}
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 6. Custom CSS
|
||
// -------------------------------------------------------------------------
|
||
if ( isset( $data['custom_css'] ) && $data['custom_css'] !== '' ) {
|
||
wp_update_custom_css_post( $data['custom_css'] );
|
||
$imported[] = 'Custom CSS';
|
||
}
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 7. Homepage-Seite
|
||
// -------------------------------------------------------------------------
|
||
if ( ! empty( $data['homepage'] ) ) {
|
||
$homepage_id = get_option( 'page_on_front' );
|
||
if ( $homepage_id ) {
|
||
wp_update_post( array(
|
||
'ID' => $homepage_id,
|
||
'post_title' => sanitize_text_field( $data['homepage']['title'] ),
|
||
'post_content' => wp_kses_post( $data['homepage']['content'] ),
|
||
'post_excerpt' => sanitize_textarea_field( $data['homepage']['excerpt'] ),
|
||
) );
|
||
if ( ! empty( $data['homepage']['featured_img'] ) ) {
|
||
set_post_thumbnail( $homepage_id, intval( $data['homepage']['featured_img'] ) );
|
||
}
|
||
$imported[] = 'Homepage-Seite';
|
||
}
|
||
}
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 8. Navigation Menüs mit Items
|
||
// -------------------------------------------------------------------------
|
||
if ( ! empty( $data['nav_menus'] ) ) {
|
||
$menu_id_map = array(); // slug => term_id Mapping für Item-Parent-Zuordnung
|
||
|
||
// Alle existierenden Menüs löschen
|
||
$existing_menus = wp_get_nav_menus();
|
||
foreach ( $existing_menus as $menu ) {
|
||
wp_delete_nav_menu( $menu->term_id );
|
||
}
|
||
|
||
// Neue Menüs und Items importieren
|
||
foreach ( $data['nav_menus'] as $menu_slug => $menu_data ) {
|
||
$new_menu = wp_create_nav_menu( $menu_data['name'] );
|
||
if ( ! is_wp_error( $new_menu ) ) {
|
||
$menu_id_map[ $menu_slug ] = $new_menu;
|
||
|
||
// Items hinzufügen
|
||
if ( ! empty( $menu_data['items'] ) ) {
|
||
$item_id_map = array(); // Altes Item ID => Neues Item ID Mapping
|
||
|
||
// Erste Runde: Root-Items (parent = 0)
|
||
foreach ( $menu_data['items'] as $idx => $item ) {
|
||
if ( empty( $item['parent'] ) || $item['parent'] == 0 ) {
|
||
$item_id = wp_update_nav_menu_item( $new_menu, 0, array(
|
||
'menu-item-title' => sanitize_text_field( $item['title'] ),
|
||
'menu-item-url' => esc_url_raw( $item['url'] ),
|
||
'menu-item-description' => sanitize_text_field( $item['description'] ),
|
||
'menu-item-type' => sanitize_key( $item['type'] ),
|
||
'menu-item-object' => sanitize_key( $item['object'] ),
|
||
'menu-item-object-id' => intval( $item['object_id'] ),
|
||
'menu-item-target' => sanitize_text_field( $item['target'] ),
|
||
'menu-item-classes' => sanitize_text_field( $item['classes'] ),
|
||
'menu-item-xfn' => sanitize_text_field( $item['xfn'] ),
|
||
'menu-item-status' => 'publish',
|
||
) );
|
||
if ( $item_id && ! is_wp_error( $item_id ) ) {
|
||
$item_id_map[ $idx ] = $item_id;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Zweite Runde: Sub-Items (parent > 0)
|
||
foreach ( $menu_data['items'] as $idx => $item ) {
|
||
if ( ! empty( $item['parent'] ) && $item['parent'] > 0 ) {
|
||
$parent_item_id = isset( $item_id_map[ $item['parent'] - 1 ] ) ? $item_id_map[ $item['parent'] - 1 ] : 0;
|
||
$item_id = wp_update_nav_menu_item( $new_menu, 0, array(
|
||
'menu-item-title' => sanitize_text_field( $item['title'] ),
|
||
'menu-item-url' => esc_url_raw( $item['url'] ),
|
||
'menu-item-description' => sanitize_text_field( $item['description'] ),
|
||
'menu-item-type' => sanitize_key( $item['type'] ),
|
||
'menu-item-object' => sanitize_key( $item['object'] ),
|
||
'menu-item-object-id' => intval( $item['object_id'] ),
|
||
'menu-item-parent-id' => $parent_item_id,
|
||
'menu-item-target' => sanitize_text_field( $item['target'] ),
|
||
'menu-item-classes' => sanitize_text_field( $item['classes'] ),
|
||
'menu-item-xfn' => sanitize_text_field( $item['xfn'] ),
|
||
'menu-item-status' => 'publish',
|
||
) );
|
||
if ( $item_id && ! is_wp_error( $item_id ) ) {
|
||
$item_id_map[ $idx ] = $item_id;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
$imported[] = 'Navigation Menüs (' . count( $data['nav_menus'] ) . ')';
|
||
}
|
||
|
||
// -------------------------------------------------------------------------
|
||
// 9. Menü-Positionen
|
||
// -------------------------------------------------------------------------
|
||
if ( ! empty( $data['nav_menu_locations'] ) ) {
|
||
set_theme_mod( 'nav_menu_locations', $data['nav_menu_locations'] );
|
||
$imported[] = 'Menü-Positionen';
|
||
}
|
||
|
||
wp_send_json_success( sprintf(
|
||
__( 'Erfolgreich wiederhergestellt: %s', 'minecraft-modern-theme' ),
|
||
implode( ', ', $imported )
|
||
) );
|
||
}
|
||
|
||
|
||
// =========================================================================
|
||
// ANNOUNCEMENT BAR
|
||
// =========================================================================
|
||
|
||
function mm_announcement_get_font_list() {
|
||
return array(
|
||
'inherit' => array( 'label' => 'Theme-Standard', 'css' => 'inherit', 'google' => false, 'google_name' => '' ),
|
||
'Arial' => array( 'label' => 'Arial', 'css' => 'Arial, Helvetica, sans-serif', 'google' => false, 'google_name' => '' ),
|
||
'Roboto' => array( 'label' => 'Roboto', 'css' => "'Roboto', sans-serif", 'google' => true, 'google_name' => 'Roboto' ),
|
||
'Montserrat' => array( 'label' => 'Montserrat', 'css' => "'Montserrat', sans-serif", 'google' => true, 'google_name' => 'Montserrat' ),
|
||
'Open Sans' => array( 'label' => 'Open Sans', 'css' => "'Open Sans', sans-serif", 'google' => true, 'google_name' => 'Open+Sans' ),
|
||
'Lato' => array( 'label' => 'Lato', 'css' => "'Lato', sans-serif", 'google' => true, 'google_name' => 'Lato' ),
|
||
'Poppins' => array( 'label' => 'Poppins', 'css' => "'Poppins', sans-serif", 'google' => true, 'google_name' => 'Poppins' ),
|
||
'Source Sans Pro' => array( 'label' => 'Source Sans Pro', 'css' => "'Source Sans Pro', sans-serif", 'google' => true, 'google_name' => 'Source+Sans+Pro' ),
|
||
'Noto Sans' => array( 'label' => 'Noto Sans', 'css' => "'Noto Sans', sans-serif", 'google' => true, 'google_name' => 'Noto+Sans' ),
|
||
'Raleway' => array( 'label' => 'Raleway', 'css' => "'Raleway', sans-serif", 'google' => true, 'google_name' => 'Raleway' ),
|
||
'Merriweather' => array( 'label' => 'Merriweather', 'css' => "'Merriweather', serif", 'google' => true, 'google_name' => 'Merriweather' ),
|
||
'Playfair Display' => array( 'label' => 'Playfair Display', 'css' => "'Playfair Display', serif", 'google' => true, 'google_name' => 'Playfair+Display' ),
|
||
'Oswald' => array( 'label' => 'Oswald', 'css' => "'Oswald', sans-serif", 'google' => true, 'google_name' => 'Oswald' ),
|
||
'Rubik' => array( 'label' => 'Rubik', 'css' => "'Rubik', sans-serif", 'google' => true, 'google_name' => 'Rubik' ),
|
||
'Inter' => array( 'label' => 'Inter', 'css' => "'Inter', sans-serif", 'google' => true, 'google_name' => 'Inter' ),
|
||
'Nunito' => array( 'label' => 'Nunito', 'css' => "'Nunito', sans-serif", 'google' => true, 'google_name' => 'Nunito' ),
|
||
'Ubuntu' => array( 'label' => 'Ubuntu', 'css' => "'Ubuntu', sans-serif", 'google' => true, 'google_name' => 'Ubuntu' ),
|
||
'PT Sans' => array( 'label' => 'PT Sans', 'css' => "'PT Sans', sans-serif", 'google' => true, 'google_name' => 'PT+Sans' ),
|
||
'Archivo' => array( 'label' => 'Archivo', 'css' => "'Archivo', sans-serif", 'google' => true, 'google_name' => 'Archivo' ),
|
||
'Fira Sans' => array( 'label' => 'Fira Sans', 'css' => "'Fira Sans', sans-serif", 'google' => true, 'google_name' => 'Fira+Sans' ),
|
||
'Work Sans' => array( 'label' => 'Work Sans', 'css' => "'Work Sans', sans-serif", 'google' => true, 'google_name' => 'Work+Sans' ),
|
||
'Quicksand' => array( 'label' => 'Quicksand', 'css' => "'Quicksand', sans-serif", 'google' => true, 'google_name' => 'Quicksand' ),
|
||
'Karla' => array( 'label' => 'Karla', 'css' => "'Karla', sans-serif", 'google' => true, 'google_name' => 'Karla' ),
|
||
'Dancing Script' => array( 'label' => 'Dancing Script', 'css' => "'Dancing Script', cursive", 'google' => true, 'google_name' => 'Dancing+Script' ),
|
||
'Pacifico' => array( 'label' => 'Pacifico', 'css' => "'Pacifico', cursive", 'google' => true, 'google_name' => 'Pacifico' ),
|
||
'Great Vibes' => array( 'label' => 'Great Vibes', 'css' => "'Great Vibes', cursive", 'google' => true, 'google_name' => 'Great+Vibes' ),
|
||
'Satisfy' => array( 'label' => 'Satisfy', 'css' => "'Satisfy', cursive", 'google' => true, 'google_name' => 'Satisfy' ),
|
||
'Allura' => array( 'label' => 'Allura', 'css' => "'Allura', cursive", 'google' => true, 'google_name' => 'Allura' ),
|
||
'Alex Brush' => array( 'label' => 'Alex Brush', 'css' => "'Alex Brush', cursive", 'google' => true, 'google_name' => 'Alex+Brush' ),
|
||
'Cookie' => array( 'label' => 'Cookie', 'css' => "'Cookie', cursive", 'google' => true, 'google_name' => 'Cookie' ),
|
||
);
|
||
}
|
||
|
||
|
||
function mm_announcement_admin_init() {
|
||
add_menu_page( 'Ankündigung', 'Ankündigung', 'manage_options', 'mm-announcement', 'mm_announcement_admin_page', 'dashicons-megaphone', 61 );
|
||
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_enabled' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_text' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_bg' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_color' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_font_size' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_font_family' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_position' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_countdown_enabled' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_countdown_label' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_countdown_date' );
|
||
register_setting( 'mm_announcement_group', 'mm_announcement_countdown_expired_msg' );
|
||
}
|
||
add_action( 'admin_menu', 'mm_announcement_admin_init' );
|
||
|
||
|
||
function mm_announcement_admin_page() {
|
||
if ( ! current_user_can( 'manage_options' ) ) return;
|
||
|
||
$fonts = mm_announcement_get_font_list();
|
||
$selected_font = get_option( 'mm_announcement_font_family', 'inherit' );
|
||
$selected_size = (int) get_option( 'mm_announcement_font_size', 16 );
|
||
$bg = esc_attr( get_option( 'mm_announcement_bg', '#1e1e1e' ) );
|
||
$color = esc_attr( get_option( 'mm_announcement_color', '#ffffff' ) );
|
||
$text_sample = wp_strip_all_tags( get_option( 'mm_announcement_text' ) ) ?: 'Das ist eine Vorschau: Wie sieht die Schrift aus?';
|
||
?>
|
||
<div class="wrap mm-announcement-admin">
|
||
<h1>Header-Ankündigung</h1>
|
||
<p class="description">Diese Leiste wird auf allen Seiten angezeigt. Die Vorschau unten zeigt sofort, wie die Ankündigung aussieht — Änderungen wirken <strong>direkt in der Vorschau</strong>, erst nach <em>Änderungen speichern</em> werden sie im Frontend übernommen.</p>
|
||
|
||
<form method="post" action="options.php" id="mm-announcement-form">
|
||
<?php settings_fields( 'mm_announcement_group' ); ?>
|
||
|
||
<h2>Allgemein</h2>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th>Aktivieren</th>
|
||
<td>
|
||
<label>
|
||
<input type="checkbox" name="mm_announcement_enabled" value="1" <?php checked( 1, get_option( 'mm_announcement_enabled' ) ); ?>>
|
||
Ankündigung anzeigen
|
||
</label>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<h2>Inhalt</h2>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th style="vertical-align:top;">Text</th>
|
||
<td>
|
||
<?php wp_editor( get_option( 'mm_announcement_text' ), 'mm_announcement_text', array( 'textarea_rows' => 6, 'media_buttons' => false, 'tinymce' => true, 'quicktags' => true ) ); ?>
|
||
|
||
<h3>Verfügbare Icons</h3>
|
||
<p class="description">Klicke auf ein Icon, um es in den Editor einzufügen.</p>
|
||
<div id="mm-announcement-icon-list" style="display:flex;flex-wrap:wrap;gap:10px;margin-bottom:20px;">
|
||
<?php
|
||
$icons = array( '⚡', '‼️', '❗', '✅', '❌', '⭐', '🔥', '💡', '📢', '🎮', '🏆', '🔔', '🎉', '💬', '🛡️' );
|
||
foreach ( $icons as $icon ) {
|
||
echo '<button type="button" class="mm-icon-button" style="font-size:20px;padding:6px 10px;border:1px solid #ccc;border-radius:4px;background:#f7f7f7;cursor:pointer;" title="Klicke zum Einfügen">' . $icon . '</button>';
|
||
}
|
||
?>
|
||
</div>
|
||
<script>
|
||
jQuery(document).ready(function($){
|
||
$('#mm-announcement-icon-list .mm-icon-button').on('click', function(){
|
||
var icon = $(this).text();
|
||
if (typeof tinymce !== 'undefined') {
|
||
var ed = tinymce.get('mm_announcement_text');
|
||
if (ed) { ed.execCommand('mceInsertContent', false, icon); return; }
|
||
}
|
||
var ta = $('#mm_announcement_text'), s = ta[0].selectionStart, e = ta[0].selectionEnd, v = ta.val();
|
||
ta.val(v.substring(0,s) + icon + v.substring(e));
|
||
ta[0].selectionStart = ta[0].selectionEnd = s + icon.length;
|
||
ta.focus();
|
||
});
|
||
});
|
||
</script>
|
||
|
||
<p class="description">HTML erlaubt (z. B. <a>-Links).</p>
|
||
|
||
<div id="mm-announcement-preview" style="background:<?php echo $bg; ?>;color:<?php echo $color; ?>;padding:12px;border-radius:6px;box-shadow:0 1px 4px rgba(0,0,0,.06);margin-top:14px;">
|
||
<div id="mm-announcement-preview-text" style="font-size:<?php echo $selected_size; ?>px;font-family:<?php echo isset( $fonts[ $selected_font ] ) ? esc_attr( $fonts[ $selected_font ]['css'] ) : 'inherit'; ?>;text-align:center;">
|
||
<?php echo esc_html( $text_sample ); ?>
|
||
</div>
|
||
<p style="margin-top:10px;color:#888;font-size:13px;text-align:center;">Live Vorschau</p>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<h2>Position</h2>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th>Anzeigeort</th>
|
||
<td>
|
||
<select name="mm_announcement_position" id="mm-announcement-position">
|
||
<option value="top" <?php selected( get_option( 'mm_announcement_position' ), 'top' ); ?>>Ganz oben (über dem Header)</option>
|
||
<option value="below-header" <?php selected( get_option( 'mm_announcement_position' ), 'below-header' ); ?>>Unter dem Header (Standard)</option>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<h2>Design</h2>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th>Hintergrundfarbe</th>
|
||
<td><input type="color" name="mm_announcement_bg" id="mm-announcement-bg" value="<?php echo $bg; ?>"></td>
|
||
</tr>
|
||
<tr>
|
||
<th>Textfarbe</th>
|
||
<td><input type="color" name="mm_announcement_color" id="mm-announcement-color" value="<?php echo $color; ?>"></td>
|
||
</tr>
|
||
<tr>
|
||
<th>Schriftgröße (px)</th>
|
||
<td><input type="number" min="10" max="48" name="mm_announcement_font_size" id="mm-announcement-size" value="<?php echo $selected_size; ?>"></td>
|
||
</tr>
|
||
<tr>
|
||
<th>Schriftfamilie</th>
|
||
<td>
|
||
<select name="mm_announcement_font_family" id="mm-announcement-font">
|
||
<?php foreach ( $fonts as $key => $f ) : ?>
|
||
<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $selected_font, $key ); ?>><?php echo esc_html( $f['label'] ); ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<h2>Countdown Timer</h2>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th>Countdown aktivieren</th>
|
||
<td><label><input type="checkbox" name="mm_announcement_countdown_enabled" value="1" <?php checked( 1, get_option( 'mm_announcement_countdown_enabled' ) ); ?>> Timer im Banner anzeigen</label></td>
|
||
</tr>
|
||
<tr>
|
||
<th>Label (Text vor Timer)</th>
|
||
<td><input type="text" name="mm_announcement_countdown_label" value="<?php echo esc_attr( get_option( 'mm_announcement_countdown_label', 'Event in:' ) ); ?>" style="width:100%;"></td>
|
||
</tr>
|
||
<tr>
|
||
<th>Zieldatum & Uhrzeit</th>
|
||
<td><input type="datetime-local" name="mm_announcement_countdown_date" value="<?php echo esc_attr( get_option( 'mm_announcement_countdown_date' ) ); ?>"></td>
|
||
</tr>
|
||
<tr>
|
||
<th>Nachricht nach Ablauf</th>
|
||
<td><input type="text" name="mm_announcement_countdown_expired_msg" value="<?php echo esc_attr( get_option( 'mm_announcement_countdown_expired_msg', 'Event läuft gerade!' ) ); ?>" style="width:100%;"></td>
|
||
</tr>
|
||
</table>
|
||
|
||
<?php submit_button( 'Änderungen speichern' ); ?>
|
||
</form>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
|
||
function mm_render_announcement_bar() {
|
||
if ( ! get_option( 'mm_announcement_enabled' ) ) return;
|
||
|
||
$countdown_enabled = get_option( 'mm_announcement_countdown_enabled', false );
|
||
$countdown_label = esc_attr( get_option( 'mm_announcement_countdown_label', 'Event in:' ) );
|
||
$countdown_date = esc_attr( get_option( 'mm_announcement_countdown_date', '' ) );
|
||
$countdown_expired = esc_html( get_option( 'mm_announcement_countdown_expired_msg', 'Event läuft gerade!' ) );
|
||
|
||
$position = esc_attr( get_option( 'mm_announcement_position', 'below-header' ) );
|
||
$bg = esc_attr( get_option( 'mm_announcement_bg', '#1e1e1e' ) );
|
||
$color = esc_attr( get_option( 'mm_announcement_color', '#ffffff' ) );
|
||
$size = (int) get_option( 'mm_announcement_font_size', 16 );
|
||
$font_key = get_option( 'mm_announcement_font_family', 'inherit' );
|
||
$fonts = mm_announcement_get_font_list();
|
||
$font_css = isset( $fonts[ $font_key ] ) ? wp_strip_all_tags( $fonts[ $font_key ]['css'] ) : 'inherit';
|
||
$text_kses = wp_kses_post( get_option( 'mm_announcement_text', '' ) );
|
||
|
||
$countdown_html = '';
|
||
if ( $countdown_enabled && ! empty( $countdown_date ) ) {
|
||
$countdown_html = '<div class="mm-countdown-wrapper" style="display:inline-flex;align-items:center;margin-left:15px;padding-left:15px;border-left:1px solid rgba(255,255,255,0.3);font-weight:bold;">
|
||
<span class="mm-countdown-label">' . $countdown_label . ' </span>
|
||
<span class="mm-countdown-timer" data-date="' . $countdown_date . '" data-expired="' . $countdown_expired . '">Laden...</span>
|
||
</div>';
|
||
}
|
||
?>
|
||
<div id="mm-announcement"
|
||
data-position="<?php echo esc_attr( $position ); ?>"
|
||
style="background:<?php echo esc_attr( $bg ); ?>;color:<?php echo esc_attr( $color ); ?>;font-size:<?php echo esc_attr( $size ); ?>px;font-family:<?php echo esc_attr( $font_css ); ?>;">
|
||
<div class="mm-announcement-inner">
|
||
<div class="mm-announcement-text" style="display:inline-flex;align-items:center;width:100%;justify-content:center;">
|
||
<?php echo $text_kses; ?>
|
||
<?php echo $countdown_html; ?>
|
||
</div>
|
||
<button class="mm-announcement-close" aria-label="<?php esc_attr_e( 'Schließen', 'minecraft-modern-theme' ); ?>">×</button>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
add_action( 'wp_body_open', 'mm_render_announcement_bar' );
|
||
|
||
|
||
function mm_announcement_enqueue_assets() {
|
||
wp_enqueue_style( 'mm-announcement-style', get_template_directory_uri() . '/css/announcement.css', array(), '1.2' );
|
||
wp_enqueue_script( 'mm-announcement-script', get_template_directory_uri() . '/js/announcement.js', array(), '1.4', true );
|
||
|
||
$fonts = mm_announcement_get_font_list();
|
||
$font_key = get_option( 'mm_announcement_font_family', 'inherit' );
|
||
if ( isset( $fonts[ $font_key ] ) && ! empty( $fonts[ $font_key ]['google'] ) && $fonts[ $font_key ]['google_name'] ) {
|
||
$url = 'https://fonts.googleapis.com/css2?family=' . rawurlencode( $fonts[ $font_key ]['google_name'] ) . ':wght@400;700&display=swap';
|
||
wp_enqueue_style( 'mm-announcement-google-font', $url, array(), null );
|
||
}
|
||
}
|
||
add_action( 'wp_enqueue_scripts', 'mm_announcement_enqueue_assets' );
|
||
|
||
|
||
function mm_announcement_admin_assets( $hook ) {
|
||
if ( $hook !== 'toplevel_page_mm-announcement' ) return;
|
||
|
||
wp_add_inline_style( 'wp-admin', '
|
||
.mm-announcement-admin .form-table th { width: 180px; vertical-align: top; }
|
||
.mm-announcement-admin .description { margin-top: 6px; color: #666; max-width: 720px; }
|
||
.mm-announcement-admin h2 { margin-top: 24px; }
|
||
#mm-announcement-preview { transition: all 140ms ease; }
|
||
#mm-announcement-preview-text { transition: font-family 160ms ease, font-size 120ms ease; white-space: normal; word-break: break-word; }
|
||
' );
|
||
|
||
wp_enqueue_script( 'mm-announcement-admin-script', get_template_directory_uri() . '/js/mm-announcement-admin.js', array( 'jquery' ), '1.1', true );
|
||
wp_localize_script( 'mm-announcement-admin-script', 'MM_Announcement_Fonts', mm_announcement_get_font_list() );
|
||
wp_localize_script( 'mm-announcement-admin-script', 'MM_Announcement_Current', array(
|
||
'font' => get_option( 'mm_announcement_font_family', 'inherit' ),
|
||
'size' => (int) get_option( 'mm_announcement_font_size', 16 ),
|
||
'bg' => get_option( 'mm_announcement_bg', '#1e1e1e' ),
|
||
'color' => get_option( 'mm_announcement_color', '#ffffff' ),
|
||
'text' => wp_kses_post( get_option( 'mm_announcement_text' ) ),
|
||
) );
|
||
}
|
||
add_action( 'admin_enqueue_scripts', 'mm_announcement_admin_assets' );
|
||
|
||
|
||
// =========================================================================
|
||
// TEAM MODUL
|
||
// =========================================================================
|
||
|
||
function create_team_post_type() {
|
||
if ( get_theme_mod( 'team_enabled', true ) ) {
|
||
register_post_type( 'team_member', array(
|
||
'labels' => array(
|
||
'name' => __( 'Team', 'minecraft-modern-theme' ),
|
||
'singular_name' => __( 'Teammitglied', 'minecraft-modern-theme' ),
|
||
'add_new' => __( 'Neues Mitglied', 'minecraft-modern-theme' ),
|
||
'menu_name' => __( 'Team', 'minecraft-modern-theme' ),
|
||
),
|
||
'public' => true,
|
||
'has_archive' => true,
|
||
'menu_icon' => 'dashicons-groups',
|
||
'supports' => array( 'title', 'thumbnail', 'page-attributes' ),
|
||
'rewrite' => array( 'slug' => 'team' ),
|
||
'show_in_rest' => true,
|
||
'show_in_menu' => false,
|
||
) );
|
||
}
|
||
}
|
||
add_action( 'init', 'create_team_post_type' );
|
||
|
||
|
||
function add_team_meta_boxes() {
|
||
add_meta_box( 'team_member_rank_box', __( 'Rang & Position', 'minecraft-modern-theme' ), 'team_member_rank_callback', 'team_member', 'side', 'default' );
|
||
}
|
||
add_action( 'add_meta_boxes', 'add_team_meta_boxes' );
|
||
|
||
function team_member_rank_callback( $post ) {
|
||
wp_nonce_field( 'team_member_rank_save', 'team_member_rank_nonce' );
|
||
$value = get_post_meta( $post->ID, '_team_member_rank', true );
|
||
?>
|
||
<p>
|
||
<label for="team_member_rank" style="font-weight:600;">Rang:</label>
|
||
<input type="text" id="team_member_rank" name="team_member_rank" value="<?php echo esc_attr( $value ); ?>" style="width:100%;" placeholder="z.B. Admin, Mod">
|
||
</p>
|
||
<?php
|
||
}
|
||
|
||
function save_team_member_rank( $post_id ) {
|
||
if ( ! isset( $_POST['team_member_rank_nonce'] ) ) return;
|
||
if ( ! wp_verify_nonce( $_POST['team_member_rank_nonce'], 'team_member_rank_save' ) ) return;
|
||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
|
||
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
|
||
if ( isset( $_POST['team_member_rank'] ) ) {
|
||
update_post_meta( $post_id, '_team_member_rank', sanitize_text_field( $_POST['team_member_rank'] ) );
|
||
}
|
||
}
|
||
add_action( 'save_post', 'save_team_member_rank' );
|
||
|
||
|
||
add_action( 'admin_menu', 'register_team_manager_page' );
|
||
function register_team_manager_page() {
|
||
add_menu_page( 'Team Manager', 'Team Manager', 'manage_options', 'mm-team-manager', 'mm_team_manager_page_html', 'dashicons-groups', 6 );
|
||
add_action( 'admin_enqueue_scripts', function( $hook ) {
|
||
if ( $hook === 'toplevel_page_mm-team-manager' ) {
|
||
wp_enqueue_media();
|
||
}
|
||
} );
|
||
}
|
||
|
||
// Breite-Fix nur auf der Team-Manager-Seite
|
||
function mm_team_manager_admin_css() {
|
||
$screen = get_current_screen();
|
||
if ( ! $screen || $screen->id !== 'toplevel_page_mm-team-manager' ) return;
|
||
echo '<style>.toplevel_page_mm-team-manager .card{max-width:100%!important;}.toplevel_page_mm-team-manager #mm-add-member-form{display:grid!important;grid-template-columns:repeat(auto-fit,minmax(250px,1fr))!important;gap:20px!important;}</style>';
|
||
}
|
||
add_action( 'admin_head', 'mm_team_manager_admin_css' );
|
||
|
||
function mm_team_manager_page_html() {
|
||
?>
|
||
<div class="wrap" style="max-width:1200px;">
|
||
<h1>Team Verwaltung</h1>
|
||
<p>Hier kannst du Teammitglieder hinzufügen, sortieren und bearbeiten.</p>
|
||
|
||
<div class="card" style="background:#fff;border:1px solid #ccd0d4;border-left:4px solid #0073aa;padding:20px;margin-bottom:20px;">
|
||
<h2>Neues Mitglied hinzufügen</h2>
|
||
<form id="mm-add-member-form" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px;align-items:start;">
|
||
<div>
|
||
<label for="new_name"><strong>Name:</strong></label><br>
|
||
<input type="text" id="new_name" style="width:100%;" required>
|
||
</div>
|
||
<div>
|
||
<label for="new_rank"><strong>Rang:</strong></label><br>
|
||
<input type="text" id="new_rank" style="width:100%;" placeholder="z.B. Admin, Mod">
|
||
</div>
|
||
<div style="grid-column:1/-1;">
|
||
<label for="new_bio"><strong>Kurzbeschreibung:</strong></label><br>
|
||
<textarea id="new_bio" rows="2" style="width:100%;" placeholder="Kurztext..."></textarea>
|
||
</div>
|
||
|
||
<div style="grid-column:1/-1;display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap;">
|
||
<!-- UUID Feld -->
|
||
<div style="flex:1;min-width:200px;">
|
||
<label for="new_uuid"><strong>Minecraft UUID:</strong></label><br>
|
||
<input type="text" id="new_uuid" style="width:100%;margin-top:4px;" placeholder="z.B. 069a79f4-44e9-4726-a5be-fca90e38aaf5">
|
||
<p style="margin:4px 0 0;color:#666;font-size:12px;">UUID eingeben → Avatar wird automatisch geladen</p>
|
||
</div>
|
||
<!-- ODER Avatar-Bild hochladen -->
|
||
<div style="flex:1;min-width:200px;">
|
||
<label><strong>Oder: Avatar-Bild:</strong></label><br>
|
||
<div style="margin-top:4px;display:flex;align-items:center;gap:10px;">
|
||
<input type="hidden" id="new_image_id" value="">
|
||
<button type="button" class="button mm-upload-btn" data-target="new_image_id">Bild auswählen</button>
|
||
<span id="new_image_name" style="color:#666;font-size:12px;">Kein Bild gewählt</span>
|
||
</div>
|
||
<p style="margin:4px 0 0;color:#666;font-size:12px;">Wird ignoriert wenn UUID gesetzt ist</p>
|
||
</div>
|
||
<!-- Banner-Bild -->
|
||
<div style="flex:1;min-width:200px;">
|
||
<label><strong>Banner-Bild:</strong></label><br>
|
||
<div style="margin-top:4px;display:flex;align-items:center;gap:10px;">
|
||
<input type="hidden" id="new_banner_id" value="">
|
||
<button type="button" class="button mm-upload-btn" data-target="new_banner_id">Banner auswählen</button>
|
||
<span id="new_banner_name" style="color:#666;font-size:12px;">Kein Banner gewählt</span>
|
||
</div>
|
||
<p style="margin:4px 0 0;color:#666;font-size:12px;">Hintergrundbild der Card (optional)</p>
|
||
<div id="new_banner_preview" style="margin-top:8px;width:100%;height:50px;background:#eee;border:1px solid #ccc;border-radius:4px;overflow:hidden;background-size:cover;background-position:center;"></div>
|
||
</div>
|
||
<!-- Avatar Vorschau -->
|
||
<div style="flex:0 0 80px;">
|
||
<label><strong>Vorschau:</strong></label><br>
|
||
<div id="new_image_preview" style="width:80px;height:80px;background:#eee;border:1px solid #ccc;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;margin-top:4px;">
|
||
<span style="color:#999;font-size:11px;">–</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="grid-column:1/-1;">
|
||
<button type="submit" class="button button-primary button-large" style="width:100%;">Hinzufügen</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="card" style="background:#fff;padding:20px;">
|
||
<table class="wp-list-table widefat fixed striped" id="team-table" style="width:100%;table-layout:fixed;">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:60px;">Bild</th>
|
||
<th style="width:18%;">Name</th>
|
||
<th style="width:15%;">Rang</th>
|
||
<th>Bio</th>
|
||
<th style="width:180px;">UUID / Bild</th>
|
||
<th style="width:70px;text-align:center;">Sort.</th>
|
||
<th style="width:100px;text-align:right;">Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="team-list-body">
|
||
<?php
|
||
$team_query = new WP_Query( array( 'post_type' => 'team_member', 'posts_per_page' => -1, 'orderby' => 'menu_order', 'order' => 'ASC' ) );
|
||
if ( $team_query->have_posts() ) :
|
||
while ( $team_query->have_posts() ) : $team_query->the_post();
|
||
$id = get_the_ID();
|
||
$name = get_the_title();
|
||
$rank = get_post_meta( $id, '_team_member_rank', true );
|
||
$bio = get_the_content();
|
||
$uuid = get_post_meta( $id, '_team_member_uuid', true );
|
||
$img_id = get_post_thumbnail_id( $id );
|
||
$banner_id = get_post_meta( $id, '_team_member_banner', true );
|
||
$banner_url = $banner_id ? wp_get_attachment_image_url( $banner_id, 'medium' ) : false;
|
||
|
||
// Avatar anzeigen: UUID > Bild > Placeholder
|
||
if ( $uuid ) {
|
||
$avatar_src = 'https://visage.surgeplay.com/bust/' . esc_attr($uuid) . '.png';
|
||
} elseif ( $img_id ) {
|
||
$avatar_src = wp_get_attachment_image_url( $img_id, array(40,40) );
|
||
} else {
|
||
$avatar_src = false;
|
||
}
|
||
?>
|
||
<tr data-id="<?php echo $id; ?>">
|
||
<td style="text-align:center;vertical-align:middle;">
|
||
<div class="mm-avatar-preview" style="width:40px;height:40px;background:#eee;display:inline-flex;align-items:center;justify-content:center;overflow:hidden;border-radius:4px;border:1px solid #ddd;">
|
||
<?php if ( $avatar_src ) : ?>
|
||
<img src="<?php echo esc_url($avatar_src); ?>" style="width:100%;height:100%;object-fit:cover;">
|
||
<?php else : ?>
|
||
<span style="font-size:20px;">👤</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
</td>
|
||
<td><input type="text" class="inline-edit" data-field="post_title" value="<?php echo esc_attr( $name ); ?>" style="width:100%;box-sizing:border-box;padding:6px;"></td>
|
||
<td><input type="text" class="inline-edit" data-field="_team_member_rank" value="<?php echo esc_attr( $rank ); ?>" style="width:100%;box-sizing:border-box;padding:6px;"></td>
|
||
<td><input type="text" class="inline-edit" data-field="post_content" value="<?php echo esc_attr( wp_strip_all_tags( $bio ) ); ?>" style="width:100%;box-sizing:border-box;padding:6px;"></td>
|
||
<td>
|
||
<input type="text" class="inline-edit uuid-field" data-field="_team_member_uuid"
|
||
value="<?php echo esc_attr( $uuid ); ?>"
|
||
placeholder="UUID oder leer lassen"
|
||
style="width:100%;box-sizing:border-box;padding:6px;font-size:11px;margin-bottom:4px;">
|
||
<div style="display:flex;align-items:center;gap:6px;margin-top:4px;">
|
||
<input type="hidden" class="row-banner-id" value="<?php echo esc_attr( $banner_id ); ?>">
|
||
<button type="button" class="button button-small mm-upload-btn-banner" data-id="<?php echo $id; ?>" style="font-size:11px;">Banner</button>
|
||
<?php if ( $banner_url ) : ?>
|
||
<div style="width:40px;height:20px;border-radius:3px;overflow:hidden;background:url('<?php echo esc_url($banner_url); ?>') center/cover;border:1px solid #ccc;"></div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</td>
|
||
<td style="text-align:center;vertical-align:middle;">
|
||
<button class="button button-small sort-up" title="Nach oben">▲</button>
|
||
<button class="button button-small sort-down" title="Nach unten">▼</button>
|
||
</td>
|
||
<td style="text-align:right;vertical-align:middle;">
|
||
<button class="button button-primary button-small save-row" title="Speichern">💾</button>
|
||
<button class="button button-small delete-row" title="Löschen">🗑️</button>
|
||
</td>
|
||
</tr>
|
||
<?php
|
||
endwhile;
|
||
else :
|
||
echo '<tr><td colspan="7" style="text-align:center;">Noch keine Mitglieder vorhanden.</td></tr>';
|
||
endif;
|
||
?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
jQuery(document).ready(function($) {
|
||
var mediaUploader;
|
||
$(document).on('click', '.mm-upload-btn', function(e) {
|
||
e.preventDefault();
|
||
var targetInput = $(this).data('target');
|
||
var isBanner = (targetInput === 'new_banner_id');
|
||
var uploader = wp.media({ title: isBanner ? 'Banner auswählen' : 'Bild auswählen', button: { text: 'Auswählen' }, multiple: false });
|
||
uploader.on('select', function() {
|
||
var att = uploader.state().get('selection').first().toJSON();
|
||
$('#' + targetInput).val(att.id);
|
||
if (isBanner) {
|
||
$('#new_banner_name').text(att.title);
|
||
var url = att.sizes && att.sizes.medium ? att.sizes.medium.url : att.url;
|
||
$('#new_banner_preview').css({'background-image': 'url(' + url + ')', 'background-size': 'cover', 'background-position': 'center'});
|
||
} else {
|
||
$('#new_image_name').text(att.title);
|
||
var thumb = att.sizes && att.sizes.thumbnail ? att.sizes.thumbnail.url : att.url;
|
||
$('#new_image_preview').html('<img src="' + thumb + '" style="width:100%;height:100%;object-fit:cover;">');
|
||
}
|
||
});
|
||
uploader.open();
|
||
});
|
||
|
||
$('#mm-add-member-form').on('submit', function(e) {
|
||
e.preventDefault();
|
||
var $form = $(this);
|
||
var btn = $form.find('button[type="submit"]').prop('disabled', true).text('Lade...');
|
||
$.ajax({
|
||
url: ajaxurl,
|
||
type: 'POST',
|
||
timeout: 15000,
|
||
data: {
|
||
action: 'mm_add_team_member',
|
||
name: $('#new_name').val(),
|
||
rank: $('#new_rank').val(),
|
||
bio: $('#new_bio').val(),
|
||
img_id: $('#new_image_id').val(),
|
||
uuid: $('#new_uuid').val(),
|
||
banner_id: $('#new_banner_id').val(),
|
||
nonce: '<?php echo wp_create_nonce( 'mm_team_nonce' ); ?>'
|
||
},
|
||
success: function(r) {
|
||
if (r.success) {
|
||
location.reload();
|
||
} else {
|
||
alert('Fehler: ' + r.data);
|
||
btn.prop('disabled', false).text('Hinzufügen');
|
||
}
|
||
},
|
||
error: function(xhr, status) {
|
||
alert('Verbindungsfehler (' + status + '). Bitte erneut versuchen.');
|
||
btn.prop('disabled', false).text('Hinzufügen');
|
||
}
|
||
});
|
||
});
|
||
|
||
// Banner-Upload in Tabellenzeile
|
||
$(document).on('click', '.mm-upload-btn-banner', function() {
|
||
var row = $(this).closest('tr');
|
||
var uploader = wp.media({ title: 'Banner auswählen', button: { text: 'Auswählen' }, multiple: false });
|
||
uploader.on('select', function() {
|
||
var att = uploader.state().get('selection').first().toJSON();
|
||
row.find('.row-banner-id').val(att.id);
|
||
var url = att.sizes && att.sizes.medium ? att.sizes.medium.url : att.url;
|
||
var preview = row.find('.mm-upload-btn-banner').next('div');
|
||
if (preview.length) {
|
||
preview.css({'background-image': 'url('+url+')'});
|
||
} else {
|
||
row.find('.mm-upload-btn-banner').after('<div style="width:40px;height:20px;border-radius:3px;overflow:hidden;background:url('+url+') center/cover;border:1px solid #ccc;display:inline-block;vertical-align:middle;margin-left:4px;"></div>');
|
||
}
|
||
});
|
||
uploader.open();
|
||
});
|
||
var uuidTimer;
|
||
$('#new_uuid').on('input', function() {
|
||
clearTimeout(uuidTimer);
|
||
var uuid = $(this).val().trim();
|
||
var preview = $('#new_image_preview');
|
||
if (!uuid) {
|
||
preview.html('<span style="color:#999;font-size:11px;">–</span>');
|
||
return;
|
||
}
|
||
uuidTimer = setTimeout(function() {
|
||
var url = 'https://visage.surgeplay.com/bust/' + uuid + '.png';
|
||
preview.html('<img src="' + url + '" style="width:100%;height:100%;object-fit:cover;" onerror="this.parentNode.innerHTML=\'<span style=color:#c00;font-size:11px>Ungültig</span>\'" />');
|
||
}, 600);
|
||
});
|
||
|
||
$('.save-row').on('click', function() {
|
||
var row = $(this).closest('tr'), btn = $(this);
|
||
var data = { action: 'mm_update_team_member', id: row.data('id'), nonce: '<?php echo wp_create_nonce( 'mm_team_nonce' ); ?>' };
|
||
row.find('.inline-edit').each(function() {
|
||
var f = $(this).data('field'), v = $(this).val();
|
||
if (f === 'post_title') data.title = v;
|
||
if (f === '_team_member_rank') data.rank = v;
|
||
if (f === 'post_content') data.bio = v;
|
||
if (f === '_team_member_uuid') data.uuid = v;
|
||
});
|
||
// Bild-ID falls vorhanden
|
||
var imgInput = row.find('.row-img-id');
|
||
if (imgInput.length) data.img_id = imgInput.val();
|
||
// Banner-ID
|
||
var bannerInput = row.find('.row-banner-id');
|
||
if (bannerInput.length) data.banner_id = bannerInput.val();
|
||
|
||
btn.text('✓').prop('disabled', true);
|
||
$.post(ajaxurl, data, function(r) {
|
||
// Avatar live aktualisieren
|
||
if (data.uuid) {
|
||
var url = 'https://visage.surgeplay.com/bust/' + data.uuid + '.png';
|
||
row.find('.mm-avatar-preview').html('<img src="' + url + '" style="width:100%;height:100%;object-fit:cover;">');
|
||
}
|
||
setTimeout(function(){ btn.text('💾').prop('disabled', false); }, 1000);
|
||
});
|
||
});
|
||
|
||
$('.delete-row').on('click', function() {
|
||
if (!confirm('Löschen?')) return;
|
||
var row = $(this).closest('tr');
|
||
$.post(ajaxurl, { action: 'mm_delete_team_member', id: row.data('id'), nonce: '<?php echo wp_create_nonce( 'mm_team_nonce' ); ?>' }, function() { row.fadeOut().remove(); });
|
||
});
|
||
|
||
$('.sort-up').on('click', function() { var r = $(this).closest('tr'), p = r.prev('tr'); if (p.length) r.insertBefore(p); });
|
||
$('.sort-down').on('click', function() { var r = $(this).closest('tr'), n = r.next('tr'); if (n.length) r.insertAfter(n); });
|
||
});
|
||
</script>
|
||
<?php
|
||
}
|
||
|
||
|
||
add_action( 'wp_ajax_mm_add_team_member', 'handle_mm_add_member' );
|
||
function handle_mm_add_member() {
|
||
check_ajax_referer( 'mm_team_nonce', 'nonce' );
|
||
if ( ! current_user_can( 'publish_posts' ) ) wp_send_json_error( 'Keine Berechtigung' );
|
||
|
||
$id = wp_insert_post( array(
|
||
'post_title' => sanitize_text_field( $_POST['name'] ),
|
||
'post_content' => sanitize_textarea_field( $_POST['bio'] ),
|
||
'post_type' => 'team_member',
|
||
'post_status' => 'publish',
|
||
'menu_order' => 999,
|
||
) );
|
||
|
||
if ( ! $id || is_wp_error( $id ) ) {
|
||
wp_send_json_error( 'Fehler beim Erstellen' );
|
||
}
|
||
|
||
update_post_meta( $id, '_team_member_rank', sanitize_text_field( $_POST['rank'] ) );
|
||
|
||
// UUID speichern (kein externer Request hier – nur als Text speichern)
|
||
if ( ! empty( $_POST['uuid'] ) ) {
|
||
$uuid = sanitize_text_field( trim( $_POST['uuid'] ) );
|
||
update_post_meta( $id, '_team_member_uuid', $uuid );
|
||
} elseif ( ! empty( $_POST['img_id'] ) ) {
|
||
set_post_thumbnail( $id, intval( $_POST['img_id'] ) );
|
||
}
|
||
|
||
// Banner-Bild speichern
|
||
if ( ! empty( $_POST['banner_id'] ) ) {
|
||
update_post_meta( $id, '_team_member_banner', intval( $_POST['banner_id'] ) );
|
||
}
|
||
|
||
wp_send_json_success( array( 'id' => $id, 'msg' => 'Hinzugefügt' ) );
|
||
}
|
||
|
||
add_action( 'wp_ajax_mm_update_team_member', 'handle_mm_update_team_member' );
|
||
function handle_mm_update_team_member() {
|
||
check_ajax_referer( 'mm_team_nonce', 'nonce' );
|
||
if ( ! current_user_can( 'edit_posts' ) ) wp_send_json_error( 'Keine Berechtigung' );
|
||
$id = intval( $_POST['id'] );
|
||
wp_update_post( array(
|
||
'ID' => $id,
|
||
'post_title' => sanitize_text_field( $_POST['title'] ),
|
||
'post_content' => sanitize_textarea_field( $_POST['bio'] ),
|
||
) );
|
||
update_post_meta( $id, '_team_member_rank', sanitize_text_field( $_POST['rank'] ) );
|
||
// UUID speichern oder löschen
|
||
if ( isset( $_POST['uuid'] ) ) {
|
||
$uuid = sanitize_text_field( trim( $_POST['uuid'] ) );
|
||
if ( $uuid ) {
|
||
update_post_meta( $id, '_team_member_uuid', $uuid );
|
||
} else {
|
||
delete_post_meta( $id, '_team_member_uuid' );
|
||
}
|
||
}
|
||
// Bild nur setzen wenn keine UUID
|
||
if ( empty( $_POST['uuid'] ) && ! empty( $_POST['img_id'] ) ) {
|
||
set_post_thumbnail( $id, intval( $_POST['img_id'] ) );
|
||
}
|
||
// Banner speichern
|
||
if ( isset( $_POST['banner_id'] ) ) {
|
||
if ( ! empty( $_POST['banner_id'] ) ) {
|
||
update_post_meta( $id, '_team_member_banner', intval( $_POST['banner_id'] ) );
|
||
}
|
||
}
|
||
wp_send_json_success( 'Gespeichert' );
|
||
}
|
||
|
||
add_action( 'wp_ajax_mm_delete_team_member', 'handle_mm_delete_team_member' );
|
||
function handle_mm_delete_team_member() {
|
||
check_ajax_referer( 'mm_team_nonce', 'nonce' );
|
||
if ( ! current_user_can( 'delete_posts' ) ) wp_send_json_error( 'Keine Berechtigung' );
|
||
wp_delete_post( intval( $_POST['id'] ), true );
|
||
wp_send_json_success( 'Gelöscht' );
|
||
}
|
||
|
||
|
||
function create_team_page_automatically() {
|
||
if ( get_theme_mod( 'team_enabled', true ) && get_page_by_title( 'Team' ) == null ) {
|
||
wp_insert_post( array( 'post_title' => 'Team', 'post_status' => 'publish', 'post_type' => 'page', 'post_author' => 1 ) );
|
||
}
|
||
}
|
||
add_action( 'customize_save_after', 'create_team_page_automatically' );
|
||
|
||
|
||
function load_team_page_template( $template ) {
|
||
if ( ! get_theme_mod( 'team_enabled', true ) ) return $template;
|
||
if ( is_post_type_archive( 'team_member' ) ) return get_template_directory() . '/archive-team.php';
|
||
if ( is_page() ) {
|
||
$obj = get_queried_object();
|
||
if ( $obj && $obj->post_name === 'team' ) return get_template_directory() . '/archive-team.php';
|
||
}
|
||
return $template;
|
||
}
|
||
add_filter( 'template_include', 'load_team_page_template' );
|
||
|
||
|
||
// Doppelte team_customize_register entfernt – ist jetzt in inc/customizer.php
|
||
|
||
// =========================================================================
|
||
// MENÜ-LAYOUTS: Hilfsfunktionen für header.php
|
||
// =========================================================================
|
||
|
||
if ( ! function_exists('mm_branding') ) :
|
||
function mm_branding( $show_title_with_logo = false ) { ?>
|
||
<div class="site-branding">
|
||
<?php if ( function_exists('the_custom_logo') && has_custom_logo() ) : ?>
|
||
<?php the_custom_logo(); ?>
|
||
<?php if ( $show_title_with_logo ) : ?>
|
||
<p class="site-title">
|
||
<a href="<?php echo esc_url( home_url('/') ); ?>" rel="home"><?php bloginfo('name'); ?></a>
|
||
</p>
|
||
<?php endif; ?>
|
||
<?php else : ?>
|
||
<?php if ( is_front_page() && is_home() ) : ?>
|
||
<h1 class="site-title"><a href="<?php echo esc_url( home_url('/') ); ?>" rel="home"><?php bloginfo('name'); ?></a></h1>
|
||
<?php else : ?>
|
||
<p class="site-title"><a href="<?php echo esc_url( home_url('/') ); ?>" rel="home"><?php bloginfo('name'); ?></a></p>
|
||
<?php endif; ?>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php }
|
||
endif;
|
||
|
||
if ( ! function_exists('mm_nav') ) :
|
||
function mm_nav( $extra_class = '' ) {
|
||
$menu_style = get_theme_mod( 'header_menu_style', 'classic' );
|
||
?>
|
||
<nav id="site-navigation" class="main-navigation <?php echo esc_attr($extra_class); ?>" role="navigation"
|
||
aria-label="<?php esc_attr_e('Hauptmenü', 'minecraft-modern-theme'); ?>">
|
||
<?php
|
||
// BUG-FIX: .menu-toggle nur für Classic / Centered / Mega ausgeben.
|
||
// Im Sidebar-Layout sitzt die Navigation im <aside> Panel –
|
||
// der Hamburger wird dort nicht gebraucht und verursacht JS-Konflikte.
|
||
if ( $menu_style !== 'sidebar' ) : ?>
|
||
<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false">
|
||
<i class="fas fa-bars"></i>
|
||
</button>
|
||
<?php endif; ?>
|
||
<?php wp_nav_menu( array(
|
||
'theme_location' => 'primary',
|
||
'container' => false,
|
||
'menu_class' => 'primary-menu',
|
||
'fallback_cb' => false,
|
||
) ); ?>
|
||
</nav>
|
||
<?php }
|
||
endif;
|
||
|
||
if ( ! function_exists('mm_icons') ) :
|
||
function mm_icons() {
|
||
$social_icons = array(
|
||
'bluesky' => 'fab fa-bluesky', 'discord' => 'fab fa-discord', 'youtube' => 'fab fa-youtube',
|
||
'twitter' => 'fab fa-x-twitter', 'facebook' => 'fab fa-facebook-f',
|
||
'instagram' => 'fab fa-instagram', 'tiktok' => 'fab fa-tiktok',
|
||
'twitch' => 'fab fa-twitch', 'steam' => 'fab fa-steam',
|
||
'github' => 'fab fa-github', 'linkedin' => 'fab fa-linkedin-in',
|
||
'pinterest' => 'fab fa-pinterest-p', 'reddit' => 'fab fa-reddit-alien',
|
||
'mastodon' => 'fab fa-mastodon', 'threads' => 'fab fa-threads',
|
||
'kickstarter' => 'fab fa-kickstarter', 'teamspeak' => 'fab fa-teamspeak', 'spotify' => 'fab fa-spotify',
|
||
'stoat' => 'fab fa-diaspora',
|
||
); ?>
|
||
<div class="header-info">
|
||
<div class="header-search">
|
||
<button class="header-search-toggle" aria-label="<?php esc_attr_e('Suche öffnen', 'minecraft-modern-theme'); ?>" aria-expanded="false">
|
||
<i class="fas fa-search"></i>
|
||
</button>
|
||
<div class="header-search-dropdown" aria-hidden="true">
|
||
<?php get_search_form(); ?>
|
||
</div>
|
||
</div>
|
||
<div class="social-links">
|
||
<?php foreach ( $social_icons as $key => $class ) :
|
||
$url = get_theme_mod( 'social_' . $key );
|
||
if ( $url ) echo '<a href="' . esc_url($url) . '" target="_blank" rel="noopener noreferrer" aria-label="' . esc_attr($key) . '"><i class="' . esc_attr($class) . '"></i></a>';
|
||
endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
endif;
|
||
|
||
|
||
// === Menü-Design Customizer-Einstellung ===
|
||
function minecraft_modern_menu_style_customizer( $wp_customize ) {
|
||
$wp_customize->add_section( 'header_menu_style_section', array(
|
||
'title' => __( 'Menü-Design', 'minecraft-modern-theme' ),
|
||
'priority' => 30,
|
||
) );
|
||
$wp_customize->add_setting( 'header_menu_style', array(
|
||
'default' => 'classic',
|
||
'sanitize_callback' => 'sanitize_text_field',
|
||
'transport' => 'refresh',
|
||
) );
|
||
$wp_customize->add_control( 'header_menu_style', array(
|
||
'label' => __( 'Menü-Layout wählen', 'minecraft-modern-theme' ),
|
||
'section' => 'header_menu_style_section',
|
||
'type' => 'select',
|
||
'choices' => array(
|
||
'classic' => __( '① Classic – Logo links, Menü Mitte, Icons rechts', 'minecraft-modern-theme' ),
|
||
'centered' => __( '② Zentriert – Logo oben, Menü darunter', 'minecraft-modern-theme' ),
|
||
'sidebar' => __( '③ Sidebar – Menü als vertikale Leiste', 'minecraft-modern-theme' ),
|
||
'mega' => __( '④ Mega-Menü – breite Dropdown-Spalten', 'minecraft-modern-theme' ),
|
||
),
|
||
) );
|
||
|
||
// Branding-Position (gilt für alle Layouts)
|
||
$wp_customize->add_setting( 'sidebar_branding_position', array(
|
||
'default' => 'left',
|
||
'sanitize_callback' => 'sanitize_text_field',
|
||
'transport' => 'refresh',
|
||
) );
|
||
$wp_customize->add_control( 'sidebar_branding_position', array(
|
||
'label' => __( 'Logo/Titel Position', 'minecraft-modern-theme' ),
|
||
'description' => __( 'Gilt für alle Menü-Layouts.', 'minecraft-modern-theme' ),
|
||
'section' => 'header_menu_style_section',
|
||
'type' => 'select',
|
||
'choices' => array(
|
||
'left' => __( 'Links', 'minecraft-modern-theme' ),
|
||
'center' => __( 'Mitte', 'minecraft-modern-theme' ),
|
||
'right' => __( 'Rechts', 'minecraft-modern-theme' ),
|
||
),
|
||
) );
|
||
}
|
||
add_action( 'customize_register', 'minecraft_modern_menu_style_customizer' );
|
||
|
||
|
||
// === Sidebar-Menü JavaScript (nur wenn Sidebar-Layout aktiv) ===
|
||
function minecraft_modern_sidebar_menu_script() {
|
||
if ( get_theme_mod( 'header_menu_style', 'classic' ) !== 'sidebar' ) return;
|
||
?>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
var toggle = document.querySelector('.sidebar-menu-toggle');
|
||
var sidebar = document.getElementById('header-sidebar');
|
||
var closeBtn = document.querySelector('.sidebar-menu-close');
|
||
|
||
// BUG-FIX: Overlay NICHT mehr per JS erstellen.
|
||
// header.php gibt bereits <div id="sidebar-overlay"> aus.
|
||
// Das alte createElement() erzeugte ein ZWEITES Overlay-Div,
|
||
// was zu doppelten Klick-Handlern und visuellem Flickern führte.
|
||
var overlay = document.getElementById('sidebar-overlay');
|
||
|
||
if (!toggle || !sidebar) return;
|
||
|
||
function openSidebar() {
|
||
sidebar.classList.add('is-open');
|
||
sidebar.setAttribute('aria-hidden', 'false');
|
||
toggle.setAttribute('aria-expanded', 'true');
|
||
if (overlay) overlay.classList.add('is-visible');
|
||
document.body.classList.add('sidebar-nav-open');
|
||
}
|
||
function closeSidebar() {
|
||
sidebar.classList.remove('is-open');
|
||
sidebar.setAttribute('aria-hidden', 'true');
|
||
toggle.setAttribute('aria-expanded', 'false');
|
||
if (overlay) overlay.classList.remove('is-visible');
|
||
document.body.classList.remove('sidebar-nav-open');
|
||
}
|
||
|
||
toggle.addEventListener('click', openSidebar);
|
||
if (closeBtn) closeBtn.addEventListener('click', closeSidebar);
|
||
if (overlay) overlay.addEventListener('click', closeSidebar);
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') closeSidebar();
|
||
});
|
||
});
|
||
</script>
|
||
<?php
|
||
}
|
||
add_action( 'wp_footer', 'minecraft_modern_sidebar_menu_script' );
|
||
|
||
|
||
// Such-Toggle wird von header-scroll.js behandelt.
|
||
|
||
|
||
// === Single-Post Sidebar registrieren ===
|
||
function minecraft_modern_single_sidebar() {
|
||
register_sidebar( array(
|
||
'name' => __( 'Beitrag Sidebar', 'minecraft-modern-theme' ),
|
||
'id' => 'single-post-sidebar',
|
||
'description' => __( 'Widget-Bereich für die Sidebar auf Einzelbeitrags-Seiten.', 'minecraft-modern-theme' ),
|
||
'before_widget' => '<div id="%1$s" class="widget %2$s sidebar-widget">',
|
||
'after_widget' => '</div>',
|
||
'before_title' => '<h3 class="widget-title">',
|
||
'after_title' => '</h3>',
|
||
) );
|
||
}
|
||
add_action( 'widgets_init', 'minecraft_modern_single_sidebar' );
|
||
|
||
|
||
// === Single-Post Sidebar Render-Funktion ===
|
||
function minecraft_modern_render_single_sidebar() {
|
||
if ( is_active_sidebar( 'single-post-sidebar' ) ) {
|
||
dynamic_sidebar( 'single-post-sidebar' );
|
||
} else {
|
||
?>
|
||
<div class="sidebar-widget widget_search">
|
||
<h3 class="widget-title"><?php _e('Suche', 'minecraft-modern-theme'); ?></h3>
|
||
<?php get_search_form(); ?>
|
||
</div>
|
||
<div class="sidebar-widget widget_recent_entries">
|
||
<h3 class="widget-title"><?php _e('Letzte Beiträge', 'minecraft-modern-theme'); ?></h3>
|
||
<?php $recent = new WP_Query( array( 'posts_per_page' => 5, 'post_status' => 'publish' ) );
|
||
if ( $recent->have_posts() ) : ?>
|
||
<ul class="sidebar-recent-posts">
|
||
<?php while ( $recent->have_posts() ) : $recent->the_post(); ?>
|
||
<li>
|
||
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||
<span class="sidebar-post-date"><i class="fas fa-calendar-alt"></i> <?php echo esc_html( get_the_date() ); ?></span>
|
||
</li>
|
||
<?php endwhile; wp_reset_postdata(); ?>
|
||
</ul>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="sidebar-widget widget_categories">
|
||
<h3 class="widget-title"><?php _e('Kategorien', 'minecraft-modern-theme'); ?></h3>
|
||
<ul class="sidebar-categories">
|
||
<?php wp_list_categories( array( 'show_count' => true, 'title_li' => '', 'orderby' => 'count', 'order' => 'DESC', 'number' => 10 ) ); ?>
|
||
</ul>
|
||
</div>
|
||
<div class="sidebar-widget widget_tag_cloud">
|
||
<h3 class="widget-title"><?php _e('Schlagwörter', 'minecraft-modern-theme'); ?></h3>
|
||
<?php wp_tag_cloud( array( 'smallest' => 11, 'largest' => 16, 'unit' => 'px', 'number' => 30, 'format' => 'flat', 'orderby' => 'count', 'order' => 'DESC' ) ); ?>
|
||
</div>
|
||
<div class="sidebar-widget sidebar-archive-dropdown">
|
||
<h3 class="widget-title"><?php _e('Archiv', 'minecraft-modern-theme'); ?></h3>
|
||
<select class="archive-select" onchange="if(this.value) window.location.href=this.value;">
|
||
<option value=""><?php _e('Monat auswählen', 'minecraft-modern-theme'); ?></option>
|
||
<?php wp_get_archives( array( 'type' => 'monthly', 'format' => 'option', 'show_post_count' => true ) ); ?>
|
||
</select>
|
||
</div>
|
||
<?php
|
||
}
|
||
}
|
||
|
||
// Archiv-Widget Liste → Dropdown per JS umwandeln
|
||
function minecraft_modern_archive_to_dropdown() {
|
||
if ( ! is_single() ) return;
|
||
?>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
document.querySelectorAll('.single-sidebar .widget_archive').forEach(function(widget) {
|
||
var list = widget.querySelector('ul');
|
||
if (!list) return;
|
||
var select = document.createElement('select');
|
||
select.className = 'archive-select';
|
||
select.innerHTML = '<option value="">Monat auswählen</option>';
|
||
list.querySelectorAll('a').forEach(function(a) {
|
||
var opt = document.createElement('option');
|
||
opt.value = a.href;
|
||
opt.textContent = a.textContent;
|
||
select.appendChild(opt);
|
||
});
|
||
select.addEventListener('change', function() { if (this.value) window.location.href = this.value; });
|
||
list.replaceWith(select);
|
||
});
|
||
});
|
||
</script>
|
||
<?php
|
||
}
|
||
add_action( 'wp_footer', 'minecraft_modern_archive_to_dropdown' );
|
||
|
||
|
||
// === Single-Post Sidebar Customizer-Einstellungen ===
|
||
function minecraft_modern_single_sidebar_customizer( $wp_customize ) {
|
||
$wp_customize->add_section( 'single_sidebar_section', array(
|
||
'title' => __( 'Beitrag Sidebar', 'minecraft-modern-theme' ),
|
||
'priority' => 55,
|
||
) );
|
||
$wp_customize->add_setting( 'single_sidebar_enabled', array(
|
||
'default' => true,
|
||
'sanitize_callback' => 'wp_validate_boolean',
|
||
) );
|
||
$wp_customize->add_control( 'single_sidebar_enabled', array(
|
||
'label' => __( 'Sidebar auf Einzelbeiträgen anzeigen', 'minecraft-modern-theme' ),
|
||
'section' => 'single_sidebar_section',
|
||
'type' => 'checkbox',
|
||
) );
|
||
$wp_customize->add_setting( 'single_sidebar_position', array(
|
||
'default' => 'right',
|
||
'sanitize_callback' => 'sanitize_text_field',
|
||
) );
|
||
$wp_customize->add_control( 'single_sidebar_position', array(
|
||
'label' => __( 'Sidebar-Position', 'minecraft-modern-theme' ),
|
||
'section' => 'single_sidebar_section',
|
||
'type' => 'select',
|
||
'choices' => array(
|
||
'right' => __( 'Rechts', 'minecraft-modern-theme' ),
|
||
'left' => __( 'Links', 'minecraft-modern-theme' ),
|
||
),
|
||
) );
|
||
}
|
||
add_action( 'customize_register', 'minecraft_modern_single_sidebar_customizer' );
|
||
|
||
|
||
// === Announcement-Bar Höhe als CSS-Variable + Body-Klasse ===
|
||
function minecraft_modern_announcement_offset_script() {
|
||
if ( ! get_option( 'mm_announcement_enabled' ) ) return;
|
||
?>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
var bar = document.getElementById('mm-announcement');
|
||
if (!bar) return;
|
||
function updateOffset() {
|
||
var h = bar.offsetHeight;
|
||
document.documentElement.style.setProperty('--announcement-height', h + 'px');
|
||
document.body.classList.add('has-announcement');
|
||
}
|
||
updateOffset();
|
||
new ResizeObserver(updateOffset).observe(bar);
|
||
// Wenn Bar geschlossen wird
|
||
var closeBtn = bar.querySelector('.mm-announcement-close');
|
||
if (closeBtn) {
|
||
closeBtn.addEventListener('click', function() {
|
||
document.documentElement.style.setProperty('--announcement-height', '0px');
|
||
document.body.classList.remove('has-announcement');
|
||
});
|
||
}
|
||
});
|
||
</script>
|
||
<?php
|
||
}
|
||
add_action( 'wp_footer', 'minecraft_modern_announcement_offset_script' );
|
||
|
||
// =============================================================================
|
||
// === COOKIE-BANNER (DSGVO) – 4 Varianten, alle gleichzeitig gerendert =======
|
||
// =============================================================================
|
||
|
||
// Vorschau-Control
|
||
if ( class_exists('WP_Customize_Control') && ! class_exists('MM_Cookie_Preview_Control') ) :
|
||
class MM_Cookie_Preview_Control extends WP_Customize_Control {
|
||
public $type = 'mm_cookie_preview';
|
||
public function render_content() { ?>
|
||
<div style="margin-top:4px;">
|
||
<span class="customize-control-title" style="display:block;margin-bottom:8px;"><?php _e('Live-Vorschau','minecraft-modern-theme'); ?></span>
|
||
<div style="padding:12px 14px;background:rgba(0,212,255,0.07);border-left:3px solid #00d4ff;border-radius:0 6px 6px 0;">
|
||
<p style="margin:0 0 5px;font-size:12px;color:#00d4ff;font-weight:600;">← <?php _e('Vorschau rechts','minecraft-modern-theme'); ?></p>
|
||
<p style="margin:0;font-size:11px;color:#aaa;line-height:1.5;"><?php _e('Der Banner wird direkt in der Seitenvorschau angezeigt und aktualisiert sich live beim Wechseln der Variante.','minecraft-modern-theme'); ?></p>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
}
|
||
endif;
|
||
|
||
|
||
// --- 1. Customizer ---
|
||
function mm_cookie_banner_customizer( $wp_customize ) {
|
||
$wp_customize->add_section( 'mm_cookie_banner_section', array(
|
||
'title' => __( 'Cookie-Banner (DSGVO)', 'minecraft-modern-theme' ),
|
||
'priority' => 75,
|
||
) );
|
||
|
||
$wp_customize->add_setting( 'mm_cookie_enabled', array( 'default' => true, 'sanitize_callback' => 'wp_validate_boolean', 'transport' => 'postMessage' ) );
|
||
$wp_customize->add_control( 'mm_cookie_enabled', array( 'label' => __( 'Cookie-Banner aktivieren', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'checkbox' ) );
|
||
|
||
$wp_customize->add_setting( 'mm_cookie_style', array( 'default' => 'bar', 'sanitize_callback' => 'sanitize_text_field', 'transport' => 'postMessage' ) );
|
||
$wp_customize->add_control( 'mm_cookie_style', array(
|
||
'label' => __( 'Design-Variante', 'minecraft-modern-theme' ),
|
||
'section' => 'mm_cookie_banner_section',
|
||
'type' => 'select',
|
||
'choices' => array(
|
||
'bar' => __( 'Variante 1 – Schmale Bar (volle Breite)', 'minecraft-modern-theme' ),
|
||
'split' => __( 'Variante 2 – Zweispaltig (3A)', 'minecraft-modern-theme' ),
|
||
'slide' => __( 'Variante 3 – Slide-In von rechts (3B)', 'minecraft-modern-theme' ),
|
||
'stepper' => __( 'Variante 4 – Kompakt-Center mit Stepper (3C)', 'minecraft-modern-theme' ),
|
||
),
|
||
) );
|
||
|
||
$wp_customize->add_setting( 'mm_cookie_text', array( 'default' => __( 'Wir nutzen Cookies und ähnliche Technologien. Einige sind essenziell, andere helfen uns diese Website zu verbessern. Du kannst deine Auswahl jederzeit anpassen.', 'minecraft-modern-theme' ), 'sanitize_callback' => 'wp_kses_post', 'transport' => 'postMessage' ) );
|
||
$wp_customize->add_control( 'mm_cookie_text', array( 'label' => __( 'Banner-Text', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'textarea' ) );
|
||
|
||
$wp_customize->add_setting( 'mm_cookie_privacy_url', array( 'default' => '', 'sanitize_callback' => 'esc_url_raw' ) );
|
||
$wp_customize->add_control( 'mm_cookie_privacy_url', array( 'label' => __( 'URL Datenschutzerklärung', 'minecraft-modern-theme' ), 'description' => __( 'Leer lassen um den Link auszublenden.', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'url' ) );
|
||
|
||
foreach ( array(
|
||
'necessary' => array( 'label' => __( 'Beschreibung: Notwendige', 'minecraft-modern-theme' ), 'default' => __( 'Grundlegende Funktionen der Website. Können nicht deaktiviert werden.', 'minecraft-modern-theme' ) ),
|
||
'statistics' => array( 'label' => __( 'Beschreibung: Statistik', 'minecraft-modern-theme' ), 'default' => __( 'Helfen uns zu verstehen wie Besucher mit der Website interagieren (z.B. Google Analytics).', 'minecraft-modern-theme' ) ),
|
||
'marketing' => array( 'label' => __( 'Beschreibung: Marketing', 'minecraft-modern-theme' ), 'default' => __( 'Werden genutzt um Werbung relevanter zu gestalten (z.B. YouTube, Facebook).', 'minecraft-modern-theme' ) ),
|
||
) as $key => $opts ) {
|
||
$wp_customize->add_setting( 'mm_cookie_desc_' . $key, array( 'default' => $opts['default'], 'sanitize_callback' => 'sanitize_textarea_field' ) );
|
||
$wp_customize->add_control( 'mm_cookie_desc_' . $key, array( 'label' => $opts['label'], 'section' => 'mm_cookie_banner_section', 'type' => 'textarea' ) );
|
||
}
|
||
|
||
$wp_customize->add_setting( 'mm_cookie_ga_id', array( 'default' => '', 'sanitize_callback' => 'sanitize_text_field' ) );
|
||
$wp_customize->add_control( 'mm_cookie_ga_id', array( 'label' => __( 'Google Analytics ID (optional)', 'minecraft-modern-theme' ), 'description' => __( 'z.B. G-XXXXXXXXXX', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'text' ) );
|
||
|
||
$wp_customize->add_setting( 'mm_cookie_lifetime', array( 'default' => 365, 'sanitize_callback' => 'absint' ) );
|
||
$wp_customize->add_control( 'mm_cookie_lifetime', array( 'label' => __( 'Cookie-Laufzeit (Tage)', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'number', 'input_attrs' => array( 'min' => 1, 'max' => 730 ) ) );
|
||
|
||
if ( class_exists( 'MM_Cookie_Preview_Control' ) ) {
|
||
$wp_customize->add_setting( 'mm_cookie_preview_dummy', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||
$wp_customize->add_control( new MM_Cookie_Preview_Control( $wp_customize, 'mm_cookie_preview_dummy', array( 'section' => 'mm_cookie_banner_section', 'priority' => 200 ) ) );
|
||
}
|
||
}
|
||
add_action( 'customize_register', 'mm_cookie_banner_customizer' );
|
||
|
||
|
||
// --- 2. Banner HTML – ALLE 4 LAYOUTS gleichzeitig ausgeben ---
|
||
// Im Customizer wechselt JS nur die Klasse auf #mm-cookie-banner.
|
||
// CSS zeigt immer nur das passende .mmc-layout-* div.
|
||
function mm_cookie_banner_render() {
|
||
$is_preview = is_customize_preview();
|
||
if ( ! $is_preview && ! get_theme_mod( 'mm_cookie_enabled', true ) ) return;
|
||
|
||
$style = get_theme_mod( 'mm_cookie_style', 'bar' );
|
||
$text = get_theme_mod( 'mm_cookie_text', __( 'Wir nutzen Cookies und ähnliche Technologien. Einige sind essenziell, andere helfen uns diese Website zu verbessern.', 'minecraft-modern-theme' ) );
|
||
$priv_url = get_theme_mod( 'mm_cookie_privacy_url', '' );
|
||
$lifetime = absint( get_theme_mod( 'mm_cookie_lifetime', 365 ) );
|
||
$ga_id = get_theme_mod( 'mm_cookie_ga_id', '' );
|
||
$desc_n = get_theme_mod( 'mm_cookie_desc_necessary', __( 'Grundlegende Funktionen der Website. Können nicht deaktiviert werden.', 'minecraft-modern-theme' ) );
|
||
$desc_s = get_theme_mod( 'mm_cookie_desc_statistics', __( 'Helfen uns zu verstehen wie Besucher mit der Website interagieren (z.B. Google Analytics).', 'minecraft-modern-theme' ) );
|
||
$desc_m = get_theme_mod( 'mm_cookie_desc_marketing', __( 'Werden genutzt um Werbung relevanter zu gestalten (z.B. YouTube, Facebook).', 'minecraft-modern-theme' ) );
|
||
|
||
$priv_link = $priv_url ? '<a href="' . esc_url($priv_url) . '" target="_blank" rel="noopener noreferrer" class="mmc-priv-link">' . __( 'Datenschutzerklärung', 'minecraft-modern-theme' ) . '</a>' : '';
|
||
$preview_class = $is_preview ? ' mmc-visible mmc-preview-mode' : '';
|
||
$inline_style = $is_preview ? '' : 'display:none;';
|
||
|
||
// Kategorien-Block (identisch in allen Varianten mit Kategorien)
|
||
$cats = '<div class="mmc-cats">
|
||
<div class="mmc-cat"><div class="mmc-cat-row"><span class="mmc-cat-name"><i class="fas fa-shield-alt"></i> ' . __('Notwendige','minecraft-modern-theme') . '</span><span class="mmc-always">' . __('Immer aktiv','minecraft-modern-theme') . '</span></div><p class="mmc-cat-desc">' . esc_html($desc_n) . '</p></div>
|
||
<div class="mmc-cat"><div class="mmc-cat-row"><label class="mmc-cat-name" for="mmc-stat"><i class="fas fa-chart-bar"></i> ' . __('Statistik','minecraft-modern-theme') . '</label><label class="mmc-toggle"><input type="checkbox" id="mmc-stat" checked><span class="mmc-knob"></span></label></div><p class="mmc-cat-desc">' . esc_html($desc_s) . '</p></div>
|
||
<div class="mmc-cat"><div class="mmc-cat-row"><label class="mmc-cat-name" for="mmc-mark"><i class="fas fa-bullhorn"></i> ' . __('Marketing','minecraft-modern-theme') . '</label><label class="mmc-toggle"><input type="checkbox" id="mmc-mark"><span class="mmc-knob"></span></label></div><p class="mmc-cat-desc">' . esc_html($desc_m) . '</p></div>
|
||
</div>';
|
||
|
||
$btn_accept = '<button id="mmc-accept" class="mmc-btn mmc-btn-accept"><i class="fas fa-check"></i> ' . __('Alle akzeptieren','minecraft-modern-theme') . '</button>';
|
||
$btn_select = '<button id="mmc-select" class="mmc-btn mmc-btn-select"><i class="fas fa-sliders-h"></i> ' . __('Auswahl speichern','minecraft-modern-theme') . '</button>';
|
||
$btn_neces = '<button id="mmc-neces" class="mmc-btn mmc-btn-neces">' . __('Nur notwendige','minecraft-modern-theme') . '</button>';
|
||
|
||
$text_esc = wp_kses_post($text);
|
||
?>
|
||
<div id="mm-cookie-banner"
|
||
class="mmc-style-<?php echo esc_attr($style); ?><?php echo $preview_class; ?>"
|
||
role="dialog" aria-modal="true"
|
||
style="<?php echo $inline_style; ?>">
|
||
|
||
<!-- Overlay (nur für stepper sichtbar, per CSS gesteuert) -->
|
||
<div class="mmc-overlay"></div>
|
||
|
||
<!-- ══ LAYOUT 1: Schmale Bar ══ -->
|
||
<div class="mmc-layout-bar">
|
||
<div class="mmc-bar-wrap">
|
||
<i class="fas fa-cookie-bite mmc-bar-icon"></i>
|
||
<p class="mmc-text"><?php echo $text_esc; ?> <?php echo $priv_link; ?></p>
|
||
<div class="mmc-bar-btns"><?php echo $btn_neces; ?><?php echo $btn_accept; ?></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══ LAYOUT 2 (3A): Zweispaltig ══ -->
|
||
<div class="mmc-layout-split">
|
||
<div class="mmc-split-left">
|
||
<i class="fas fa-cookie-bite mmc-split-icon"></i>
|
||
<h3 class="mmc-split-title"><?php _e('Datenschutz-Einstellungen','minecraft-modern-theme'); ?></h3>
|
||
<p class="mmc-split-sub"><?php echo $text_esc; ?></p>
|
||
<?php if ($priv_link) echo '<p class="mmc-split-priv">' . $priv_link . '</p>'; ?>
|
||
</div>
|
||
<div class="mmc-split-right">
|
||
<?php echo $cats; ?>
|
||
<div class="mmc-split-btns"><?php echo $btn_neces; ?><?php echo $btn_select; ?><?php echo $btn_accept; ?></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══ LAYOUT 3 (3B): Slide-In von rechts ══ -->
|
||
<div class="mmc-layout-slide">
|
||
<div class="mmc-slide-header">
|
||
<div class="mmc-slide-icon"><i class="fas fa-cookie-bite"></i></div>
|
||
<h3 class="mmc-slide-title"><?php _e('Datenschutz-Einstellungen','minecraft-modern-theme'); ?></h3>
|
||
</div>
|
||
<p class="mmc-slide-text"><?php echo $text_esc; ?> <?php echo $priv_link; ?></p>
|
||
<?php echo $cats; ?>
|
||
<div class="mmc-slide-btns"><?php echo $btn_accept; ?><?php echo $btn_select; ?><?php echo $btn_neces; ?></div>
|
||
</div>
|
||
|
||
<!-- ══ LAYOUT 4 (3C): Stepper ══ -->
|
||
<div class="mmc-layout-stepper">
|
||
<div class="mmc-steps">
|
||
<div class="mmc-step mmc-step-done"><span class="mmc-step-num">✓</span><?php _e('Info','minecraft-modern-theme'); ?></div>
|
||
<div class="mmc-step mmc-step-active"><span class="mmc-step-num">2</span><?php _e('Auswahl','minecraft-modern-theme'); ?></div>
|
||
<div class="mmc-step"><span class="mmc-step-num">3</span><?php _e('Fertig','minecraft-modern-theme'); ?></div>
|
||
</div>
|
||
<div class="mmc-stepper-body">
|
||
<p class="mmc-stepper-text"><?php echo $text_esc; ?> <?php echo $priv_link; ?></p>
|
||
<?php echo $cats; ?>
|
||
<div class="mmc-stepper-btns"><?php echo $btn_neces; ?><?php echo $btn_select; ?><?php echo $btn_accept; ?></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- #mm-cookie-banner -->
|
||
|
||
<script>
|
||
(function(){
|
||
var IS_PREVIEW=<?php echo $is_preview?'true':'false';?>;
|
||
var COOKIE='mm_cookie_consent',DAYS=<?php echo intval($lifetime);?>,GA_ID=<?php echo json_encode($ga_id);?>,STYLE=<?php echo json_encode($style);?>;
|
||
var BLOCKED=['youtube.com','youtube-nocookie.com','youtu.be','vimeo.com','maps.google.com','google.com/maps','facebook.com','fb.com','twitter.com','platform.twitter.com','tiktok.com','instagram.com','open.spotify.com','twitch.tv'];
|
||
|
||
function getCookie(n){var m=document.cookie.match(new RegExp('(?:^|; )'+n.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')+'=([^;]*)'));try{return m?JSON.parse(decodeURIComponent(m[1])):null;}catch(e){return null;}}
|
||
function setCookie(n,v,d){var e=new Date();e.setDate(e.getDate()+d);document.cookie=n+'='+encodeURIComponent(JSON.stringify(v))+'; expires='+e.toUTCString()+'; path=/; SameSite=Lax';}
|
||
|
||
var banner=document.getElementById('mm-cookie-banner');
|
||
if(!banner)return;
|
||
|
||
function getCurrentStyle(){return banner.className.match(/mmc-style-(\w+)/)?banner.className.match(/mmc-style-(\w+)/)[1]:STYLE;}
|
||
|
||
function show(){
|
||
banner.style.display='';
|
||
var s=getCurrentStyle();
|
||
if(s==='stepper')document.body.style.overflow='hidden';
|
||
setTimeout(function(){banner.classList.add('mmc-visible');},30);
|
||
}
|
||
function hide(){
|
||
if(IS_PREVIEW)return;
|
||
banner.classList.add('mmc-hiding');
|
||
setTimeout(function(){banner.style.display='none';banner.classList.remove('mmc-hiding','mmc-visible');document.body.style.overflow='';},400);
|
||
}
|
||
|
||
function loadGA(id){if(window._mmGaOk)return;window._mmGaOk=true;var s=document.createElement('script');s.async=true;s.src='https://www.googletagmanager.com/gtag/js?id='+id;document.head.appendChild(s);window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config',id,{anonymize_ip:true});}
|
||
function isBlocked(src){return src&&BLOCKED.some(function(d){return src.indexOf(d)!==-1;});}
|
||
function blockIframes(){if(IS_PREVIEW)return;document.querySelectorAll('iframe').forEach(function(f){var src=f.getAttribute('src')||f.getAttribute('data-src')||'';if(!isBlocked(src)||f.dataset.mmBlocked)return;f.dataset.mmOrigSrc=src;f.dataset.mmBlocked='1';f.setAttribute('src','about:blank');f.style.display='none';var ph=document.createElement('div');ph.className='mmc-placeholder';ph.innerHTML='<i class="fas fa-cookie-bite"></i><p><?php echo esc_js(__("Inhalt wegen Cookie-Einstellungen blockiert.","minecraft-modern-theme"));?></p><button class="mmc-ph-btn"><?php echo esc_js(__("Einstellungen ändern","minecraft-modern-theme"));?></button>';f.parentNode.insertBefore(ph,f);ph.querySelector('.mmc-ph-btn').addEventListener('click',show);});}
|
||
function unblockIframes(){document.querySelectorAll('iframe[data-mm-blocked]').forEach(function(f){var prev=f.previousElementSibling;if(prev&&prev.classList.contains('mmc-placeholder'))prev.remove();f.setAttribute('src',f.dataset.mmOrigSrc||'');f.style.display='';delete f.dataset.mmBlocked;});}
|
||
function applyConsent(c){document.dispatchEvent(new CustomEvent('mm_cookie_consent_set',{detail:c}));if(c.statistics&&GA_ID)loadGA(GA_ID);if(c.marketing){unblockIframes();}else{blockIframes();}}
|
||
function saveAndClose(stat,mark){var c={necessary:true,statistics:!!stat,marketing:!!mark};setCookie(COOKIE,c,DAYS);applyConsent(c);hide();}
|
||
|
||
document.addEventListener('DOMContentLoaded',function(){
|
||
var existing=getCookie(COOKIE);
|
||
// Checkboxen aus allen Layouts referenzieren (nur die ersten sind aktiv)
|
||
function getStatCb(){return document.querySelector('#mm-cookie-banner .mmc-layout-'+getCurrentStyle()+' #mmc-stat, #mmc-stat');}
|
||
function getMarkCb(){return document.querySelector('#mm-cookie-banner .mmc-layout-'+getCurrentStyle()+' #mmc-mark, #mmc-mark');}
|
||
|
||
if(!IS_PREVIEW&&existing){applyConsent(existing);var s=getStatCb(),m=getMarkCb();if(s)s.checked=!!existing.statistics;if(m)m.checked=!!existing.marketing;}
|
||
else if(!IS_PREVIEW){blockIframes();setTimeout(show,800);}
|
||
|
||
banner.addEventListener('click',function(e){
|
||
var t=e.target;
|
||
if(t.id==='mmc-accept'||t.closest('#mmc-accept')){var s=getStatCb(),m=getMarkCb();if(s)s.checked=true;if(m)m.checked=true;saveAndClose(true,true);}
|
||
else if(t.id==='mmc-select'||t.closest('#mmc-select')){var s=getStatCb(),m=getMarkCb();saveAndClose(s&&s.checked,m&&m.checked);}
|
||
else if(t.id==='mmc-neces'||t.closest('#mmc-neces')){saveAndClose(false,false);}
|
||
});
|
||
});
|
||
|
||
window.mmOpenCookieBanner=show;
|
||
})();
|
||
</script>
|
||
<?php
|
||
}
|
||
add_action( 'wp_footer', 'mm_cookie_banner_render' );
|
||
|
||
|
||
// --- 3. Hilfsfunktionen ---
|
||
function mm_cookie_consent(){if(!isset($_COOKIE['mm_cookie_consent']))return array();$v=json_decode(stripslashes($_COOKIE['mm_cookie_consent']),true);return is_array($v)?$v:array();}
|
||
function mm_cookie_accepted($category='necessary'){$c=mm_cookie_consent();return!empty($c[$category]);}
|
||
function mm_cookie_settings_shortcode($atts){$a=shortcode_atts(array('text'=>__('Cookie-Einstellungen','minecraft-modern-theme')),$atts);return '<a href="javascript:void(0)" onclick="if(window.mmOpenCookieBanner)window.mmOpenCookieBanner();" class="mmc-settings-link">'.esc_html($a['text']).'</a>';}
|
||
add_shortcode('cookie_settings','mm_cookie_settings_shortcode');
|
||
|
||
|
||
// --- 4. Live-Vorschau: nur Klasse + Text wechseln, HTML ist bereits vollständig ---
|
||
function mm_cookie_banner_preview_js(){
|
||
if(!is_customize_preview())return; ?>
|
||
<script>
|
||
(function(){
|
||
var ALL=['bar','split','slide','stepper'];
|
||
wp.customize.bind('preview-ready',function(){
|
||
|
||
// Variante wechseln: nur CSS-Klasse tauschen, HTML bleibt
|
||
wp.customize('mm_cookie_style',function(setting){setting.bind(function(v){
|
||
var b=document.getElementById('mm-cookie-banner');if(!b)return;
|
||
ALL.forEach(function(x){b.classList.remove('mmc-style-'+x);});
|
||
b.classList.add('mmc-style-'+v);
|
||
// Scroll-Lock für Stepper
|
||
document.body.style.overflow=(v==='stepper'?'hidden':'');
|
||
});});
|
||
|
||
// Text in allen 4 Layouts gleichzeitig aktualisieren
|
||
wp.customize('mm_cookie_text',function(setting){setting.bind(function(v){
|
||
['.mmc-text','.mmc-split-sub','.mmc-slide-text','.mmc-stepper-text'].forEach(function(sel){
|
||
document.querySelectorAll('#mm-cookie-banner '+sel).forEach(function(el){
|
||
var lnk=el.querySelector('a.mmc-priv-link');
|
||
el.textContent=v+' ';
|
||
if(lnk)el.appendChild(lnk);
|
||
});
|
||
});
|
||
});});
|
||
|
||
// Banner ein/aus
|
||
wp.customize('mm_cookie_enabled',function(setting){setting.bind(function(v){
|
||
var b=document.getElementById('mm-cookie-banner');if(!b)return;
|
||
if(v){b.style.display='';b.classList.remove('mmc-hiding');setTimeout(function(){b.classList.add('mmc-visible');},30);}
|
||
else{b.classList.add('mmc-hiding');setTimeout(function(){b.style.display='none';b.classList.remove('mmc-hiding','mmc-visible');},400);}
|
||
});});
|
||
});
|
||
})();
|
||
</script>
|
||
<?php
|
||
}
|
||
add_action('customize_preview_init',function(){add_action('wp_footer','mm_cookie_banner_preview_js',99);});
|
||
|
||
// =============================================================================
|
||
// === VIDEO-MODUL =============================================================
|
||
// =============================================================================
|
||
|
||
// --- 1. Custom Post Type: Video ---
|
||
function mm_register_video_post_type() {
|
||
register_post_type( 'mm_video', array(
|
||
'labels' => array(
|
||
'name' => __( 'Videos', 'minecraft-modern-theme' ),
|
||
'singular_name' => __( 'Video', 'minecraft-modern-theme' ),
|
||
'add_new' => __( 'Neues Video', 'minecraft-modern-theme' ),
|
||
'add_new_item' => __( 'Neues Video hinzufügen', 'minecraft-modern-theme' ),
|
||
'edit_item' => __( 'Video bearbeiten', 'minecraft-modern-theme' ),
|
||
'all_items' => __( 'Alle Videos', 'minecraft-modern-theme' ),
|
||
'menu_name' => __( 'Videos', 'minecraft-modern-theme' ),
|
||
),
|
||
'public' => true,
|
||
'has_archive' => true,
|
||
'menu_icon' => 'dashicons-video-alt3',
|
||
'menu_position' => 7,
|
||
'supports' => array( 'title', 'thumbnail', 'excerpt', 'page-attributes' ),
|
||
'rewrite' => array( 'slug' => 'videos' ),
|
||
'show_in_rest' => true,
|
||
) );
|
||
|
||
register_post_type( 'mm_livestream', array(
|
||
'labels' => array(
|
||
'name' => __( 'Livestreams', 'minecraft-modern-theme' ),
|
||
'singular_name' => __( 'Livestream', 'minecraft-modern-theme' ),
|
||
'add_new' => __( 'Neuer Livestream', 'minecraft-modern-theme' ),
|
||
'add_new_item' => __( 'Neuen Livestream hinzufügen', 'minecraft-modern-theme' ),
|
||
'edit_item' => __( 'Livestream bearbeiten', 'minecraft-modern-theme' ),
|
||
'all_items' => __( 'Alle Livestreams', 'minecraft-modern-theme' ),
|
||
'menu_name' => __( 'Livestreams', 'minecraft-modern-theme' ),
|
||
),
|
||
'public' => true,
|
||
'publicly_queryable' => false,
|
||
'exclude_from_search' => true,
|
||
'show_ui' => true,
|
||
'show_in_menu' => 'edit.php?post_type=mm_video',
|
||
'menu_position' => 8,
|
||
'supports' => array( 'title', 'excerpt', 'page-attributes' ),
|
||
'show_in_rest' => true,
|
||
) );
|
||
}
|
||
add_action( 'init', 'mm_register_video_post_type' );
|
||
|
||
|
||
// --- 2. Meta-Box: Video URL + Kategorie ---
|
||
function mm_video_meta_boxes() {
|
||
add_meta_box(
|
||
'mm_video_data',
|
||
__( 'Video-Einstellungen', 'minecraft-modern-theme' ),
|
||
'mm_video_meta_box_html',
|
||
'mm_video', 'normal', 'high'
|
||
);
|
||
|
||
add_meta_box(
|
||
'mm_livestream_data',
|
||
__( 'Livestream-Einstellungen', 'minecraft-modern-theme' ),
|
||
'mm_livestream_meta_box_html',
|
||
'mm_livestream', 'normal', 'high'
|
||
);
|
||
}
|
||
add_action( 'add_meta_boxes', 'mm_video_meta_boxes' );
|
||
|
||
function mm_video_meta_box_html( $post ) {
|
||
wp_nonce_field( 'mm_video_save', 'mm_video_nonce' );
|
||
$url = get_post_meta( $post->ID, '_mm_video_url', true );
|
||
$category = get_post_meta( $post->ID, '_mm_video_category', true );
|
||
$post_id = $post->ID;
|
||
?>
|
||
<table class="form-table" style="margin-top:0;">
|
||
<tr>
|
||
<th style="width:140px;padding-top:12px;"><label for="mm_video_url"><strong><?php _e('Video-URL', 'minecraft-modern-theme'); ?></strong></label></th>
|
||
<td style="padding-top:12px;">
|
||
<input type="url" id="mm_video_url" name="mm_video_url"
|
||
value="<?php echo esc_attr($url); ?>"
|
||
style="width:100%;max-width:600px;"
|
||
placeholder="https://www.youtube.com/watch?v=... oder https://vimeo.com/... oder https://www.twitch.tv/videos/... oder direkte .mp4 URL">
|
||
<p class="description" style="margin-top:6px;">
|
||
<?php _e('Unterstützt: YouTube, Vimeo, Twitch VOD, direkte MP4-Datei. Einfach die normale Seiten-URL einfügen.', 'minecraft-modern-theme'); ?>
|
||
</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="mm_video_category"><strong><?php _e('Kategorie', 'minecraft-modern-theme'); ?></strong></label></th>
|
||
<td>
|
||
<input type="text" id="mm_video_category" name="mm_video_category"
|
||
value="<?php echo esc_attr($category); ?>"
|
||
style="width:300px;"
|
||
placeholder="z.B. Highlights, Tutorials, Events">
|
||
<p class="description"><?php _e('Zum Filtern auf der Galerie-Seite. Leer lassen wenn nicht benötigt.', 'minecraft-modern-theme'); ?></p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th style="padding-top:14px;"><strong><?php _e('Shortcode', 'minecraft-modern-theme'); ?></strong></th>
|
||
<td style="padding-top:14px;">
|
||
<?php if ( $url ) : ?>
|
||
<div id="mm-video-shortcode-wrap" style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;">
|
||
<?php else : ?>
|
||
<div id="mm-video-shortcode-wrap" style="display:none;align-items:center;gap:10px;flex-wrap:wrap;">
|
||
<?php endif; ?>
|
||
<code id="mm-video-shortcode-code"
|
||
style="background:#1e1e1e;color:#00d4ff;padding:8px 14px;border-radius:6px;font-size:13px;border:1px solid #333;user-select:all;cursor:text;"
|
||
><?php echo $url ? esc_html('[mm_video url="' . $url . '"]') : ''; ?></code>
|
||
<button type="button" id="mm-video-copy-btn"
|
||
style="padding:7px 14px;background:#0073aa;color:#fff;border:none;border-radius:5px;cursor:pointer;font-size:13px;font-weight:600;">
|
||
<span class="dashicons dashicons-clipboard" style="vertical-align:middle;font-size:16px;margin-right:4px;"></span>
|
||
<?php _e('Kopieren', 'minecraft-modern-theme'); ?>
|
||
</button>
|
||
<span id="mm-video-copy-ok" style="display:none;color:#46b450;font-weight:600;font-size:13px;">
|
||
✓ <?php _e('Kopiert!', 'minecraft-modern-theme'); ?>
|
||
</span>
|
||
</div>
|
||
<p class="description" style="margin-top:6px;">
|
||
<?php _e('Diesen Shortcode in beliebigen Beiträgen oder Seiten einfügen um das Video dort einzubetten.', 'minecraft-modern-theme'); ?>
|
||
</p>
|
||
<script>
|
||
(function() {
|
||
var urlInput = document.getElementById('mm_video_url');
|
||
var scWrap = document.getElementById('mm-video-shortcode-wrap');
|
||
var scCode = document.getElementById('mm-video-shortcode-code');
|
||
var copyBtn = document.getElementById('mm-video-copy-btn');
|
||
var copyOk = document.getElementById('mm-video-copy-ok');
|
||
|
||
// Live-Update beim Tippen
|
||
if (urlInput) {
|
||
urlInput.addEventListener('input', function() {
|
||
var val = this.value.trim();
|
||
if (val) {
|
||
scCode.textContent = '[mm_video url="' + val + '"]';
|
||
scWrap.style.display = 'flex';
|
||
} else {
|
||
scWrap.style.display = 'none';
|
||
}
|
||
});
|
||
}
|
||
|
||
// Kopieren-Button
|
||
if (copyBtn) {
|
||
copyBtn.addEventListener('click', function() {
|
||
var text = scCode.textContent;
|
||
if (navigator.clipboard) {
|
||
navigator.clipboard.writeText(text).then(function() {
|
||
showCopied();
|
||
});
|
||
} else {
|
||
// Fallback für ältere Browser
|
||
var ta = document.createElement('textarea');
|
||
ta.value = text;
|
||
ta.style.position = 'fixed';
|
||
ta.style.opacity = '0';
|
||
document.body.appendChild(ta);
|
||
ta.select();
|
||
document.execCommand('copy');
|
||
document.body.removeChild(ta);
|
||
showCopied();
|
||
}
|
||
});
|
||
}
|
||
|
||
function showCopied() {
|
||
copyOk.style.display = 'inline';
|
||
setTimeout(function() { copyOk.style.display = 'none'; }, 2500);
|
||
}
|
||
})();
|
||
</script>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<?php
|
||
}
|
||
|
||
function mm_livestream_meta_box_html( $post ) {
|
||
wp_nonce_field( 'mm_livestream_save', 'mm_livestream_nonce' );
|
||
$url = get_post_meta( $post->ID, '_mm_livestream_url', true );
|
||
$player_url = get_post_meta( $post->ID, '_mm_livestream_player_url', true );
|
||
$owner = get_post_meta( $post->ID, '_mm_livestream_owner', true );
|
||
?>
|
||
<table class="form-table" style="margin-top:0;">
|
||
<tr>
|
||
<th style="width:160px;padding-top:12px;"><label for="mm_livestream_url"><strong><?php _e('Profil-URL', 'minecraft-modern-theme'); ?></strong></label></th>
|
||
<td style="padding-top:12px;">
|
||
<input type="url" id="mm_livestream_url" name="mm_livestream_url"
|
||
value="<?php echo esc_attr( $url ); ?>"
|
||
style="width:100%;max-width:700px;"
|
||
placeholder="https://www.youtube.com/@handle oder https://www.twitch.tv/kanal">
|
||
<p class="description" style="margin-top:6px;">
|
||
<?php _e('Kanal-Link einfügen. Bei YouTube kannst du den @Handle oder die Channel-URL verwenden - die Kanal-ID wird automatisch ermittelt.', 'minecraft-modern-theme'); ?>
|
||
</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th style="padding-top:12px;"><label for="mm_livestream_player_url"><strong><?php _e('Direkte Stream-URL', 'minecraft-modern-theme'); ?></strong></label></th>
|
||
<td style="padding-top:12px;">
|
||
<input type="url" id="mm_livestream_player_url" name="mm_livestream_player_url"
|
||
value="<?php echo esc_attr( $player_url ); ?>"
|
||
style="width:100%;max-width:700px;"
|
||
placeholder="https://www.youtube.com/watch?v=... oder https://www.twitch.tv/videos/...">
|
||
<p class="description" style="margin-top:6px;">
|
||
<?php _e('Optional. Wenn ein Kanal mehrere Streams parallel hat, kannst du hier einen konkreten Stream-Link eintragen. Ohne dieses Feld wird der Live-Player aus der Profil-URL erzeugt.', 'minecraft-modern-theme'); ?>
|
||
</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th style="padding-top:12px;"><label for="mm_livestream_owner"><strong><?php _e('Streamer / Gruppe', 'minecraft-modern-theme'); ?></strong></label></th>
|
||
<td style="padding-top:12px;">
|
||
<input type="text" id="mm_livestream_owner" name="mm_livestream_owner"
|
||
value="<?php echo esc_attr( $owner ); ?>"
|
||
style="width:100%;max-width:420px;"
|
||
placeholder="z.B. Streamer-Name oder Gruppen-Name">
|
||
<p class="description" style="margin-top:6px;">
|
||
<?php _e('Mehrere Livestream-Einträge mit demselben Streamer/Gruppen-Namen werden oberhalb der Videos in einer gemeinsamen Box mit Umschalter zusammengefasst.', 'minecraft-modern-theme'); ?>
|
||
</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th style="padding-top:12px;"><strong><?php _e('Optionaler Text', 'minecraft-modern-theme'); ?></strong></th>
|
||
<td style="padding-top:12px;">
|
||
<p class="description"><?php _e('Du kannst den Auszug des Eintrags optional als kurze Beschreibung für diesen Livestream verwenden.', 'minecraft-modern-theme'); ?></p>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<?php
|
||
}
|
||
|
||
function mm_normalize_youtube_channel_id( $input ) {
|
||
$input = trim( (string) $input );
|
||
|
||
if ( $input === '' ) {
|
||
return '';
|
||
}
|
||
|
||
if ( preg_match( '/^UC[a-zA-Z0-9_-]+$/', $input ) ) {
|
||
return $input;
|
||
}
|
||
|
||
if ( preg_match( '~youtube\.com/channel/(UC[a-zA-Z0-9_-]+)~i', $input, $matches ) ) {
|
||
return $matches[1];
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
function mm_video_save_meta( $post_id ) {
|
||
if ( ! isset( $_POST['mm_video_nonce'] ) || ! wp_verify_nonce( $_POST['mm_video_nonce'], 'mm_video_save' ) ) return;
|
||
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
|
||
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
|
||
|
||
if ( isset( $_POST['mm_video_url'] ) ) {
|
||
update_post_meta( $post_id, '_mm_video_url', esc_url_raw( $_POST['mm_video_url'] ) );
|
||
}
|
||
if ( isset( $_POST['mm_video_category'] ) ) {
|
||
update_post_meta( $post_id, '_mm_video_category', sanitize_text_field( $_POST['mm_video_category'] ) );
|
||
}
|
||
}
|
||
add_action( 'save_post', 'mm_video_save_meta' );
|
||
|
||
function mm_livestream_save_meta( $post_id ) {
|
||
if ( ! isset( $_POST['mm_livestream_nonce'] ) || ! wp_verify_nonce( $_POST['mm_livestream_nonce'], 'mm_livestream_save' ) ) return;
|
||
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
|
||
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
|
||
|
||
if ( isset( $_POST['mm_livestream_url'] ) ) {
|
||
update_post_meta( $post_id, '_mm_livestream_url', esc_url_raw( $_POST['mm_livestream_url'] ) );
|
||
}
|
||
if ( isset( $_POST['mm_livestream_player_url'] ) ) {
|
||
update_post_meta( $post_id, '_mm_livestream_player_url', esc_url_raw( $_POST['mm_livestream_player_url'] ) );
|
||
}
|
||
if ( isset( $_POST['mm_livestream_owner'] ) ) {
|
||
update_post_meta( $post_id, '_mm_livestream_owner', sanitize_text_field( $_POST['mm_livestream_owner'] ) );
|
||
}
|
||
}
|
||
add_action( 'save_post_mm_livestream', 'mm_livestream_save_meta' );
|
||
|
||
|
||
// --- 3. URL → Embed-URL umwandeln ---
|
||
function mm_video_get_embed_url( $url ) {
|
||
if ( empty($url) ) return false;
|
||
|
||
// YouTube: watch?v=ID, youtu.be/ID, shorts/ID
|
||
if ( preg_match( '/(?:youtube\.com\/(?:watch\?v=|shorts\/|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/', $url, $m ) ) {
|
||
return 'https://www.youtube-nocookie.com/embed/' . $m[1] . '?rel=0&modestbranding=1';
|
||
}
|
||
|
||
// Vimeo: vimeo.com/ID
|
||
if ( preg_match( '/vimeo\.com\/(?:video\/)?(\d+)/', $url, $m ) ) {
|
||
return 'https://player.vimeo.com/video/' . $m[1] . '?dnt=1';
|
||
}
|
||
|
||
// Twitch VOD: twitch.tv/videos/ID
|
||
if ( preg_match( '/twitch\.tv\/videos\/(\d+)/', $url, $m ) ) {
|
||
$parent = parse_url( home_url(), PHP_URL_HOST );
|
||
return 'https://player.twitch.tv/?video=v' . $m[1] . '&parent=' . $parent . '&autoplay=false';
|
||
}
|
||
|
||
// Twitch Kanal-Stream: twitch.tv/CHANNEL (mit oder ohne trailing slash)
|
||
if ( preg_match( '/twitch\.tv\/([a-zA-Z0-9_]+)\/?(?:\?.*)?$/', $url, $m ) ) {
|
||
$parent = parse_url( home_url(), PHP_URL_HOST );
|
||
return 'https://player.twitch.tv/?channel=' . $m[1] . '&parent=' . $parent . '&autoplay=false';
|
||
}
|
||
|
||
// Direkte MP4 / WebM / OGV
|
||
if ( preg_match( '/\.(mp4|webm|ogv|ogg)(\?.*)?$/i', $url ) ) {
|
||
return $url; // wird als <video> Tag ausgegeben, nicht iframe
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
function mm_video_get_type( $url ) {
|
||
if ( preg_match( '/youtube\.com|youtu\.be/', $url ) ) return 'youtube';
|
||
if ( strpos( $url, 'vimeo.com' ) !== false ) return 'vimeo';
|
||
if ( strpos( $url, 'twitch.tv' ) !== false ) return 'twitch';
|
||
if ( preg_match( '/\.(mp4|webm|ogv|ogg)(\?.*)?$/i', $url ) ) return 'mp4';
|
||
return 'unknown';
|
||
}
|
||
|
||
function mm_twitch_get_channel_from_url( $url ) {
|
||
if ( preg_match( '/twitch\.tv\/([a-zA-Z0-9_]+)(?:\/|\?|$)/', (string) $url, $m ) ) {
|
||
return strtolower( $m[1] );
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
function mm_twitch_get_app_token() {
|
||
$client_id = get_theme_mod( 'twitch_client_id', '' );
|
||
$client_secret = get_theme_mod( 'twitch_client_secret', '' );
|
||
|
||
if ( empty( $client_id ) || empty( $client_secret ) ) {
|
||
return false;
|
||
}
|
||
|
||
$cache_key = 'mm_twitch_app_token';
|
||
$cached = get_transient( $cache_key );
|
||
if ( ! empty( $cached ) ) {
|
||
return $cached;
|
||
}
|
||
|
||
$response = wp_remote_post( 'https://id.twitch.tv/oauth2/token', array(
|
||
'timeout' => 8,
|
||
'body' => array(
|
||
'client_id' => $client_id,
|
||
'client_secret' => $client_secret,
|
||
'grant_type' => 'client_credentials',
|
||
),
|
||
) );
|
||
|
||
if ( is_wp_error( $response ) ) {
|
||
return false;
|
||
}
|
||
|
||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||
if ( empty( $data['access_token'] ) || empty( $data['expires_in'] ) ) {
|
||
return false;
|
||
}
|
||
|
||
$ttl = max( 60, (int) $data['expires_in'] - 60 );
|
||
set_transient( $cache_key, $data['access_token'], $ttl );
|
||
|
||
return $data['access_token'];
|
||
}
|
||
|
||
function mm_twitch_is_live( $channel ) {
|
||
$channel = sanitize_text_field( (string) $channel );
|
||
if ( $channel === '' ) {
|
||
return false;
|
||
}
|
||
|
||
$cache_key = 'mm_twitch_live_' . $channel;
|
||
$cached = get_transient( $cache_key );
|
||
if ( false !== $cached ) {
|
||
return $cached === 'live';
|
||
}
|
||
|
||
$client_id = get_theme_mod( 'twitch_client_id', '' );
|
||
$token = mm_twitch_get_app_token();
|
||
if ( empty( $client_id ) || empty( $token ) ) {
|
||
return false;
|
||
}
|
||
|
||
$url = add_query_arg( array(
|
||
'user_login' => $channel,
|
||
), 'https://api.twitch.tv/helix/streams' );
|
||
|
||
$response = wp_remote_get( $url, array(
|
||
'timeout' => 8,
|
||
'headers' => array(
|
||
'Client-ID' => $client_id,
|
||
'Authorization' => 'Bearer ' . $token,
|
||
),
|
||
) );
|
||
|
||
if ( is_wp_error( $response ) ) {
|
||
return false;
|
||
}
|
||
|
||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||
$is_live = ! empty( $data['data'][0] );
|
||
set_transient( $cache_key, $is_live ? 'live' : 'offline', 2 * MINUTE_IN_SECONDS );
|
||
|
||
return $is_live;
|
||
}
|
||
|
||
function mm_video_get_youtube_player_url( $identifier, $mode = 'video' ) {
|
||
$params = 'autoplay=0&rel=0&modestbranding=1';
|
||
|
||
if ( $mode === 'channel' ) {
|
||
return 'https://www.youtube.com/embed/live_stream?channel=' . rawurlencode( $identifier ) . '&' . $params;
|
||
}
|
||
|
||
if ( $mode === 'handle-live' ) {
|
||
return 'https://www.youtube.com/embed/' . ltrim( $identifier ) . '/live?' . $params;
|
||
}
|
||
|
||
return 'https://www.youtube.com/embed/' . rawurlencode( $identifier ) . '?' . $params;
|
||
}
|
||
|
||
function mm_video_get_youtube_handle_from_url( $url ) {
|
||
if ( preg_match( '~youtube\.com/(@[A-Za-z0-9._-]+)(?:/.*)?$~i', (string) $url, $matches ) ) {
|
||
return sanitize_text_field( $matches[1] );
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
function mm_video_extract_youtube_live_video_id( $html ) {
|
||
$patterns = array(
|
||
'/"canonicalBaseUrl":"\\/watch\?v=([A-Za-z0-9_-]{11})"/i',
|
||
'/"watchEndpoint":\{"videoId":"([A-Za-z0-9_-]{11})"/i',
|
||
'/\/watch\?v=([A-Za-z0-9_-]{11})\\u0026/i',
|
||
'/"videoId":"([A-Za-z0-9_-]{11})".{0,600}?"isLiveNow":true/is',
|
||
'/"videoId":"([A-Za-z0-9_-]{11})".{0,600}?"style":"LIVE"/is',
|
||
'/"videoId":"([A-Za-z0-9_-]{11})".{0,600}?LIVE_NOW/is',
|
||
'/https:\/\/www\.youtube\.com\/watch\?v=([A-Za-z0-9_-]{11})/i',
|
||
'/<link rel="canonical" href="https:\/\/www\.youtube\.com\/watch\?v=([A-Za-z0-9_-]{11})"/i',
|
||
);
|
||
|
||
foreach ( $patterns as $pattern ) {
|
||
if ( preg_match( $pattern, $html, $matches ) ) {
|
||
return $matches[1];
|
||
}
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Prüft ob ein YouTube Video/Stream tatsächlich LIVE ist (optional mit API)
|
||
* @param string $video_id YouTube Video ID
|
||
* @return bool|null true wenn live, false wenn offline, null wenn unbekannt
|
||
*/
|
||
function mm_video_check_youtube_live_status( $video_id ) {
|
||
if ( empty( $video_id ) ) {
|
||
return null;
|
||
}
|
||
|
||
// Cache-Check
|
||
$cache_key = 'mm_yt_status_' . $video_id;
|
||
$cached = get_transient( $cache_key );
|
||
if ( false !== $cached ) {
|
||
return $cached === 'live';
|
||
}
|
||
|
||
// YouTube API Key: Erst Customizer, dann wp-config.php Fallback
|
||
$api_key = get_theme_mod( 'youtube_api_key', '' );
|
||
if ( empty( $api_key ) && defined( 'YOUTUBE_API_KEY' ) ) {
|
||
$api_key = YOUTUBE_API_KEY;
|
||
}
|
||
|
||
if ( ! empty( $api_key ) ) {
|
||
// Mit API prüfen
|
||
$url = sprintf(
|
||
'https://www.googleapis.com/youtube/v3/videos?id=%s&part=snippet,liveStreamingDetails&key=%s',
|
||
rawurlencode( $video_id ),
|
||
rawurlencode( $api_key )
|
||
);
|
||
|
||
$response = wp_remote_get( $url, array( 'timeout' => 5 ) );
|
||
if ( ! is_wp_error( $response ) ) {
|
||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||
if ( ! empty( $data['items'][0] ) ) {
|
||
$state = $data['items'][0]['snippet']['liveBroadcastContent'] ?? '';
|
||
$is_live = ( $state === 'live' );
|
||
set_transient( $cache_key, $is_live ? 'live' : 'offline', 2 * MINUTE_IN_SECONDS );
|
||
return $is_live;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Fallback: Wenn keine API, gehen wir davon aus dass die video_id aktuell ist
|
||
// weil sie von mm_video_resolve_youtube_live_video_id() kam
|
||
set_transient( $cache_key, 'live', 2 * MINUTE_IN_SECONDS );
|
||
return true;
|
||
}
|
||
|
||
function mm_video_resolve_youtube_live_video_id( $profile_url = '', $youtube_channel_id = '' ) {
|
||
$profile_url = trim( (string) $profile_url );
|
||
$youtube_channel_id = trim( (string) $youtube_channel_id );
|
||
$cache_key = 'mm_yt_live_v2_' . md5( strtolower( $profile_url . '|' . $youtube_channel_id ) );
|
||
$cached = get_transient( $cache_key );
|
||
|
||
if ( is_array( $cached ) && array_key_exists( 'video_id', $cached ) ) {
|
||
return $cached['video_id'];
|
||
}
|
||
|
||
$candidate_urls = array();
|
||
$handle = mm_video_get_youtube_handle_from_url( $profile_url );
|
||
|
||
if ( $youtube_channel_id && preg_match( '/^UC[a-zA-Z0-9_-]+$/', $youtube_channel_id ) ) {
|
||
$candidate_urls[] = 'https://www.youtube.com/channel/' . rawurlencode( $youtube_channel_id ) . '/live';
|
||
$candidate_urls[] = 'https://www.youtube.com/channel/' . rawurlencode( $youtube_channel_id ) . '/streams';
|
||
}
|
||
|
||
if ( $handle ) {
|
||
$candidate_urls[] = 'https://www.youtube.com/' . rawurlencode( ltrim( $handle, '/' ) ) . '/live';
|
||
$candidate_urls[] = 'https://www.youtube.com/' . rawurlencode( ltrim( $handle, '/' ) ) . '/streams';
|
||
}
|
||
|
||
if ( $profile_url ) {
|
||
$candidate_urls[] = untrailingslashit( $profile_url ) . '/live';
|
||
$candidate_urls[] = untrailingslashit( $profile_url ) . '/streams';
|
||
}
|
||
|
||
$candidate_urls = array_values( array_unique( array_filter( $candidate_urls ) ) );
|
||
$request_args = array(
|
||
'timeout' => 10,
|
||
'redirection' => 5,
|
||
'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
|
||
'headers' => array(
|
||
'Accept-Language' => 'en-US,en;q=0.9,de;q=0.8',
|
||
),
|
||
);
|
||
|
||
foreach ( $candidate_urls as $candidate_url ) {
|
||
$response = wp_remote_get( $candidate_url, $request_args );
|
||
|
||
if ( is_wp_error( $response ) ) {
|
||
continue;
|
||
}
|
||
|
||
$body = wp_remote_retrieve_body( $response );
|
||
if ( ! is_string( $body ) || $body === '' ) {
|
||
continue;
|
||
}
|
||
|
||
$video_id = mm_video_extract_youtube_live_video_id( $body );
|
||
if ( $video_id ) {
|
||
set_transient( $cache_key, array( 'video_id' => $video_id ), 2 * MINUTE_IN_SECONDS );
|
||
return $video_id;
|
||
}
|
||
}
|
||
|
||
set_transient( $cache_key, array( 'video_id' => '' ), 60 );
|
||
return '';
|
||
}
|
||
|
||
function mm_video_get_livestream_data( $profile_url = '', $player_url = '', $youtube_channel_id = '' ) {
|
||
if ( empty( $profile_url ) && empty( $player_url ) && empty( $youtube_channel_id ) ) {
|
||
return false;
|
||
}
|
||
|
||
$profile_url = trim( $profile_url );
|
||
$player_url = trim( $player_url );
|
||
$youtube_channel_id = trim( $youtube_channel_id );
|
||
$source_url = $player_url ? $player_url : $profile_url;
|
||
$parent_host = parse_url( home_url(), PHP_URL_HOST );
|
||
$data = array(
|
||
'profile_url' => esc_url_raw( $profile_url ? $profile_url : $player_url ),
|
||
'platform' => 'unknown',
|
||
'label' => __( 'Livestream', 'minecraft-modern-theme' ),
|
||
'icon' => 'fas fa-tower-broadcast',
|
||
'color' => '#00d4ff',
|
||
'cta' => __( 'Profil öffnen', 'minecraft-modern-theme' ),
|
||
'embed_url' => '',
|
||
'video_id' => '',
|
||
'channel' => '',
|
||
'channel_display' => '',
|
||
);
|
||
|
||
if ( ! empty( $youtube_channel_id ) && preg_match( '/^UC[a-zA-Z0-9_-]+$/', $youtube_channel_id ) ) {
|
||
$resolved_video_id = mm_video_resolve_youtube_live_video_id( $profile_url, $youtube_channel_id );
|
||
|
||
$data['platform'] = 'youtube';
|
||
$data['label'] = __( 'YouTube Livestream', 'minecraft-modern-theme' );
|
||
$data['icon'] = 'fab fa-youtube';
|
||
$data['color'] = '#ff0000';
|
||
$data['cta'] = __( 'Zum YouTube-Kanal', 'minecraft-modern-theme' );
|
||
$data['channel'] = $youtube_channel_id;
|
||
$data['channel_display'] = $youtube_channel_id;
|
||
$data['video_id'] = $resolved_video_id;
|
||
$data['embed_url'] = $resolved_video_id ? mm_video_get_youtube_player_url( $resolved_video_id, 'video' ) : '';
|
||
|
||
if ( preg_match( '~youtube\.com/(@[A-Za-z0-9._-]+)(?:/.*)?$~i', $profile_url, $handle_matches ) ) {
|
||
$data['channel_display'] = sanitize_text_field( $handle_matches[1] );
|
||
}
|
||
|
||
if ( empty( $data['profile_url'] ) ) {
|
||
$data['profile_url'] = 'https://www.youtube.com/channel/' . rawurlencode( $youtube_channel_id );
|
||
}
|
||
|
||
if ( empty( $player_url ) ) {
|
||
return $data;
|
||
}
|
||
}
|
||
|
||
if ( empty( $source_url ) ) {
|
||
return false;
|
||
}
|
||
|
||
if ( preg_match( '/youtube\.com|youtu\.be/', $source_url ) && preg_match( '/(?:youtube\.com\/(?:watch\?v=|shorts\/|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/', $source_url ) ) {
|
||
$data['platform'] = 'youtube';
|
||
$data['label'] = __( 'YouTube Livestream', 'minecraft-modern-theme' );
|
||
$data['icon'] = 'fab fa-youtube';
|
||
$data['color'] = '#ff0000';
|
||
$data['cta'] = __( 'Zum YouTube-Kanal', 'minecraft-modern-theme' );
|
||
preg_match( '/(?:youtube\.com\/(?:watch\?v=|shorts\/|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/', $source_url, $video_match );
|
||
$data['video_id'] = ! empty( $video_match[1] ) ? $video_match[1] : '';
|
||
$data['embed_url'] = ! empty( $video_match[1] ) ? mm_video_get_youtube_player_url( $video_match[1], 'video' ) : '';
|
||
return $data;
|
||
}
|
||
|
||
if ( preg_match( '~twitch\.tv/([A-Za-z0-9_]+)(?:/)?(?:\?.*)?$~i', $source_url, $matches ) && strtolower( $matches[1] ) !== 'videos' ) {
|
||
$channel = sanitize_key( $matches[1] );
|
||
$data['platform'] = 'twitch';
|
||
$data['label'] = __( 'Twitch Livestream', 'minecraft-modern-theme' );
|
||
$data['icon'] = 'fab fa-twitch';
|
||
$data['color'] = '#9146ff';
|
||
$data['cta'] = __( 'Zum Twitch-Kanal', 'minecraft-modern-theme' );
|
||
$data['channel'] = $channel;
|
||
$data['channel_display'] = '@' . $channel;
|
||
$data['embed_url'] = 'https://player.twitch.tv/?channel=' . rawurlencode( $channel ) . '&parent=' . rawurlencode( $parent_host ) . '&autoplay=false';
|
||
return $data;
|
||
}
|
||
|
||
if ( preg_match( '~kick\.com/([A-Za-z0-9_]+)(?:/)?(?:\?.*)?$~i', $source_url, $matches ) ) {
|
||
$channel = sanitize_key( $matches[1] );
|
||
$data['platform'] = 'kick';
|
||
$data['label'] = __( 'Kick Livestream', 'minecraft-modern-theme' );
|
||
$data['icon'] = 'fas fa-satellite-dish';
|
||
$data['color'] = '#53fc18';
|
||
$data['cta'] = __( 'Zum Kick-Kanal', 'minecraft-modern-theme' );
|
||
$data['channel'] = $channel;
|
||
$data['channel_display'] = '@' . $channel;
|
||
$data['embed_url'] = 'https://player.kick.com/' . rawurlencode( $channel );
|
||
return $data;
|
||
}
|
||
|
||
if ( preg_match( '~youtube\.com/channel/(UC[a-zA-Z0-9_-]+)~i', $source_url, $matches ) ) {
|
||
$channel_id = sanitize_text_field( $matches[1] );
|
||
$resolved_video_id = mm_video_resolve_youtube_live_video_id( $source_url, $channel_id );
|
||
$data['platform'] = 'youtube';
|
||
$data['label'] = __( 'YouTube Livestream', 'minecraft-modern-theme' );
|
||
$data['icon'] = 'fab fa-youtube';
|
||
$data['color'] = '#ff0000';
|
||
$data['cta'] = __( 'Zum YouTube-Kanal', 'minecraft-modern-theme' );
|
||
$data['channel'] = $channel_id;
|
||
$data['channel_display'] = $channel_id;
|
||
$data['video_id'] = $resolved_video_id;
|
||
$data['embed_url'] = $resolved_video_id ? mm_video_get_youtube_player_url( $resolved_video_id, 'video' ) : '';
|
||
return $data;
|
||
}
|
||
|
||
if ( preg_match( '~youtube\.com/(@[A-Za-z0-9._-]+)(?:/.*)?$~i', $source_url, $matches ) ) {
|
||
$handle = sanitize_text_field( $matches[1] );
|
||
$resolved_video_id = mm_video_resolve_youtube_live_video_id( $source_url, '' );
|
||
$data['platform'] = 'youtube';
|
||
$data['label'] = __( 'YouTube Livestream', 'minecraft-modern-theme' );
|
||
$data['icon'] = 'fab fa-youtube';
|
||
$data['color'] = '#ff0000';
|
||
$data['cta'] = __( 'Zum YouTube-Kanal', 'minecraft-modern-theme' );
|
||
$data['channel'] = ltrim( $handle, '@' );
|
||
$data['channel_display'] = $handle;
|
||
$data['video_id'] = $resolved_video_id;
|
||
$data['embed_url'] = $resolved_video_id ? mm_video_get_youtube_player_url( $resolved_video_id, 'video' ) : '';
|
||
return $data;
|
||
}
|
||
|
||
if ( preg_match( '~youtube\.com/(?:c|user)/([A-Za-z0-9._-]+)(?:/.*)?$~i', $source_url, $matches ) ) {
|
||
$channel_name = sanitize_text_field( $matches[1] );
|
||
$resolved_video_id = mm_video_resolve_youtube_live_video_id( $source_url, '' );
|
||
$data['platform'] = 'youtube';
|
||
$data['label'] = __( 'YouTube Livestream', 'minecraft-modern-theme' );
|
||
$data['icon'] = 'fab fa-youtube';
|
||
$data['color'] = '#ff0000';
|
||
$data['cta'] = __( 'Zum YouTube-Kanal', 'minecraft-modern-theme' );
|
||
$data['channel'] = $channel_name;
|
||
$data['channel_display'] = '@' . ltrim( $channel_name, '@' );
|
||
$data['video_id'] = $resolved_video_id;
|
||
$data['embed_url'] = $resolved_video_id ? mm_video_get_youtube_player_url( $resolved_video_id, 'video' ) : '';
|
||
return $data;
|
||
}
|
||
|
||
if ( strpos( $source_url, 'youtube.com' ) !== false || strpos( $source_url, 'youtu.be' ) !== false ) {
|
||
$data['platform'] = 'youtube';
|
||
$data['label'] = __( 'YouTube Livestream', 'minecraft-modern-theme' );
|
||
$data['icon'] = 'fab fa-youtube';
|
||
$data['color'] = '#ff0000';
|
||
$data['cta'] = __( 'Zum YouTube-Kanal', 'minecraft-modern-theme' );
|
||
}
|
||
|
||
return $data;
|
||
}
|
||
|
||
function mm_video_get_livestream_item( $post_id ) {
|
||
$stream_url = get_post_meta( $post_id, '_mm_livestream_url', true );
|
||
$player_url = get_post_meta( $post_id, '_mm_livestream_player_url', true );
|
||
$owner_meta = trim( get_post_meta( $post_id, '_mm_livestream_owner', true ) );
|
||
$youtube_channel_id = get_post_meta( $post_id, '_mm_livestream_youtube_channel_id', true );
|
||
$stream = mm_video_get_livestream_data( $stream_url, $player_url, $youtube_channel_id );
|
||
|
||
if ( ! $stream || empty( $stream['profile_url'] ) ) {
|
||
return false;
|
||
}
|
||
|
||
$stream_title = trim( get_the_title( $post_id ) );
|
||
if ( empty( $stream_title ) || $stream_title === '(kein Titel)' || stripos( $stream_title, 'Automatisch gespeicherter Entwurf' ) !== false || stripos( $stream_title, 'Auto Draft' ) !== false ) {
|
||
$stream_title = ! empty( $stream['channel_display'] ) ? $stream['channel_display'] : $stream['label'];
|
||
}
|
||
|
||
$stream_excerpt = has_excerpt( $post_id ) ? get_the_excerpt( $post_id ) : '';
|
||
$owner = $owner_meta;
|
||
if ( empty( $owner ) ) {
|
||
$owner = ! empty( $stream['channel_display'] ) ? $stream['channel_display'] : $stream_title;
|
||
}
|
||
|
||
return array(
|
||
'post_id' => $post_id,
|
||
'owner' => $owner,
|
||
'title' => $stream_title,
|
||
'description' => $stream_excerpt,
|
||
'profile_url' => $stream['profile_url'],
|
||
'channel' => $stream['channel'],
|
||
'stream' => $stream,
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Automatische YouTube-Live-Erkennung via @Handle (Optimiert)
|
||
*/
|
||
|
||
/**
|
||
* 1. Hilfsfunktion: Wandelt @Handle in eine Channel-ID um
|
||
*/
|
||
function mm_get_channel_id_by_handle( $handle ) {
|
||
$api_key = get_theme_mod( 'youtube_api_key' );
|
||
if ( empty( $api_key ) || empty( $handle ) ) {
|
||
return false;
|
||
}
|
||
|
||
// Handle normalisieren (ohne @)
|
||
$handle = ltrim( $handle, '@' );
|
||
|
||
// Cache für die Channel-ID (diese ändert sich nie, daher 30 Tage speichern)
|
||
$cache_key = 'mm_id_for_' . $handle;
|
||
$channel_id = get_transient( $cache_key );
|
||
if ( false !== $channel_id ) {
|
||
return $channel_id;
|
||
}
|
||
|
||
// Suche Kanal zum Handle
|
||
$url = 'https://www.googleapis.com/youtube/v3/search?part=snippet&q=' . urlencode( '@' . $handle ) . '&type=channel&maxResults=1&key=' . $api_key;
|
||
|
||
$response = wp_remote_get( $url );
|
||
if ( is_wp_error( $response ) ) {
|
||
return false;
|
||
}
|
||
|
||
$data = json_decode( wp_remote_retrieve_body( $response ) );
|
||
|
||
if ( ! empty( $data->items[0]->snippet->channelId ) ) {
|
||
$id = $data->items[0]->snippet->channelId;
|
||
set_transient( $cache_key, $id, DAY_IN_SECONDS * 30 );
|
||
return $id;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 2. Hauptfunktion: Findet die Video-ID des aktuellen Livestreams
|
||
*/
|
||
function mm_get_youtube_live_id_from_handle( $handle ) {
|
||
$api_key = get_theme_mod( 'youtube_api_key' );
|
||
if ( empty( $api_key ) ) {
|
||
return false;
|
||
}
|
||
|
||
// 1. Kanal-ID zum Handle finden
|
||
$channel_id = mm_get_channel_id_by_handle( $handle );
|
||
if ( ! $channel_id ) {
|
||
return false;
|
||
}
|
||
|
||
// 2. Aktuellen Livestream in diesem Kanal suchen
|
||
$cache_key_live = 'mm_live_status_' . $channel_id;
|
||
$live_id = get_transient( $cache_key_live );
|
||
if ( false !== $live_id ) {
|
||
return ( $live_id === 'none' ) ? false : $live_id;
|
||
}
|
||
|
||
// Wir suchen direkt nach dem Live-Event des Kanals
|
||
$url = 'https://www.googleapis.com/youtube/v3/search?part=id&channelId=' . $channel_id . '&eventType=live&type=video&key=' . $api_key;
|
||
|
||
$response = wp_remote_get( $url );
|
||
if ( is_wp_error( $response ) ) {
|
||
return false;
|
||
}
|
||
|
||
$data = json_decode( wp_remote_retrieve_body( $response ) );
|
||
|
||
if ( ! empty( $data->items[0]->id->videoId ) ) {
|
||
$video_id = $data->items[0]->id->videoId;
|
||
set_transient( $cache_key_live, $video_id, 2 * MINUTE_IN_SECONDS ); // Nur 2 Min für schnellere Reaktion
|
||
return $video_id;
|
||
}
|
||
|
||
// Wenn nicht live, 'none' speichern, um API-Anfragen zu drosseln
|
||
set_transient( $cache_key_live, 'none', 2 * MINUTE_IN_SECONDS );
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 3. Update für mm_video_get_livestream_groups - Hybrid-System
|
||
* Zeigt ALLE konfigurierten Livestreams an:
|
||
* - Livestream-Posts (Hauptmethode für mehrere Kanäle)
|
||
* - Optional: Customizer @Handle (für einzelnen Hauptkanal)
|
||
*/
|
||
function mm_video_get_livestream_groups() {
|
||
$groups = array();
|
||
$api_key = get_theme_mod( 'youtube_api_key', '' );
|
||
|
||
// === METHODE 1: Livestream-Posts (IMMER abfragen) ===
|
||
$posts = get_posts( array(
|
||
'post_type' => 'mm_livestream',
|
||
'post_status' => 'publish',
|
||
'posts_per_page' => -1,
|
||
'orderby' => 'ID',
|
||
'order' => 'ASC',
|
||
) );
|
||
|
||
if ( ! empty( $posts ) ) {
|
||
foreach ( $posts as $post ) {
|
||
$profile_url = get_post_meta( $post->ID, '_mm_livestream_url', true );
|
||
$stream_url = get_post_meta( $post->ID, '_mm_livestream_player_url', true );
|
||
$owner = get_post_meta( $post->ID, '_mm_livestream_owner', true );
|
||
$channel_id = '';
|
||
|
||
// Versuche Channel-ID aus Profil-URL zu extrahieren (nur für YouTube)
|
||
if ( ! empty( $profile_url ) && strpos( $profile_url, 'youtube.com' ) !== false ) {
|
||
// Channel-URL mit UC-ID
|
||
if ( preg_match( '~/channel/(UC[a-zA-Z0-9_-]+)~', $profile_url, $m ) ) {
|
||
$channel_id = $m[1];
|
||
}
|
||
// @Handle -> über API auflösen
|
||
elseif ( preg_match( '~/@([a-zA-Z0-9_.-]+)(?:/|$)~', $profile_url, $m ) && ! empty( $api_key ) ) {
|
||
$channel_id = mm_get_channel_id_by_handle( $m[1] );
|
||
}
|
||
}
|
||
|
||
// YouTube-Livestream: Prüfe ob live via API
|
||
if ( ! empty( $channel_id ) && ! empty( $api_key ) ) {
|
||
$cache_key_live = 'mm_live_status_' . $channel_id;
|
||
$live_id = get_transient( $cache_key_live );
|
||
|
||
if ( false === $live_id ) {
|
||
$search_url = add_query_arg( array(
|
||
'part' => 'id',
|
||
'channelId' => $channel_id,
|
||
'eventType' => 'live',
|
||
'type' => 'video',
|
||
'key' => $api_key,
|
||
), 'https://www.googleapis.com/youtube/v3/search' );
|
||
|
||
$response = wp_remote_get( $search_url, array( 'timeout' => 10 ) );
|
||
|
||
if ( ! is_wp_error( $response ) ) {
|
||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||
|
||
if ( isset( $data['items'][0]['id']['videoId'] ) ) {
|
||
$live_id = $data['items'][0]['id']['videoId'];
|
||
set_transient( $cache_key_live, $live_id, 2 * MINUTE_IN_SECONDS );
|
||
} else {
|
||
set_transient( $cache_key_live, 'none', 2 * MINUTE_IN_SECONDS );
|
||
$live_id = false;
|
||
}
|
||
} else {
|
||
$live_id = false;
|
||
}
|
||
} elseif ( $live_id === 'none' ) {
|
||
$live_id = false;
|
||
}
|
||
|
||
// Nur hinzufügen wenn live
|
||
if ( $live_id && $live_id !== 'none' ) {
|
||
$groups[] = array(
|
||
'title' => $post->post_title,
|
||
'platform' => 'youtube',
|
||
'yt_id' => $live_id,
|
||
'handle' => $profile_url,
|
||
);
|
||
}
|
||
}
|
||
// Andere Plattformen (Twitch, etc.): Prüfe zuerst direkte Stream-URL, sonst Profil-URL
|
||
elseif ( ! empty( $stream_url ) || ! empty( $profile_url ) ) {
|
||
$use_url = ! empty( $stream_url ) ? $stream_url : $profile_url;
|
||
$embed_url = mm_video_get_embed_url( $use_url );
|
||
|
||
// Nur Live-Streams anzeigen (Twitch muss live sein)
|
||
if ( $embed_url ) {
|
||
$platform = mm_video_get_type( $use_url );
|
||
|
||
if ( $platform !== 'twitch' ) {
|
||
continue;
|
||
}
|
||
|
||
$channel = mm_twitch_get_channel_from_url( $use_url );
|
||
if ( ! mm_twitch_is_live( $channel ) ) {
|
||
continue;
|
||
}
|
||
|
||
$groups[] = array(
|
||
'title' => $post->post_title,
|
||
'platform' => $platform,
|
||
'embed_url' => $embed_url,
|
||
'profile_url' => $profile_url,
|
||
'owner' => $owner,
|
||
);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return $groups;
|
||
}
|
||
|
||
/**
|
||
* Debug-Informationen für Livestream-System
|
||
*/
|
||
function mm_video_get_api_livestream_debug() {
|
||
if ( ! is_user_logged_in() || ! current_user_can( 'edit_posts' ) ) {
|
||
return array();
|
||
}
|
||
|
||
$api_key = get_theme_mod( 'youtube_api_key', '' );
|
||
|
||
// Zähle Livestream-Posts
|
||
$posts_count = wp_count_posts( 'mm_livestream' );
|
||
$published_posts = isset( $posts_count->publish ) ? $posts_count->publish : 0;
|
||
|
||
// === Fall 1: Keine Konfiguration ===
|
||
if ( $published_posts === 0 ) {
|
||
return array(
|
||
'status' => 'error',
|
||
'message' => 'Keine Livestream-Posts gefunden',
|
||
'hint' => 'Erstelle Livestream-Posts über "Livestreams → Neu"',
|
||
);
|
||
}
|
||
|
||
// === Fall 2: API Key fehlt (nur Warnung) ===
|
||
if ( empty( $api_key ) ) {
|
||
return array(
|
||
'status' => 'warning',
|
||
'message' => 'Kein YouTube API Key',
|
||
'hint' => 'API Key wird für YouTube Live-Erkennung benötigt. Twitch-Streams funktionieren ohne.',
|
||
'posts_count' => $published_posts,
|
||
);
|
||
}
|
||
|
||
// === Fall 3: Alles OK ===
|
||
return array(
|
||
'status' => 'ok',
|
||
'posts_count' => $published_posts,
|
||
'api_key_length' => strlen( $api_key ),
|
||
);
|
||
}
|
||
|
||
function mm_video_get_hidden_livestream_count() {
|
||
// Für API-basiertes System nicht relevant
|
||
return 0;
|
||
}
|
||
|
||
function mm_video_get_livestream_debug_rows() {
|
||
// Ersetzt durch mm_video_get_api_livestream_debug()
|
||
return array();
|
||
}
|
||
|
||
function mm_video_render_livestream_group( $group, $index = 0 ) {
|
||
// Format 1: Neues API-YouTube-Format mit yt_id (Customizer oder Posts)
|
||
if ( isset( $group['yt_id'] ) && isset( $group['platform'] ) && $group['platform'] === 'youtube' ) {
|
||
$video_id = trim( (string) $group['yt_id'] );
|
||
$title = isset( $group['title'] ) ? $group['title'] : __( 'Live', 'minecraft-modern-theme' );
|
||
$handle = isset( $group['handle'] ) ? trim( (string) $group['handle'] ) : '';
|
||
|
||
if ( empty( $video_id ) ) {
|
||
return '';
|
||
}
|
||
|
||
$embed_url = 'https://www.youtube-nocookie.com/embed/' . rawurlencode( $video_id ) . '?autoplay=0&rel=0&modestbranding=1&playsinline=1';
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="video-livestream-api-simple">
|
||
<div class="responsive-video">
|
||
<iframe
|
||
src="<?php echo esc_url( $embed_url ); ?>"
|
||
allow="autoplay; encrypted-media; picture-in-picture"
|
||
allowfullscreen
|
||
loading="lazy"
|
||
title="<?php echo esc_attr( $title ); ?>"></iframe>
|
||
</div>
|
||
<div class="video-livestream-meta">
|
||
<?php if ( ! empty( $handle ) ) : ?>
|
||
<a href="https://www.youtube.com/<?php echo esc_attr( $handle ); ?>" target="_blank" rel="noopener noreferrer" class="video-livestream-channel-link">
|
||
<i class="fab fa-youtube"></i>
|
||
<?php echo esc_html( $title ); ?>
|
||
</a>
|
||
<?php else : ?>
|
||
<span class="video-livestream-channel-link">
|
||
<i class="fab fa-youtube"></i>
|
||
<?php echo esc_html( $title ); ?>
|
||
</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
// Format 2: Einfaches Embed-Format (andere Plattformen via Posts)
|
||
if ( isset( $group['embed_url'] ) && ! empty( $group['embed_url'] ) ) {
|
||
$title = isset( $group['title'] ) ? $group['title'] : __( 'Live', 'minecraft-modern-theme' );
|
||
$embed_url = $group['embed_url'];
|
||
$profile_url = isset( $group['profile_url'] ) ? $group['profile_url'] : '';
|
||
$platform = isset( $group['platform'] ) ? $group['platform'] : 'unknown';
|
||
|
||
if ( $platform === 'youtube' && isset( $group['video_id'] ) && ! empty( $group['video_id'] ) ) {
|
||
$embed_url = 'https://www.youtube-nocookie.com/embed/' . rawurlencode( (string) $group['video_id'] ) . '?autoplay=0&rel=0&modestbranding=1&playsinline=1';
|
||
}
|
||
|
||
$platform_icons = array(
|
||
'twitch' => array( 'icon' => 'fab fa-twitch', 'color' => '#9146ff' ),
|
||
'vimeo' => array( 'icon' => 'fab fa-vimeo-v', 'color' => '#1ab7ea' ),
|
||
'youtube' => array( 'icon' => 'fab fa-youtube', 'color' => '#ff0000' ),
|
||
);
|
||
$icon = isset( $platform_icons[$platform] ) ? $platform_icons[$platform]['icon'] : 'fas fa-play';
|
||
|
||
ob_start();
|
||
?>
|
||
<div class="video-livestream-api-simple">
|
||
<div class="responsive-video">
|
||
<iframe
|
||
src="<?php echo esc_url( $embed_url ); ?>"
|
||
allow="autoplay; encrypted-media; picture-in-picture"
|
||
allowfullscreen
|
||
loading="lazy"
|
||
title="<?php echo esc_attr( $title ); ?>"></iframe>
|
||
</div>
|
||
<div class="video-livestream-meta">
|
||
<?php if ( ! empty( $profile_url ) ) : ?>
|
||
<a href="<?php echo esc_url( $profile_url ); ?>" target="_blank" rel="noopener noreferrer" class="video-livestream-channel-link">
|
||
<i class="<?php echo esc_attr( $icon ); ?>"></i>
|
||
<?php echo esc_html( $title ); ?>
|
||
</a>
|
||
<?php else : ?>
|
||
<span class="video-livestream-channel-link">
|
||
<i class="<?php echo esc_attr( $icon ); ?>"></i>
|
||
<?php echo esc_html( $title ); ?>
|
||
</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
|
||
// Format 3: Altes Post-basiertes Format mit Items (komplex) - für Rückwärtskompatibilität
|
||
$items = isset( $group['items'] ) ? $group['items'] : array();
|
||
if ( empty( $items ) ) {
|
||
return '';
|
||
}
|
||
|
||
$active_item = $items[0];
|
||
$group_id = 'video-livestream-' . absint( $index );
|
||
$description = ! empty( $group['description'] )
|
||
? $group['description']
|
||
: ( count( $items ) > 1
|
||
? __( 'Mehrere aktive oder gespeicherte Streams dieses Streamers lassen sich hier direkt umschalten.', 'minecraft-modern-theme' )
|
||
: __( 'Der Bereich wird automatisch aus deinem Profil-Link erzeugt und oberhalb der Videos eingebunden.', 'minecraft-modern-theme' ) );
|
||
|
||
ob_start();
|
||
?>
|
||
<section class="video-livestream" aria-label="<?php esc_attr_e( 'Livestream', 'minecraft-modern-theme' ); ?>" id="<?php echo esc_attr( $group_id ); ?>">
|
||
<div class="video-livestream-copy">
|
||
<span class="video-livestream-kicker" style="--stream-accent: <?php echo esc_attr( $active_item['stream']['color'] ); ?>;">
|
||
<i class="<?php echo esc_attr( $active_item['stream']['icon'] ); ?>"></i>
|
||
<?php esc_html_e( 'Livestream', 'minecraft-modern-theme' ); ?>
|
||
</span>
|
||
<h2 class="video-livestream-title"><?php echo esc_html( $group['owner'] ); ?></h2>
|
||
<p class="video-livestream-text"><?php echo esc_html( $description ); ?></p>
|
||
<?php if ( count( $items ) > 1 ) : ?>
|
||
<div class="video-livestream-nav">
|
||
<button type="button" class="video-livestream-nav-btn" data-stream-prev aria-label="<?php esc_attr_e( 'Vorheriger Stream', 'minecraft-modern-theme' ); ?>">
|
||
<i class="fas fa-chevron-left"></i>
|
||
<?php esc_html_e( 'Zurueck', 'minecraft-modern-theme' ); ?>
|
||
</button>
|
||
<span class="video-livestream-nav-count" data-stream-count>1 / <?php echo esc_html( count( $items ) ); ?></span>
|
||
<button type="button" class="video-livestream-nav-btn" data-stream-next aria-label="<?php esc_attr_e( 'Naechster Stream', 'minecraft-modern-theme' ); ?>">
|
||
<?php esc_html_e( 'Weiter', 'minecraft-modern-theme' ); ?>
|
||
<i class="fas fa-chevron-right"></i>
|
||
</button>
|
||
</div>
|
||
<div class="video-livestream-switcher" role="tablist" aria-label="<?php esc_attr_e( 'Stream-Auswahl', 'minecraft-modern-theme' ); ?>">
|
||
<?php foreach ( $items as $item_index => $item ) : ?>
|
||
<button
|
||
type="button"
|
||
class="video-livestream-switch<?php echo $item_index === 0 ? ' is-active' : ''; ?>"
|
||
data-stream-switch
|
||
data-embed-url="<?php echo esc_url( $item['stream']['embed_url'] ); ?>"
|
||
data-profile-url="<?php echo esc_url( $item['profile_url'] ); ?>"
|
||
data-cta="<?php echo esc_attr( $item['stream']['cta'] ); ?>"
|
||
data-icon="<?php echo esc_attr( $item['stream']['icon'] ); ?>"
|
||
data-platform="<?php echo esc_attr( $item['stream']['platform'] ); ?>"
|
||
data-youtube-video-id="<?php echo esc_attr( $item['stream']['video_id'] ); ?>"
|
||
data-title="<?php echo esc_attr( $item['title'] ); ?>"
|
||
data-note="<?php echo esc_attr( ( empty( $item['stream']['embed_url'] ) && $item['stream']['platform'] === 'youtube' ) ? __( 'Aktuell konnte kein laufender YouTube-Livestream fuer diesen Kanal erkannt werden. Der Kanal-Link bleibt aber verfuegbar.', 'minecraft-modern-theme' ) : '' ); ?>"
|
||
aria-selected="<?php echo $item_index === 0 ? 'true' : 'false'; ?>">
|
||
<?php echo esc_html( $item['title'] ); ?>
|
||
</button>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<div class="video-livestream-actions">
|
||
<a class="video-livestream-button" data-livestream-cta href="<?php echo esc_url( $active_item['profile_url'] ); ?>" target="_blank" rel="noopener noreferrer">
|
||
<i class="<?php echo esc_attr( $active_item['stream']['icon'] ); ?>"></i>
|
||
<span><?php echo esc_html( $active_item['stream']['cta'] ); ?></span>
|
||
</a>
|
||
<?php if ( ! empty( $active_item['stream']['channel_display'] ) ) : ?>
|
||
<span class="video-livestream-channel" data-livestream-channel><?php echo esc_html( $active_item['stream']['channel_display'] ); ?></span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<p class="video-livestream-note<?php echo ( empty( $active_item['stream']['embed_url'] ) && $active_item['stream']['platform'] === 'youtube' ) ? '' : ' is-hidden'; ?>" data-livestream-note><?php esc_html_e( 'Aktuell konnte kein laufender YouTube-Livestream fuer diesen Kanal erkannt werden. Der Kanal-Link bleibt aber verfuegbar.', 'minecraft-modern-theme' ); ?></p>
|
||
</div>
|
||
<div class="video-livestream-player-wrap">
|
||
<?php if ( ! empty( $active_item['stream']['embed_url'] ) ) : ?>
|
||
<div class="video-livestream-player" data-livestream-player>
|
||
<iframe
|
||
data-livestream-iframe
|
||
src="<?php echo esc_url( $active_item['stream']['platform'] === 'youtube' && ! empty( $active_item['stream']['video_id'] ) ? 'https://www.youtube-nocookie.com/embed/' . rawurlencode( (string) $active_item['stream']['video_id'] ) . '?autoplay=0&rel=0&modestbranding=1&playsinline=1' : $active_item['stream']['embed_url'] ); ?>"
|
||
title="<?php echo esc_attr( $active_item['title'] ); ?>"
|
||
frameborder="0"
|
||
allowfullscreen
|
||
loading="lazy"
|
||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe>
|
||
</div>
|
||
<div class="video-livestream-placeholder is-hidden" data-livestream-placeholder>
|
||
<i class="<?php echo esc_attr( $active_item['stream']['icon'] ); ?>"></i>
|
||
<p><?php esc_html_e( 'Für diesen Profil-Link ist aktuell kein direkter Player möglich. Der Kanal-Link bleibt aber verfügbar.', 'minecraft-modern-theme' ); ?></p>
|
||
</div>
|
||
<?php else : ?>
|
||
<div class="video-livestream-player is-hidden" data-livestream-player>
|
||
<iframe data-livestream-iframe src="about:blank" title="" frameborder="0" allowfullscreen loading="lazy" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe>
|
||
</div>
|
||
<div class="video-livestream-placeholder" data-livestream-placeholder>
|
||
<i class="<?php echo esc_attr( $active_item['stream']['icon'] ); ?>"></i>
|
||
<p><?php esc_html_e( 'Für diesen Profil-Link ist aktuell kein direkter Player möglich. Der Kanal-Link bleibt aber verfügbar.', 'minecraft-modern-theme' ); ?></p>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</section>
|
||
<?php
|
||
|
||
return ob_get_clean();
|
||
}
|
||
|
||
|
||
// --- 4. Embed HTML rendern ---
|
||
function mm_video_render_embed( $url, $args = array() ) {
|
||
$embed_url = mm_video_get_embed_url( $url );
|
||
if ( ! $embed_url ) return '<p class="mm-video-error">' . __('Ungültige Video-URL.', 'minecraft-modern-theme') . '</p>';
|
||
|
||
$type = mm_video_get_type( $url );
|
||
$title = isset($args['title']) ? esc_attr($args['title']) : __('Video', 'minecraft-modern-theme');
|
||
|
||
if ( $type === 'mp4' ) {
|
||
return '<div class="mm-video-wrapper">'
|
||
. '<video class="mm-video-player" controls preload="metadata" playsinline>'
|
||
. '<source src="' . esc_url($embed_url) . '" type="video/mp4">'
|
||
. __('Dein Browser unterstützt kein HTML5-Video.', 'minecraft-modern-theme')
|
||
. '</video></div>';
|
||
}
|
||
|
||
return '<div class="mm-video-wrapper">'
|
||
. '<iframe src="' . esc_url($embed_url) . '" '
|
||
. 'title="' . $title . '" '
|
||
. 'frameborder="0" allowfullscreen allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share">'
|
||
. '</iframe></div>';
|
||
}
|
||
|
||
|
||
// --- 5. Shortcode: [mm_video url="..."] ---
|
||
// Beispiele:
|
||
// [mm_video url="https://www.youtube.com/watch?v=dQw4w9WgXcQ"]
|
||
// [mm_video url="https://vimeo.com/123456789" title="Mein Video"]
|
||
function mm_video_shortcode( $atts ) {
|
||
$a = shortcode_atts( array(
|
||
'url' => '',
|
||
'title' => __('Video', 'minecraft-modern-theme'),
|
||
), $atts );
|
||
|
||
if ( empty($a['url']) ) return '';
|
||
return mm_video_render_embed( $a['url'], $a );
|
||
}
|
||
add_shortcode( 'mm_video', 'mm_video_shortcode' );
|
||
|
||
|
||
// --- 6. Template-Loader für Video-Archiv und Galerie-Seite ---
|
||
function mm_video_template_loader( $template ) {
|
||
// Archiv (domain.de/videos/)
|
||
if ( is_post_type_archive('mm_video') ) {
|
||
$t = get_template_directory() . '/archive-video.php';
|
||
if ( file_exists($t) ) return $t;
|
||
}
|
||
// Seite mit dem Slug "videos"
|
||
if ( is_page() ) {
|
||
$obj = get_queried_object();
|
||
if ( $obj && $obj->post_name === 'videos' ) {
|
||
$t = get_template_directory() . '/archive-video.php';
|
||
if ( file_exists($t) ) return $t;
|
||
}
|
||
}
|
||
return $template;
|
||
}
|
||
add_filter( 'template_include', 'mm_video_template_loader' );
|
||
|
||
|
||
// --- 7. "Videos"-Seite automatisch anlegen ---
|
||
function mm_video_create_page() {
|
||
if ( ! get_page_by_path('videos') ) {
|
||
wp_insert_post( array(
|
||
'post_title' => __('Videos', 'minecraft-modern-theme'),
|
||
'post_name' => 'videos',
|
||
'post_status' => 'publish',
|
||
'post_type' => 'page',
|
||
'post_author' => 1,
|
||
) );
|
||
}
|
||
}
|
||
add_action( 'after_switch_theme', 'mm_video_create_page' );
|
||
// Auch beim Speichern im Customizer anlegen
|
||
add_action( 'customize_save_after', 'mm_video_create_page' );
|
||
|
||
|
||
// =============================================================================
|
||
// === BEWERBUNGSFORMULAR ======================================================
|
||
// =============================================================================
|
||
|
||
// --- 1. Customizer: Ein/Ausschalten ---
|
||
function mm_bewerbung_customizer( $wp_customize ) {
|
||
$wp_customize->add_section( 'mm_bewerbung_section', array(
|
||
'title' => __( 'Bewerbungsformular', 'minecraft-modern-theme' ),
|
||
'priority' => 80,
|
||
) );
|
||
|
||
$wp_customize->add_setting( 'mm_bewerbung_enabled', array(
|
||
'default' => false,
|
||
'sanitize_callback' => 'wp_validate_boolean',
|
||
) );
|
||
$wp_customize->add_control( 'mm_bewerbung_enabled', array(
|
||
'label' => __( 'Bewerbungsformular aktivieren', 'minecraft-modern-theme' ),
|
||
'description' => __( 'Schaltet die Bewerbungsseite und das Formular ein.', 'minecraft-modern-theme' ),
|
||
'section' => 'mm_bewerbung_section',
|
||
'type' => 'checkbox',
|
||
) );
|
||
|
||
$wp_customize->add_setting( 'mm_bewerbung_title', array(
|
||
'default' => __( 'Bewirb dich bei uns!', 'minecraft-modern-theme' ),
|
||
'sanitize_callback' => 'sanitize_text_field',
|
||
) );
|
||
$wp_customize->add_control( 'mm_bewerbung_title', array(
|
||
'label' => __( 'Titel der Bewerbungsseite', 'minecraft-modern-theme' ),
|
||
'section' => 'mm_bewerbung_section',
|
||
'type' => 'text',
|
||
) );
|
||
|
||
$wp_customize->add_setting( 'mm_bewerbung_desc', array(
|
||
'default' => __( 'Du möchtest Teil unseres Teams werden? Füll das Formular aus und wir melden uns bei dir.', 'minecraft-modern-theme' ),
|
||
'sanitize_callback' => 'sanitize_textarea_field',
|
||
) );
|
||
$wp_customize->add_control( 'mm_bewerbung_desc', array(
|
||
'label' => __( 'Beschreibungstext', 'minecraft-modern-theme' ),
|
||
'section' => 'mm_bewerbung_section',
|
||
'type' => 'textarea',
|
||
) );
|
||
|
||
$wp_customize->add_setting( 'mm_bewerbung_success_msg', array(
|
||
'default' => __( 'Deine Bewerbung wurde erfolgreich eingereicht! Wir melden uns so bald wie möglich bei dir.', 'minecraft-modern-theme' ),
|
||
'sanitize_callback' => 'sanitize_textarea_field',
|
||
) );
|
||
$wp_customize->add_control( 'mm_bewerbung_success_msg', array(
|
||
'label' => __( 'Erfolgsmeldung nach dem Absenden', 'minecraft-modern-theme' ),
|
||
'section' => 'mm_bewerbung_section',
|
||
'type' => 'textarea',
|
||
) );
|
||
|
||
$wp_customize->add_setting( 'mm_bewerbung_min_alter', array(
|
||
'default' => 14,
|
||
'sanitize_callback' => 'absint',
|
||
) );
|
||
$wp_customize->add_control( 'mm_bewerbung_min_alter', array(
|
||
'label' => __( 'Mindestalter', 'minecraft-modern-theme' ),
|
||
'description' => __( 'Bewerbungen unter diesem Alter werden abgelehnt. 0 = kein Limit.', 'minecraft-modern-theme' ),
|
||
'section' => 'mm_bewerbung_section',
|
||
'type' => 'number',
|
||
'input_attrs' => array( 'min' => 0, 'max' => 99 ),
|
||
) );
|
||
}
|
||
add_action( 'customize_register', 'mm_bewerbung_customizer' );
|
||
|
||
|
||
// --- 2. Custom Post Type: Bewerbung ---
|
||
function mm_register_bewerbung_cpt() {
|
||
if ( ! get_theme_mod( 'mm_bewerbung_enabled', false ) ) return;
|
||
|
||
register_post_type( 'mm_bewerbung', array(
|
||
'labels' => array(
|
||
'name' => __( 'Bewerbungen', 'minecraft-modern-theme' ),
|
||
'singular_name' => __( 'Bewerbung', 'minecraft-modern-theme' ),
|
||
'all_items' => __( 'Alle Bewerbungen', 'minecraft-modern-theme' ),
|
||
'menu_name' => __( 'Bewerbungen', 'minecraft-modern-theme' ),
|
||
),
|
||
'public' => false,
|
||
'show_ui' => true,
|
||
'show_in_menu' => true,
|
||
'menu_icon' => 'dashicons-clipboard',
|
||
'menu_position' => 8,
|
||
'supports' => array( 'title' ),
|
||
'capabilities' => array(
|
||
'create_posts' => 'do_not_allow', // Nur über Frontend erstellbar
|
||
),
|
||
'map_meta_cap' => true,
|
||
) );
|
||
}
|
||
add_action( 'init', 'mm_register_bewerbung_cpt' );
|
||
|
||
|
||
// --- 3. Admin: Meta-Box für Bewerbungs-Details ---
|
||
function mm_bewerbung_meta_box() {
|
||
add_meta_box(
|
||
'mm_bewerbung_details',
|
||
__( 'Bewerbungs-Details', 'minecraft-modern-theme' ),
|
||
'mm_bewerbung_meta_box_html',
|
||
'mm_bewerbung', 'normal', 'high'
|
||
);
|
||
add_meta_box(
|
||
'mm_bewerbung_status_box',
|
||
__( 'Status', 'minecraft-modern-theme' ),
|
||
'mm_bewerbung_status_box_html',
|
||
'mm_bewerbung', 'side', 'high'
|
||
);
|
||
}
|
||
add_action( 'add_meta_boxes', 'mm_bewerbung_meta_box' );
|
||
|
||
function mm_bewerbung_meta_box_html( $post ) {
|
||
$fields = array(
|
||
'_mm_bew_mc_name' => __( 'Minecraft Username', 'minecraft-modern-theme' ),
|
||
'_mm_bew_discord' => __( 'Discord Username', 'minecraft-modern-theme' ),
|
||
'_mm_bew_alter' => __( 'Alter', 'minecraft-modern-theme' ),
|
||
'_mm_bew_warum' => __( 'Warum möchtest du mitspielen?', 'minecraft-modern-theme' ),
|
||
'_mm_bew_erfahrung' => __( 'Erfahrung / Vorstellung', 'minecraft-modern-theme' ),
|
||
'_mm_bew_datum' => __( 'Eingereicht am', 'minecraft-modern-theme' ),
|
||
'_mm_bew_ip' => __( 'IP-Adresse', 'minecraft-modern-theme' ),
|
||
);
|
||
echo '<table class="form-table" style="margin:0;">';
|
||
foreach ( $fields as $key => $label ) {
|
||
$val = get_post_meta( $post->ID, $key, true );
|
||
if ( ! $val ) continue;
|
||
$is_long = in_array( $key, array( '_mm_bew_warum', '_mm_bew_erfahrung' ) );
|
||
echo '<tr>';
|
||
echo '<th style="width:180px;padding:10px 0;vertical-align:top;"><strong>' . esc_html($label) . '</strong></th>';
|
||
echo '<td style="padding:10px 0;">';
|
||
if ( $is_long ) {
|
||
echo '<div style="background:#f9f9f9;border:1px solid #ddd;border-radius:4px;padding:10px 14px;line-height:1.6;max-width:700px;white-space:pre-wrap;">' . esc_html($val) . '</div>';
|
||
} else {
|
||
echo '<span style="font-size:14px;">' . esc_html($val) . '</span>';
|
||
}
|
||
echo '</td></tr>';
|
||
}
|
||
echo '</table>';
|
||
}
|
||
|
||
function mm_bewerbung_status_box_html( $post ) {
|
||
$status = get_post_meta( $post->ID, '_mm_bew_status', true ) ?: 'neu';
|
||
wp_nonce_field( 'mm_bew_status_save', 'mm_bew_status_nonce' );
|
||
$options = array(
|
||
'neu' => array( 'label' => __('Neu','minecraft-modern-theme'), 'color' => '#0073aa' ),
|
||
'in_pruef' => array( 'label' => __('In Prüfung','minecraft-modern-theme'), 'color' => '#f0ad4e' ),
|
||
'angenommen' => array( 'label' => __('Angenommen','minecraft-modern-theme'), 'color' => '#46b450' ),
|
||
'abgelehnt' => array( 'label' => __('Abgelehnt','minecraft-modern-theme'), 'color' => '#dc3232' ),
|
||
);
|
||
echo '<select name="mm_bew_status" style="width:100%;margin-bottom:10px;">';
|
||
foreach ( $options as $val => $opt ) {
|
||
$sel = selected( $status, $val, false );
|
||
echo '<option value="' . esc_attr($val) . '" ' . $sel . '>' . esc_html($opt['label']) . '</option>';
|
||
}
|
||
echo '</select>';
|
||
$cur = isset($options[$status]) ? $options[$status] : $options['neu'];
|
||
echo '<div style="background:' . esc_attr($cur['color']) . ';color:#fff;text-align:center;padding:6px;border-radius:4px;font-weight:600;">' . esc_html($cur['label']) . '</div>';
|
||
|
||
// Admin-Notiz
|
||
$notiz = get_post_meta( $post->ID, '_mm_bew_notiz', true );
|
||
echo '<hr style="margin:12px 0;">';
|
||
echo '<label style="font-weight:600;display:block;margin-bottom:6px;">' . __('Interne Notiz:', 'minecraft-modern-theme') . '</label>';
|
||
echo '<textarea name="mm_bew_notiz" rows="4" style="width:100%;font-size:12px;">' . esc_textarea($notiz) . '</textarea>';
|
||
}
|
||
|
||
function mm_bewerbung_save_status( $post_id ) {
|
||
if ( ! isset($_POST['mm_bew_status_nonce']) || ! wp_verify_nonce($_POST['mm_bew_status_nonce'], 'mm_bew_status_save') ) return;
|
||
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
|
||
if ( ! current_user_can('edit_post', $post_id) ) return;
|
||
if ( isset($_POST['mm_bew_status']) ) {
|
||
update_post_meta( $post_id, '_mm_bew_status', sanitize_text_field($_POST['mm_bew_status']) );
|
||
}
|
||
if ( isset($_POST['mm_bew_notiz']) ) {
|
||
update_post_meta( $post_id, '_mm_bew_notiz', sanitize_textarea_field($_POST['mm_bew_notiz']) );
|
||
}
|
||
}
|
||
add_action( 'save_post', 'mm_bewerbung_save_status' );
|
||
|
||
|
||
// --- 4. Admin-Spalten in der Bewerbungsliste ---
|
||
function mm_bewerbung_columns( $cols ) {
|
||
return array(
|
||
'cb' => $cols['cb'],
|
||
'title' => __( 'Name', 'minecraft-modern-theme' ),
|
||
'mc_name' => __( 'Minecraft', 'minecraft-modern-theme' ),
|
||
'discord' => __( 'Discord', 'minecraft-modern-theme' ),
|
||
'alter' => __( 'Alter', 'minecraft-modern-theme' ),
|
||
'status' => __( 'Status', 'minecraft-modern-theme' ),
|
||
'datum' => __( 'Eingereicht', 'minecraft-modern-theme' ),
|
||
);
|
||
}
|
||
add_filter( 'manage_mm_bewerbung_posts_columns', 'mm_bewerbung_columns' );
|
||
|
||
function mm_bewerbung_column_content( $col, $post_id ) {
|
||
$status_colors = array(
|
||
'neu' => '#0073aa',
|
||
'in_pruef' => '#f0ad4e',
|
||
'angenommen' => '#46b450',
|
||
'abgelehnt' => '#dc3232',
|
||
);
|
||
$status_labels = array(
|
||
'neu' => __('Neu','minecraft-modern-theme'),
|
||
'in_pruef' => __('In Prüfung','minecraft-modern-theme'),
|
||
'angenommen' => __('Angenommen','minecraft-modern-theme'),
|
||
'abgelehnt' => __('Abgelehnt','minecraft-modern-theme'),
|
||
);
|
||
switch ($col) {
|
||
case 'mc_name':
|
||
$mc = get_post_meta($post_id, '_mm_bew_mc_name', true);
|
||
if ($mc) {
|
||
echo '<div style="display:flex;align-items:center;gap:8px;">';
|
||
echo '<img src="https://mc-heads.net/avatar/' . esc_attr($mc) . '/24" style="border-radius:3px;" width="24" height="24" alt="">';
|
||
echo esc_html($mc) . '</div>';
|
||
}
|
||
break;
|
||
case 'discord':
|
||
echo esc_html( get_post_meta($post_id, '_mm_bew_discord', true) );
|
||
break;
|
||
case 'alter':
|
||
echo esc_html( get_post_meta($post_id, '_mm_bew_alter', true) );
|
||
break;
|
||
case 'status':
|
||
$s = get_post_meta($post_id, '_mm_bew_status', true) ?: 'neu';
|
||
$color = isset($status_colors[$s]) ? $status_colors[$s] : '#0073aa';
|
||
$label = isset($status_labels[$s]) ? $status_labels[$s] : $s;
|
||
echo '<span style="background:' . esc_attr($color) . ';color:#fff;padding:2px 10px;border-radius:12px;font-size:12px;font-weight:600;">' . esc_html($label) . '</span>';
|
||
break;
|
||
case 'datum':
|
||
echo esc_html( get_post_meta($post_id, '_mm_bew_datum', true) );
|
||
break;
|
||
}
|
||
}
|
||
add_action( 'manage_mm_bewerbung_posts_custom_column', 'mm_bewerbung_column_content', 10, 2 );
|
||
|
||
|
||
// --- 5. AJAX: Formular absenden ---
|
||
add_action( 'wp_ajax_mm_submit_bewerbung', 'mm_submit_bewerbung' );
|
||
add_action( 'wp_ajax_nopriv_mm_submit_bewerbung', 'mm_submit_bewerbung' );
|
||
|
||
function mm_submit_bewerbung() {
|
||
// Nonce prüfen
|
||
if ( ! isset($_POST['nonce']) || ! wp_verify_nonce($_POST['nonce'], 'mm_bewerbung_nonce') ) {
|
||
wp_send_json_error( array('msg' => __('Sicherheitsfehler. Bitte Seite neu laden.', 'minecraft-modern-theme')) );
|
||
}
|
||
|
||
// Felder validieren
|
||
$mc_name = sanitize_text_field( $_POST['mc_name'] ?? '' );
|
||
$discord = sanitize_text_field( $_POST['discord'] ?? '' );
|
||
$alter_raw = absint( $_POST['alter'] ?? 0 );
|
||
$warum = sanitize_textarea_field( $_POST['warum'] ?? '' );
|
||
$erfahrung = sanitize_textarea_field( $_POST['erfahrung'] ?? '' );
|
||
|
||
$errors = array();
|
||
if ( empty($mc_name) ) $errors[] = __('Minecraft Username ist erforderlich.', 'minecraft-modern-theme');
|
||
if ( empty($discord) ) $errors[] = __('Discord Username ist erforderlich.', 'minecraft-modern-theme');
|
||
if ( $alter_raw < 1 ) $errors[] = __('Bitte gib dein Alter an.', 'minecraft-modern-theme');
|
||
if ( empty($warum) ) $errors[] = __('Bitte erkläre warum du mitspielen möchtest.', 'minecraft-modern-theme');
|
||
if ( empty($erfahrung) ) $errors[] = __('Bitte stell dich kurz vor.', 'minecraft-modern-theme');
|
||
|
||
// Mindestalter prüfen
|
||
$min_alter = absint( get_theme_mod('mm_bewerbung_min_alter', 14) );
|
||
if ( $min_alter > 0 && $alter_raw < $min_alter ) {
|
||
$errors[] = sprintf( __('Du musst mindestens %d Jahre alt sein.', 'minecraft-modern-theme'), $min_alter );
|
||
}
|
||
|
||
// Doppelbewerbung prüfen (gleicher MC-Name in den letzten 30 Tagen)
|
||
$existing = get_posts( array(
|
||
'post_type' => 'mm_bewerbung',
|
||
'post_status' => 'publish',
|
||
'meta_query' => array(
|
||
array( 'key' => '_mm_bew_mc_name', 'value' => $mc_name, 'compare' => '=' ),
|
||
),
|
||
'date_query' => array(
|
||
array( 'after' => '30 days ago' ),
|
||
),
|
||
'numberposts' => 1,
|
||
) );
|
||
if ( $existing ) {
|
||
$errors[] = __('Mit diesem Minecraft-Namen wurde in den letzten 30 Tagen bereits eine Bewerbung eingereicht.', 'minecraft-modern-theme');
|
||
}
|
||
|
||
if ( ! empty($errors) ) {
|
||
wp_send_json_error( array('msg' => implode(' ', $errors)) );
|
||
}
|
||
|
||
// Bewerbung als Post speichern
|
||
$post_id = wp_insert_post( array(
|
||
'post_type' => 'mm_bewerbung',
|
||
'post_status' => 'publish',
|
||
'post_title' => $mc_name . ' – ' . date_i18n('d.m.Y H:i'),
|
||
) );
|
||
|
||
if ( is_wp_error($post_id) ) {
|
||
wp_send_json_error( array('msg' => __('Fehler beim Speichern. Bitte versuche es erneut.', 'minecraft-modern-theme')) );
|
||
}
|
||
|
||
update_post_meta( $post_id, '_mm_bew_mc_name', $mc_name );
|
||
update_post_meta( $post_id, '_mm_bew_discord', $discord );
|
||
update_post_meta( $post_id, '_mm_bew_alter', $alter_raw );
|
||
update_post_meta( $post_id, '_mm_bew_warum', $warum );
|
||
update_post_meta( $post_id, '_mm_bew_erfahrung', $erfahrung );
|
||
update_post_meta( $post_id, '_mm_bew_status', 'neu' );
|
||
update_post_meta( $post_id, '_mm_bew_datum', date_i18n('d.m.Y H:i:s') );
|
||
update_post_meta( $post_id, '_mm_bew_ip', sanitize_text_field( $_SERVER['REMOTE_ADDR'] ?? '' ) );
|
||
|
||
$success_msg = get_theme_mod( 'mm_bewerbung_success_msg', __('Deine Bewerbung wurde erfolgreich eingereicht! Wir melden uns so bald wie möglich bei dir.', 'minecraft-modern-theme') );
|
||
wp_send_json_success( array('msg' => $success_msg) );
|
||
}
|
||
|
||
|
||
// --- 6. Template-Loader ---
|
||
function mm_bewerbung_template_loader( $template ) {
|
||
if ( ! get_theme_mod('mm_bewerbung_enabled', false) ) return $template;
|
||
if ( is_page('bewerbung') ) {
|
||
$t = get_template_directory() . '/page-bewerbung.php';
|
||
if ( file_exists($t) ) return $t;
|
||
}
|
||
return $template;
|
||
}
|
||
add_filter( 'template_include', 'mm_bewerbung_template_loader' );
|
||
|
||
|
||
// --- 7. Seite automatisch anlegen ---
|
||
function mm_bewerbung_create_page() {
|
||
if ( ! get_theme_mod('mm_bewerbung_enabled', false) ) return;
|
||
if ( ! get_page_by_path('bewerbung') ) {
|
||
wp_insert_post( array(
|
||
'post_title' => __('Bewerbung', 'minecraft-modern-theme'),
|
||
'post_name' => 'bewerbung',
|
||
'post_status' => 'publish',
|
||
'post_type' => 'page',
|
||
'post_author' => 1,
|
||
) );
|
||
}
|
||
}
|
||
add_action( 'customize_save_after', 'mm_bewerbung_create_page' );
|