Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 43ee6153dd | |||
| 042a526aba | |||
| bc5e131749 | |||
| 5bbba99f3b | |||
| 46362b5355 | |||
| af25b0a2b0 | |||
| 6d3152047a | |||
| e1a8074e99 | |||
| 43f40a39b0 | |||
| 9f20b9433f | |||
| b9b6e5fa57 | |||
| c08b3d6506 | |||
| 9db3bdff17 | |||
| 6b6cf4e76f | |||
| 4ef8d4a393 | |||
| 2b13b937ec | |||
| 85f96ea145 | |||
| 4a12a88d2c | |||
| b67a6f2d52 | |||
| 82877cb410 | |||
| 2425b154cb | |||
| 170ad670bc | |||
| c74800a91e | |||
| e417f31c99 | |||
| 85d12e832d | |||
| 12d1da2818 | |||
| 3563752968 | |||
| 095e3b5990 | |||
| abb711abbe | |||
| 558f827fa5 | |||
| db2ca87135 | |||
| 62bab14817 | |||
| 5008184633 | |||
| 83bff40565 | |||
| 5a4115222e | |||
| 2ccd1f5769 | |||
| 94975c41fb | |||
| 8be73b9764 | |||
| c2f366e391 | |||
| e530922071 | |||
| 07b09a83c3 | |||
| 2487405491 | |||
| 853e9be519 | |||
| 11f7621ea9 | |||
| 40ef763823 | |||
| bb818139b2 | |||
| 3e7aaf3560 | |||
| 32fb4c8204 | |||
| 2a70e23c6b | |||
| 3fdf178a4b | |||
| 9fc7507037 | |||
| 5beb82d9dd | |||
| 50ebde6b70 | |||
| 2ba14ed9a9 | |||
| 4e16f543a5 | |||
| 7e3f7303c4 | |||
| 0a494f8148 | |||
| 75c3583b11 | |||
| 387ee5586f | |||
| 5e087bb07a | |||
| 21d9e0f56c | |||
| 37b01a5135 | |||
| cc0de6b5dd | |||
| 1a9f2ba8f2 | |||
| be9c444ba2 | |||
| 7870995bab | |||
| 16a4577e6b | |||
| e319e91290 | |||
| b2ba06c1f3 | |||
| dce1de3f68 | |||
| 65f6fbb0a2 | |||
| 9c6931d25d | |||
| 2882231550 | |||
| 7684cae147 | |||
| c2e7ef1b46 | |||
| 1c9b19acda | |||
| 96a71b0254 | |||
| e1dc54463a | |||
| 15403ac652 | |||
| 50343f6dca | |||
| 9ee1e662ea | |||
| 1f8fffb58a | |||
| 2855fbada5 | |||
| 3d08d57d64 | |||
| 5e155c8398 | |||
| c858112d7f | |||
| b90684aa22 | |||
| 9aa5fc2507 | |||
| 53f5d57b32 | |||
| f9bd5558b7 | |||
| 18c07628f5 |
192
Minecraft-Modern-Theme/404.php
Normal file
192
Minecraft-Modern-Theme/404.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php get_header(); ?>
|
||||
|
||||
<main id="primary" class="site-main">
|
||||
<div class="container">
|
||||
<div class="content-area">
|
||||
|
||||
<div class="error-404-container">
|
||||
|
||||
<div class="error-404-visual">
|
||||
<div class="error-404-code">404</div>
|
||||
<div class="error-404-blocks">
|
||||
<!-- Minecraft-style Blöcke als Dekoration -->
|
||||
<span class="block block-grass"></span>
|
||||
<span class="block block-dirt"></span>
|
||||
<span class="block block-stone"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="error-404-content">
|
||||
<h1 class="error-404-title">
|
||||
<?php _e('Diese Seite ist verloren gegangen...', 'minecraft-modern-theme'); ?>
|
||||
</h1>
|
||||
<p class="error-404-subtitle">
|
||||
<?php _e('Wie eine Map ohne Spawn-Punkt – diese Seite existiert nicht (mehr).', 'minecraft-modern-theme'); ?>
|
||||
</p>
|
||||
|
||||
<div class="error-404-actions">
|
||||
<a href="<?php echo esc_url( home_url('/') ); ?>" class="error-404-btn primary">
|
||||
<i class="fas fa-home"></i> <?php _e('Zur Startseite', 'minecraft-modern-theme'); ?>
|
||||
</a>
|
||||
<a href="javascript:history.back()" class="error-404-btn secondary">
|
||||
<i class="fas fa-arrow-left"></i> <?php _e('Zurück', 'minecraft-modern-theme'); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Suchformular -->
|
||||
<div class="error-404-search">
|
||||
<p><?php _e('Oder suche direkt nach dem was du brauchst:', 'minecraft-modern-theme'); ?></p>
|
||||
<?php get_search_form(); ?>
|
||||
</div>
|
||||
|
||||
<!-- Letzte Beiträge als Hilfestellung -->
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.error-404-container {
|
||||
display: flex;
|
||||
gap: 60px;
|
||||
align-items: center;
|
||||
padding: 60px 0;
|
||||
min-height: 60vh;
|
||||
}
|
||||
|
||||
.error-404-visual {
|
||||
flex-shrink: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.error-404-code {
|
||||
font-size: clamp(80px, 15vw, 160px);
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
color: var(--primary-accent, #00d4ff);
|
||||
text-shadow: 0 0 40px rgba(0, 212, 255, 0.3);
|
||||
letter-spacing: -4px;
|
||||
}
|
||||
|
||||
.error-404-blocks {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.block {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
.block-grass { background: linear-gradient(to bottom, #5c8a1e 40%, #6b4c2a 40%); }
|
||||
.block-dirt { background: #6b4c2a; }
|
||||
.block-stone { background: #888; }
|
||||
|
||||
.error-404-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.error-404-title {
|
||||
font-size: clamp(1.4rem, 3vw, 2rem);
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
|
||||
.error-404-subtitle {
|
||||
color: var(--text-muted, #a0a0a0);
|
||||
margin-bottom: 30px;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.error-404-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.error-404-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 24px;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
.error-404-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||
}
|
||||
.error-404-btn.primary {
|
||||
background: var(--primary-accent, #00d4ff);
|
||||
color: #fff;
|
||||
}
|
||||
.error-404-btn.secondary {
|
||||
background: var(--card-bg);
|
||||
color: inherit;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.error-404-search {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.error-404-search p {
|
||||
color: var(--text-muted, #a0a0a0);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error-404-recent h3 {
|
||||
font-size: 1rem;
|
||||
color: var(--text-muted, #a0a0a0);
|
||||
margin-bottom: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.error-404-recent-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.error-404-recent-list li {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.06);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.error-404-recent-list li i {
|
||||
color: var(--primary-accent, #00d4ff);
|
||||
font-size: 0.75rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.error-404-recent-list a {
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.error-404-recent-list a:hover {
|
||||
color: var(--primary-accent, #00d4ff);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.error-404-container {
|
||||
flex-direction: column;
|
||||
gap: 30px;
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.error-404-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
@@ -1,31 +1,28 @@
|
||||
<?php get_header(); ?> <!-- HIER WIRD DER HEADER EINGEBUNDEN -->
|
||||
<?php get_header(); ?>
|
||||
|
||||
<div class="container site-main">
|
||||
<div class="content-area">
|
||||
|
||||
<!-- Hülle um den gesamten FAQ-Inhalt für einen festen Hintergrund -->
|
||||
<div class="faq-archive-container">
|
||||
|
||||
|
||||
<header class="page-header">
|
||||
<h1 class="page-title"><?php _e( 'Häufig gestellte Fragen (FAQ)', 'minecraft-modern-theme' ); ?></h1>
|
||||
<p><?php _e( 'Wählen Sie eine Kategorie, um die passenden Fragen zu sehen.', 'minecraft-modern-theme' ); ?></p>
|
||||
</header>
|
||||
|
||||
<?php
|
||||
// Alle FAQ-Kategorien abrufen
|
||||
$categories = get_terms( array(
|
||||
'taxonomy' => 'faq_category',
|
||||
'orderby' => 'name',
|
||||
'order' => 'ASC'
|
||||
'order' => 'ASC',
|
||||
) );
|
||||
|
||||
if ( ! empty( $categories ) && ! is_wp_error( $categories ) ) : ?>
|
||||
|
||||
<!-- Tab-Navigation -->
|
||||
<ul class="faq-tabs">
|
||||
<?php
|
||||
<?php
|
||||
$is_first = true;
|
||||
foreach ( $categories as $category ) :
|
||||
foreach ( $categories as $category ) :
|
||||
$active_class = $is_first ? 'active' : '';
|
||||
?>
|
||||
<li>
|
||||
@@ -33,20 +30,19 @@
|
||||
<?php echo esc_html( $category->name ); ?>
|
||||
</button>
|
||||
</li>
|
||||
<?php
|
||||
$is_first = false;
|
||||
<?php
|
||||
$is_first = false;
|
||||
endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<!-- Container für alle Tab-Inhalte -->
|
||||
<div class="faq-tab-content-container">
|
||||
<?php
|
||||
<?php
|
||||
$is_first_pane = true;
|
||||
foreach ( $categories as $category ) :
|
||||
foreach ( $categories as $category ) :
|
||||
$active_pane_class = $is_first_pane ? 'active' : '';
|
||||
?>
|
||||
<div class="faq-tab-pane <?php echo esc_attr($active_pane_class); ?>" data-category="<?php echo esc_attr($category->slug); ?>">
|
||||
|
||||
|
||||
<?php
|
||||
$faqs = new WP_Query( array(
|
||||
'post_type' => 'faq',
|
||||
@@ -58,8 +54,8 @@
|
||||
'terms' => $category->slug,
|
||||
),
|
||||
),
|
||||
'orderby' => 'menu_order',
|
||||
'order' => 'ASC',
|
||||
'orderby' => 'menu_order',
|
||||
'order' => 'ASC',
|
||||
) );
|
||||
|
||||
if ( $faqs->have_posts() ) : ?>
|
||||
@@ -77,8 +73,8 @@
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
$is_first_pane = false;
|
||||
<?php
|
||||
$is_first_pane = false;
|
||||
endforeach; ?>
|
||||
</div>
|
||||
|
||||
@@ -91,4 +87,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php get_footer(); ?> <!-- HIER WIRD DER FOOTER EINGEBUNDEN -->
|
||||
<?php get_footer(); ?>
|
||||
@@ -3,45 +3,107 @@
|
||||
<div class="container site-main">
|
||||
<div class="content-area">
|
||||
<div class="team-archive-container">
|
||||
|
||||
<header class="page-header">
|
||||
<h1 class="page-title">Unser Team</h1>
|
||||
<p class="page-description">Lerne die Leute kennen, die diesen Server am Laufen halten.</p>
|
||||
</header>
|
||||
|
||||
<?php
|
||||
$query = new WP_Query(array('post_type' => 'team_member', 'posts_per_page' => -1, 'orderby' => 'menu_order', 'order' => 'ASC'));
|
||||
$query = new WP_Query( array(
|
||||
'post_type' => 'team_member',
|
||||
'posts_per_page' => -1,
|
||||
'orderby' => 'menu_order',
|
||||
'order' => 'ASC',
|
||||
) );
|
||||
|
||||
if ( $query->have_posts() ) : ?>
|
||||
<div class="team-grid">
|
||||
<?php while ( $query->have_posts() ) : $query->the_post();
|
||||
$rank_string = get_post_meta( get_the_ID(), '_team_member_rank', true );
|
||||
$img = get_the_post_thumbnail_url( get_the_ID(), 'medium' );
|
||||
if ( !$img ) $img = get_template_directory_uri() . '/images/default-avatar.png';
|
||||
$uuid = get_post_meta( get_the_ID(), '_team_member_uuid', true );
|
||||
$banner_id = get_post_meta( get_the_ID(), '_team_member_banner', true );
|
||||
$img = get_the_post_thumbnail_url( get_the_ID(), 'medium' );
|
||||
$banner_url = $banner_id ? wp_get_attachment_image_url( $banner_id, 'medium_large' ) : false;
|
||||
|
||||
// UUID hat Vorrang – Minecraft Avatar via visage.surgeplay.com
|
||||
if ( $uuid ) {
|
||||
$avatar_url = 'https://visage.surgeplay.com/bust/' . esc_attr( $uuid ) . '.png';
|
||||
} elseif ( $img ) {
|
||||
$avatar_url = $img;
|
||||
} else {
|
||||
$avatar_url = false;
|
||||
}
|
||||
$use_placeholder = ! $avatar_url;
|
||||
$initials = mb_strtoupper( mb_substr( get_the_title(), 0, 1 ) );
|
||||
?>
|
||||
<article class="team-card">
|
||||
<div class="team-image-wrapper">
|
||||
<img src="<?php echo esc_url($img); ?>" alt="<?php echo esc_attr(get_the_title()); ?>">
|
||||
<!-- Banner -->
|
||||
<div class="team-card-banner" <?php if ( $banner_url ) echo 'style="background-image:url(' . esc_url($banner_url) . ')"'; ?>>
|
||||
</div>
|
||||
|
||||
<!-- Avatar -->
|
||||
<div class="team-image-wrapper">
|
||||
<?php if ( $avatar_url ) : ?>
|
||||
<img src="<?php echo esc_url( $avatar_url ); ?>"
|
||||
alt="<?php echo esc_attr( get_the_title() ); ?>"
|
||||
loading="lazy">
|
||||
<?php else : ?>
|
||||
<div class="team-avatar-placeholder">
|
||||
<?php echo esc_html( $initials ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="team-info">
|
||||
<h3 class="team-name"><?php the_title(); ?></h3>
|
||||
<div class="team-ranks-wrapper">
|
||||
<?php if ( !empty($rank_string) ) {
|
||||
$ranks = explode(',', $rank_string);
|
||||
<?php if ( ! empty( $rank_string ) ) {
|
||||
$ranks = explode( ',', $rank_string );
|
||||
foreach ( $ranks as $r ) {
|
||||
echo '<span class="team-rank">' . esc_html(trim($r)) . '</span>';
|
||||
echo '<span class="team-rank">' . esc_html( trim( $r ) ) . '</span>';
|
||||
}
|
||||
} ?>
|
||||
</div>
|
||||
<div class="team-bio"><?php the_excerpt(); ?></div>
|
||||
</div>
|
||||
</article>
|
||||
<?php endwhile; ?>
|
||||
<?php endwhile; wp_reset_postdata(); ?>
|
||||
</div>
|
||||
<?php wp_reset_postdata(); ?>
|
||||
|
||||
<?php else : ?>
|
||||
<p>Noch keine Teammitglieder.</p>
|
||||
<p><?php _e('Noch keine Teammitglieder.', 'minecraft-modern-theme'); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Avatar-Placeholder wenn kein Bild gesetzt ist */
|
||||
.team-avatar-placeholder {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
background: var(--card-bg);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--primary-accent, #00d4ff);
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
gap: 4px;
|
||||
}
|
||||
.team-avatar-placeholder svg {
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
color: var(--primary-accent, #00d4ff);
|
||||
}
|
||||
.team-avatar-placeholder span {
|
||||
font-size: 2rem;
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
461
Minecraft-Modern-Theme/archive-video.php
Normal file
461
Minecraft-Modern-Theme/archive-video.php
Normal file
@@ -0,0 +1,461 @@
|
||||
<?php get_header(); ?>
|
||||
|
||||
<style>
|
||||
/* Basis-Styles für Player */
|
||||
#yt-player-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-bottom: 56.25%; /* 16:9 */
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
#yt-player-container iframe,
|
||||
#yt-player-container #yt-player {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
#other-player-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-bottom: 56.25%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
#other-player-container iframe,
|
||||
#other-player-container video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* === NEU: Styles für das Livestream Popup (Lightbox) === */
|
||||
.livestream-lightbox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10000;
|
||||
display: none; /* Wird via JS auf flex gesetzt */
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
.livestream-lightbox.is-open {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
.livestream-lightbox-backdrop {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.livestream-lightbox-box {
|
||||
position: relative;
|
||||
width: 90%;
|
||||
max-width: 1100px;
|
||||
background: #1a1a1a;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||||
transform: translateY(20px);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.livestream-lightbox.is-open .livestream-lightbox-box {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.livestream-lightbox-head {
|
||||
padding: 15px 25px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #222;
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
.livestream-lightbox-title {
|
||||
margin: 0;
|
||||
font-size: 1.2rem;
|
||||
color: #fff;
|
||||
}
|
||||
.livestream-lightbox-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #aaa;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.livestream-lightbox-close:hover {
|
||||
color: #fff;
|
||||
}
|
||||
.livestream-lightbox-player {
|
||||
position: relative;
|
||||
padding-bottom: 56.25%;
|
||||
height: 0;
|
||||
background: #000;
|
||||
}
|
||||
.livestream-lightbox-player iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
.livestream-lightbox-meta {
|
||||
padding: 15px 25px;
|
||||
background: #222;
|
||||
text-align: right;
|
||||
}
|
||||
.livestream-lightbox-meta a {
|
||||
color: #00dcff;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
/* Klick-Indikator für die Karten */
|
||||
.video-livestream-list > div {
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.video-livestream-list > div:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container site-main">
|
||||
<div class="content-area">
|
||||
<div class="video-archive-container">
|
||||
|
||||
<header class="page-header">
|
||||
<h1 class="page-title">
|
||||
<i class="fas fa-play-circle"></i> <?php _e( 'Videos', 'minecraft-modern-theme' ); ?>
|
||||
</h1>
|
||||
<p class="page-description">
|
||||
<?php _e( 'Alle Videos auf einem Blick. Klicke auf ein Video um es direkt hier anzusehen.', 'minecraft-modern-theme' ); ?>
|
||||
</p>
|
||||
|
||||
<?php
|
||||
$categories = array();
|
||||
$all_vids = get_posts( array( 'post_type' => 'mm_video', 'posts_per_page' => -1, 'fields' => 'ids' ) );
|
||||
foreach ( $all_vids as $vid_id ) {
|
||||
$cat = get_post_meta( $vid_id, '_mm_video_category', true );
|
||||
if ( $cat ) $categories[ $cat ] = $cat;
|
||||
}
|
||||
if ( count( $categories ) > 1 ) : ?>
|
||||
<div class="video-filter-bar">
|
||||
<button class="video-filter-btn active" data-filter="all">
|
||||
<?php _e( 'Alle', 'minecraft-modern-theme' ); ?>
|
||||
</button>
|
||||
<?php foreach ( $categories as $cat ) : ?>
|
||||
<button class="video-filter-btn" data-filter="<?php echo esc_attr( $cat ); ?>">
|
||||
<?php echo esc_html( $cat ); ?>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
|
||||
<?php
|
||||
$livestream_groups = mm_video_get_livestream_groups();
|
||||
?>
|
||||
<?php if ( ! empty( $livestream_groups ) ) : ?>
|
||||
<div class="video-livestream-section">
|
||||
<h2 class="section-livestream-title">
|
||||
<span class="live-indicator"></span>
|
||||
<span><?php _e( 'JETZT LIVE', 'minecraft-modern-theme' ); ?></span>
|
||||
</h2>
|
||||
<div class="video-livestream-list">
|
||||
<?php foreach ( $livestream_groups as $group_index => $livestream_group ) : ?>
|
||||
<?php echo mm_video_render_livestream_group( $livestream_group, $group_index ); ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
$query = new WP_Query( array(
|
||||
'post_type' => 'mm_video',
|
||||
'posts_per_page' => -1,
|
||||
'orderby' => 'menu_order date',
|
||||
'order' => 'ASC',
|
||||
) );
|
||||
|
||||
if ( $query->have_posts() ) : ?>
|
||||
|
||||
<div class="video-grid" id="video-grid">
|
||||
<?php while ( $query->have_posts() ) : $query->the_post();
|
||||
$url = get_post_meta( get_the_ID(), '_mm_video_url', true );
|
||||
$category = get_post_meta( get_the_ID(), '_mm_video_category', true );
|
||||
$thumb = get_the_post_thumbnail_url( get_the_ID(), 'medium_large' );
|
||||
$type = $url ? mm_video_get_type( $url ) : 'unknown';
|
||||
|
||||
if ( ! $thumb && $url && $type === 'youtube' ) {
|
||||
if ( preg_match( '/(?:youtube\.com\/(?:watch\?v=|shorts\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/', $url, $m ) ) {
|
||||
$thumb = 'https://img.youtube.com/vi/' . $m[1] . '/maxresdefault.jpg';
|
||||
}
|
||||
}
|
||||
|
||||
$platform_icons = array(
|
||||
'youtube' => array( 'icon' => 'fab fa-youtube', 'color' => '#ff0000' ),
|
||||
'vimeo' => array( 'icon' => 'fab fa-vimeo-v', 'color' => '#1ab7ea' ),
|
||||
'twitch' => array( 'icon' => 'fab fa-twitch', 'color' => '#9146ff' ),
|
||||
'mp4' => array( 'icon' => 'fas fa-film', 'color' => '#aaa' ),
|
||||
);
|
||||
$platform = isset( $platform_icons[$type] ) ? $platform_icons[$type] : array( 'icon' => 'fas fa-play', 'color' => '#aaa' );
|
||||
?>
|
||||
<div class="video-card" data-category="<?php echo esc_attr( $category ); ?>">
|
||||
<div class="video-card-thumb"
|
||||
data-url="<?php echo esc_attr( $url ); ?>"
|
||||
data-type="<?php echo esc_attr( $type ); ?>"
|
||||
data-title="<?php echo esc_attr( get_the_title() ); ?>">
|
||||
<?php if ( $thumb ) : ?>
|
||||
<img src="<?php echo esc_url( $thumb ); ?>" alt="<?php echo esc_attr( get_the_title() ); ?>" loading="lazy">
|
||||
<?php else : ?>
|
||||
<div class="video-card-no-thumb"><i class="fas fa-play-circle"></i></div>
|
||||
<?php endif; ?>
|
||||
<div class="video-card-hover">
|
||||
<i class="fas fa-play"></i>
|
||||
</div>
|
||||
<span class="video-platform-badge" style="color:<?php echo esc_attr($platform['color']); ?>">
|
||||
<i class="<?php echo esc_attr($platform['icon']); ?>"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="video-card-body">
|
||||
<h3 class="video-card-title"><?php the_title(); ?></h3>
|
||||
<?php if ( has_excerpt() ) : ?>
|
||||
<p class="video-card-excerpt"><?php echo wp_trim_words( get_the_excerpt(), 12 ); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ( $category ) : ?>
|
||||
<span class="video-card-tag"><?php echo esc_html( $category ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endwhile; wp_reset_postdata(); ?>
|
||||
</div>
|
||||
|
||||
<div id="video-lightbox" class="video-lightbox" style="display:none;" aria-hidden="true">
|
||||
<div class="video-lightbox-backdrop"></div>
|
||||
<div class="video-lightbox-box">
|
||||
<div class="video-lightbox-head">
|
||||
<h3 class="video-lightbox-title"></h3>
|
||||
<button class="video-lightbox-close" aria-label="<?php esc_attr_e('Schließen','minecraft-modern-theme'); ?>">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="video-lightbox-player">
|
||||
<div id="yt-player-container" style="display:none;">
|
||||
<div id="yt-player"></div>
|
||||
</div>
|
||||
<div id="other-player-container" style="display:none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php else : ?>
|
||||
<div class="video-empty">
|
||||
<i class="fas fa-video-slash"></i>
|
||||
<p><?php _e( 'Noch keine Videos vorhanden.', 'minecraft-modern-theme' ); ?></p>
|
||||
<?php if ( current_user_can('publish_posts') ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url('post-new.php?post_type=mm_video') ); ?>" class="btn-primary">
|
||||
<i class="fas fa-plus"></i> <?php _e('Erstes Video hinzufügen','minecraft-modern-theme'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://www.youtube.com/iframe_api"></script>
|
||||
<script>
|
||||
var ytPlayer = null;
|
||||
var ytPlayerReady = false;
|
||||
var pendingVideoId = null;
|
||||
var livestreamPlayers = new Map();
|
||||
var livestreamPlayerCallbacks = [];
|
||||
|
||||
function onYouTubeIframeAPIReady() {
|
||||
ytPlayer = new YT.Player('yt-player', {
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
playerVars: { autoplay: 1, rel: 0, modestbranding: 1 },
|
||||
events: {
|
||||
onReady: function(e) {
|
||||
ytPlayerReady = true;
|
||||
if (pendingVideoId) {
|
||||
e.target.loadVideoById(pendingVideoId);
|
||||
pendingVideoId = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
livestreamPlayerCallbacks.forEach(function(callback) { callback(); });
|
||||
livestreamPlayerCallbacks = [];
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var lb = document.getElementById('video-lightbox');
|
||||
var lbTitle = lb ? lb.querySelector('.video-lightbox-title') : null;
|
||||
var ytContainer = document.getElementById('yt-player-container');
|
||||
var otContainer = document.getElementById('other-player-container');
|
||||
|
||||
function extractYouTubeId(url) {
|
||||
var m = url.match(/(?:youtube\.com\/(?:watch\?v=|shorts\/|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/);
|
||||
return m ? m[1] : null;
|
||||
}
|
||||
|
||||
function buildOtherEmbed(url, title) {
|
||||
var t = (title||'Video').replace(/"/g,'"');
|
||||
var viM = url.match(/vimeo\.com\/(?:video\/)?(\d+)/);
|
||||
if (viM) return '<iframe src="https://player.vimeo.com/video/'+viM[1]+'?autoplay=1&dnt=1" title="'+t+'" frameborder="0" allowfullscreen allow="autoplay; encrypted-media"></iframe>';
|
||||
var tvM = url.match(/twitch\.tv\/videos\/(\d+)/);
|
||||
if (tvM) return '<iframe src="https://player.twitch.tv/?video=v'+tvM[1]+'&parent='+location.hostname+'&autoplay=true" title="'+t+'" frameborder="0" allowfullscreen></iframe>';
|
||||
var tcM = url.match(/twitch\.tv\/([a-zA-Z0-9_]+)$/);
|
||||
if (tcM) return '<iframe src="https://player.twitch.tv/?channel='+tcM[1]+'&parent='+location.hostname+'&autoplay=true" title="'+t+'" frameborder="0" allowfullscreen></iframe>';
|
||||
if (/\.(mp4|webm|ogv)(\?.*)?$/i.test(url)) return '<video controls autoplay playsinline><source src="'+url+'" type="video/mp4"></video>';
|
||||
return '<p style="color:#aaa;text-align:center;padding:30px;">Ungültige URL</p>';
|
||||
}
|
||||
|
||||
function openLb(url, title, type) {
|
||||
if (!lb) return;
|
||||
if (lbTitle) lbTitle.textContent = title || '';
|
||||
lb.style.display = 'flex';
|
||||
lb.setAttribute('aria-hidden','false');
|
||||
document.body.style.overflow = 'hidden';
|
||||
setTimeout(function(){ lb.classList.add('is-open'); }, 10);
|
||||
|
||||
var ytId = extractYouTubeId(url);
|
||||
if (ytId) {
|
||||
otContainer.style.display = 'none';
|
||||
otContainer.innerHTML = '';
|
||||
ytContainer.style.display = 'block';
|
||||
if (ytPlayerReady && ytPlayer) ytPlayer.loadVideoById(ytId); else pendingVideoId = ytId;
|
||||
} else {
|
||||
ytContainer.style.display = 'none';
|
||||
if (ytPlayerReady && ytPlayer) ytPlayer.stopVideo();
|
||||
otContainer.style.display = 'block';
|
||||
otContainer.innerHTML = buildOtherEmbed(url, title);
|
||||
}
|
||||
}
|
||||
|
||||
function closeLb() {
|
||||
if (!lb) return;
|
||||
lb.classList.remove('is-open');
|
||||
setTimeout(function(){
|
||||
lb.style.display = 'none';
|
||||
lb.setAttribute('aria-hidden','true');
|
||||
document.body.style.overflow = '';
|
||||
if (ytPlayerReady && ytPlayer) ytPlayer.stopVideo();
|
||||
ytContainer.style.display = 'none';
|
||||
otContainer.innerHTML = '';
|
||||
otContainer.style.display = 'none';
|
||||
}, 300);
|
||||
}
|
||||
|
||||
document.querySelectorAll('.video-card-thumb').forEach(function(el) {
|
||||
el.addEventListener('click', function() { openLb(this.dataset.url, this.dataset.title, this.dataset.type); });
|
||||
});
|
||||
|
||||
if (lb) {
|
||||
lb.querySelector('.video-lightbox-close').addEventListener('click', closeLb);
|
||||
lb.querySelector('.video-lightbox-backdrop').addEventListener('click', closeLb);
|
||||
}
|
||||
document.addEventListener('keydown', function(e){ if (e.key==='Escape') closeLb(); });
|
||||
|
||||
// Filter
|
||||
document.querySelectorAll('.video-filter-btn').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
document.querySelectorAll('.video-filter-btn').forEach(function(b){ b.classList.remove('active'); });
|
||||
this.classList.add('active');
|
||||
var f = this.dataset.filter;
|
||||
document.querySelectorAll('.video-card').forEach(function(c) {
|
||||
c.style.display = (f === 'all' || c.dataset.category === f) ? '' : 'none';
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// === Livestream Lightbox System ===
|
||||
var livestreamLightbox = document.createElement('div');
|
||||
livestreamLightbox.id = 'livestream-lightbox';
|
||||
livestreamLightbox.className = 'livestream-lightbox';
|
||||
livestreamLightbox.setAttribute('aria-hidden', 'true');
|
||||
livestreamLightbox.innerHTML = `
|
||||
<div class="livestream-lightbox-backdrop"></div>
|
||||
<div class="livestream-lightbox-box">
|
||||
<div class="livestream-lightbox-head">
|
||||
<h3 class="livestream-lightbox-title"></h3>
|
||||
<button class="livestream-lightbox-close" aria-label="Schließen"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
<div class="livestream-lightbox-player"></div>
|
||||
<div class="livestream-lightbox-meta"></div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(livestreamLightbox);
|
||||
|
||||
var lsLightbox = document.getElementById('livestream-lightbox');
|
||||
var lsTitle = lsLightbox.querySelector('.livestream-lightbox-title');
|
||||
var lsPlayer = lsLightbox.querySelector('.livestream-lightbox-player');
|
||||
var lsMeta = lsLightbox.querySelector('.livestream-lightbox-meta');
|
||||
|
||||
function openLivestreamLightbox(embedUrl, title, profileUrl, platform) {
|
||||
lsTitle.textContent = title || 'Livestream';
|
||||
// Wir nutzen ein sauberes Iframe für das Popup
|
||||
lsPlayer.innerHTML = '<iframe src="' + embedUrl + '" allow="autoplay; encrypted-media" allowfullscreen></iframe>';
|
||||
|
||||
var icon = platform === 'youtube' ? 'fab fa-youtube' : (platform === 'twitch' ? 'fab fa-twitch' : 'fas fa-play');
|
||||
lsMeta.innerHTML = profileUrl ? '<a href="' + profileUrl + '" target="_blank" rel="noopener"><i class="' + icon + '"></i> Zum Kanal</a>' : '';
|
||||
|
||||
lsLightbox.style.display = 'flex';
|
||||
lsLightbox.setAttribute('aria-hidden', 'false');
|
||||
document.body.style.overflow = 'hidden';
|
||||
setTimeout(function() { lsLightbox.classList.add('is-open'); }, 10);
|
||||
}
|
||||
|
||||
function closeLivestreamLightbox() {
|
||||
lsLightbox.classList.remove('is-open');
|
||||
setTimeout(function() {
|
||||
lsLightbox.style.display = 'none';
|
||||
lsLightbox.setAttribute('aria-hidden', 'true');
|
||||
document.body.style.overflow = '';
|
||||
lsPlayer.innerHTML = '';
|
||||
}, 300);
|
||||
}
|
||||
|
||||
lsLightbox.querySelector('.livestream-lightbox-close').addEventListener('click', closeLivestreamLightbox);
|
||||
lsLightbox.querySelector('.livestream-lightbox-backdrop').addEventListener('click', closeLivestreamLightbox);
|
||||
|
||||
// Klick-Event für die "Jetzt Live" Karten
|
||||
document.querySelectorAll('.video-livestream-list > div').forEach(function(card) {
|
||||
card.addEventListener('click', function(e) {
|
||||
// Falls auf den echten Button im Card geklickt wird, Standardverhalten lassen
|
||||
if (e.target.closest('.btn-primary')) return;
|
||||
|
||||
e.preventDefault();
|
||||
var iframe = card.querySelector('iframe');
|
||||
var embedUrl = iframe ? iframe.src : '';
|
||||
var title = card.querySelector('h3') ? card.querySelector('h3').textContent : 'Livestream';
|
||||
var link = card.querySelector('.btn-primary') ? card.querySelector('.btn-primary').href : '';
|
||||
|
||||
var platform = embedUrl.includes('twitch') ? 'twitch' : 'youtube';
|
||||
|
||||
if (embedUrl && !embedUrl.includes('about:blank')) {
|
||||
openLivestreamLightbox(embedUrl, title, link, platform);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
120
Minecraft-Modern-Theme/archive.php
Normal file
120
Minecraft-Modern-Theme/archive.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php get_header(); ?>
|
||||
|
||||
<main id="primary" class="site-main">
|
||||
<div class="container">
|
||||
<div class="content-area">
|
||||
|
||||
<header class="archive-header">
|
||||
<?php
|
||||
if ( is_category() ) {
|
||||
echo '<div class="archive-type-badge"><i class="fas fa-folder-open"></i> ' . __('Kategorie', 'minecraft-modern-theme') . '</div>';
|
||||
the_archive_title( '<h1 class="archive-title">', '</h1>' );
|
||||
the_archive_description( '<div class="archive-description">', '</div>' );
|
||||
} elseif ( is_tag() ) {
|
||||
echo '<div class="archive-type-badge"><i class="fas fa-hashtag"></i> ' . __('Tag', 'minecraft-modern-theme') . '</div>';
|
||||
the_archive_title( '<h1 class="archive-title">', '</h1>' );
|
||||
the_archive_description( '<div class="archive-description">', '</div>' );
|
||||
} elseif ( is_author() ) {
|
||||
$author = get_queried_object();
|
||||
echo '<div class="archive-type-badge"><i class="fas fa-user"></i> ' . __('Autor', 'minecraft-modern-theme') . '</div>';
|
||||
?>
|
||||
<div class="archive-author-header">
|
||||
<?php echo get_avatar( $author->ID, 80, '', '', array('class' => 'archive-author-avatar') ); ?>
|
||||
<div>
|
||||
<h1 class="archive-title"><?php echo esc_html( $author->display_name ); ?></h1>
|
||||
<?php if ( $author->description ) : ?>
|
||||
<p class="archive-description"><?php echo esc_html( $author->description ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
} elseif ( is_date() ) {
|
||||
echo '<div class="archive-type-badge"><i class="fas fa-calendar"></i> ' . __('Archiv', 'minecraft-modern-theme') . '</div>';
|
||||
the_archive_title( '<h1 class="archive-title">', '</h1>' );
|
||||
} else {
|
||||
the_archive_title( '<h1 class="archive-title">', '</h1>' );
|
||||
the_archive_description( '<div class="archive-description">', '</div>' );
|
||||
}
|
||||
?>
|
||||
</header>
|
||||
|
||||
<?php if ( have_posts() ) : ?>
|
||||
|
||||
<div class="archive-posts-grid">
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class('post archive-post-card'); ?>>
|
||||
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<div class="archive-card-thumb">
|
||||
<a href="<?php the_permalink(); ?>">
|
||||
<?php the_post_thumbnail('medium_large', array('loading' => 'lazy')); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="archive-card-body">
|
||||
|
||||
<?php $cats = get_the_category(); if ( $cats ) : ?>
|
||||
<div class="archive-card-cats">
|
||||
<a href="<?php echo esc_url( get_category_link( $cats[0]->term_id ) ); ?>" class="post-category-badge">
|
||||
<?php echo esc_html( $cats[0]->name ); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2 class="archive-card-title">
|
||||
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||||
</h2>
|
||||
|
||||
<div class="archive-card-meta">
|
||||
<span><i class="fas fa-calendar-alt"></i> <?php echo esc_html( get_the_date() ); ?></span>
|
||||
<span><i class="fas fa-user"></i> <?php the_author(); ?></span>
|
||||
<?php
|
||||
$wc = str_word_count( strip_tags( get_post_field('post_content', get_the_ID()) ) );
|
||||
$rt = max(1, ceil($wc / 200));
|
||||
?>
|
||||
<span><i class="fas fa-clock"></i> <?php printf( _n('%d Min.', '%d Min.', $rt, 'minecraft-modern-theme'), $rt ); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="archive-card-excerpt">
|
||||
<?php the_excerpt(); ?>
|
||||
</div>
|
||||
|
||||
<a href="<?php the_permalink(); ?>" class="archive-card-read-more">
|
||||
<?php _e('Weiterlesen', 'minecraft-modern-theme'); ?> <i class="fas fa-arrow-right"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="archive-pagination">
|
||||
<?php
|
||||
the_posts_pagination( array(
|
||||
'mid_size' => 2,
|
||||
'prev_text' => '<i class="fas fa-chevron-left"></i> ' . __('Zurück', 'minecraft-modern-theme'),
|
||||
'next_text' => __('Weiter', 'minecraft-modern-theme') . ' <i class="fas fa-chevron-right"></i>',
|
||||
'before_page_number' => '<span class="page-num">',
|
||||
'after_page_number' => '</span>',
|
||||
) );
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<div class="no-posts-found">
|
||||
<i class="fas fa-search fa-2x"></i>
|
||||
<p><?php _e('Keine Beiträge gefunden.', 'minecraft-modern-theme'); ?></p>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
9
Minecraft-Modern-Theme/clear-cache.php
Normal file
9
Minecraft-Modern-Theme/clear-cache.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
global $wpdb;
|
||||
$deleted1 = $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_mm_yt_live%'");
|
||||
$deleted2 = $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_mm_yt_live%'");
|
||||
|
||||
echo "Cache cleared: Deleted $deleted1 transients and $deleted2 timeouts\n";
|
||||
93
Minecraft-Modern-Theme/clear-livestream-cache.php
Normal file
93
Minecraft-Modern-Theme/clear-livestream-cache.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* Löscht alle Livestream-Caches
|
||||
*/
|
||||
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
echo "=== Cache löschen ===\n\n";
|
||||
|
||||
// Zähler
|
||||
$deleted = 0;
|
||||
global $wpdb;
|
||||
|
||||
// 1. Alle alten Channel-ID Caches löschen (mm_channel_id_* - alt)
|
||||
$results = $wpdb->get_results(
|
||||
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_mm_channel_id_%'"
|
||||
);
|
||||
|
||||
foreach ($results as $row) {
|
||||
$key = str_replace('_transient_', '', $row->option_name);
|
||||
delete_transient($key);
|
||||
$deleted++;
|
||||
}
|
||||
echo "✓ Gelöscht: $deleted Channel-ID Caches (alt)\n";
|
||||
|
||||
// 2. Alle Live-Status Caches löschen (mm_live_status_*)
|
||||
$deleted = 0;
|
||||
$results = $wpdb->get_results(
|
||||
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_mm_live_status_%'"
|
||||
);
|
||||
|
||||
foreach ($results as $row) {
|
||||
$key = str_replace('_transient_', '', $row->option_name);
|
||||
delete_transient($key);
|
||||
$deleted++;
|
||||
}
|
||||
echo "✓ Gelöscht: $deleted Live-Status Caches\n";
|
||||
|
||||
// 3. Alte Live-ID Caches löschen (mm_live_id_* - alt)
|
||||
$deleted = 0;
|
||||
$results = $wpdb->get_results(
|
||||
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_mm_live_id_%'"
|
||||
);
|
||||
|
||||
foreach ($results as $row) {
|
||||
$key = str_replace('_transient_', '', $row->option_name);
|
||||
delete_transient($key);
|
||||
$deleted++;
|
||||
}
|
||||
echo "✓ Gelöscht: $deleted Live-ID Caches (alt)\n";
|
||||
|
||||
// 4. Alte Channel-ID Caches löschen (mm_id_for_* - neu)
|
||||
$deleted = 0;
|
||||
$results = $wpdb->get_results(
|
||||
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_mm_id_for_%'"
|
||||
);
|
||||
|
||||
foreach ($results as $row) {
|
||||
$key = str_replace('_transient_', '', $row->option_name);
|
||||
delete_transient($key);
|
||||
$deleted++;
|
||||
}
|
||||
echo "✓ Gelöscht: $deleted Channel-ID Caches (neu)\n";
|
||||
|
||||
// 3. Alte Video-Resolution Caches löschen (mm_yt_live_v2_*)
|
||||
$deleted = 0;
|
||||
$results = $wpdb->get_results(
|
||||
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_mm_yt_live_v2_%'"
|
||||
);
|
||||
|
||||
foreach ($results as $row) {
|
||||
$key = str_replace('_transient_', '', $row->option_name);
|
||||
delete_transient($key);
|
||||
$deleted++;
|
||||
}
|
||||
echo "✓ Gelöscht: $deleted YouTube Video Caches\n";
|
||||
|
||||
// 4. Alte Live-Status Caches löschen (mm_yt_status_*)
|
||||
$deleted = 0;
|
||||
$results = $wpdb->get_results(
|
||||
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_mm_yt_status_%'"
|
||||
);
|
||||
|
||||
foreach ($results as $row) {
|
||||
$key = str_replace('_transient_', '', $row->option_name);
|
||||
delete_transient($key);
|
||||
$deleted++;
|
||||
}
|
||||
echo "✓ Gelöscht: $deleted YouTube Status Caches\n";
|
||||
|
||||
echo "\n✓ Alle Caches wurden gelöscht!\n";
|
||||
echo "Die Seite kann jetzt neu geladen werden.\n";
|
||||
158
Minecraft-Modern-Theme/comments.php
Normal file
158
Minecraft-Modern-Theme/comments.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
// Kein direkter Zugriff
|
||||
if ( ! defined('ABSPATH') ) exit;
|
||||
|
||||
// Wenn Passwort erforderlich, nichts anzeigen
|
||||
if ( post_password_required() ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
|
||||
<div id="comments" class="comments-area">
|
||||
|
||||
<?php if ( have_comments() ) : ?>
|
||||
|
||||
<h3 class="comments-title">
|
||||
<i class="fas fa-comments"></i>
|
||||
<?php
|
||||
$comment_count = get_comments_number();
|
||||
printf(
|
||||
_n(
|
||||
'%d Kommentar zu “%s”',
|
||||
'%d Kommentare zu “%s”',
|
||||
$comment_count,
|
||||
'minecraft-modern-theme'
|
||||
),
|
||||
$comment_count,
|
||||
'<span>' . get_the_title() . '</span>'
|
||||
);
|
||||
?>
|
||||
</h3>
|
||||
|
||||
<!-- Ältere Kommentare / Pagination oben -->
|
||||
<?php if ( get_comment_pages_count() > 1 && get_option('page_comments') ) : ?>
|
||||
<nav class="comment-navigation" aria-label="<?php esc_attr_e('Kommentar-Navigation', 'minecraft-modern-theme'); ?>">
|
||||
<div class="comment-nav-prev"><?php previous_comments_link( '<i class="fas fa-chevron-left"></i> ' . __('Ältere Kommentare', 'minecraft-modern-theme') ); ?></div>
|
||||
<div class="comment-nav-next"><?php next_comments_link( __('Neuere Kommentare', 'minecraft-modern-theme') . ' <i class="fas fa-chevron-right"></i>' ); ?></div>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
|
||||
<ol class="comment-list">
|
||||
<?php
|
||||
wp_list_comments( array(
|
||||
'style' => 'ol',
|
||||
'short_ping' => true,
|
||||
'avatar_size' => 48,
|
||||
'callback' => 'minecraft_modern_comment_template',
|
||||
) );
|
||||
?>
|
||||
</ol>
|
||||
|
||||
<!-- Neuere Kommentare / Pagination unten -->
|
||||
<?php if ( get_comment_pages_count() > 1 && get_option('page_comments') ) : ?>
|
||||
<nav class="comment-navigation" aria-label="<?php esc_attr_e('Kommentar-Navigation', 'minecraft-modern-theme'); ?>">
|
||||
<div class="comment-nav-prev"><?php previous_comments_link( '<i class="fas fa-chevron-left"></i> ' . __('Ältere Kommentare', 'minecraft-modern-theme') ); ?></div>
|
||||
<div class="comment-nav-next"><?php next_comments_link( __('Neuere Kommentare', 'minecraft-modern-theme') . ' <i class="fas fa-chevron-right"></i>' ); ?></div>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php endif; // have_comments() ?>
|
||||
|
||||
<?php
|
||||
// Kommentarformular
|
||||
if ( comments_open() ) :
|
||||
comment_form( array(
|
||||
'title_reply' => '<span><i class="fas fa-pencil-alt"></i> ' . __('Hinterlasse einen Kommentar', 'minecraft-modern-theme') . '</span>',
|
||||
'title_reply_to' => __('Antworten auf %s', 'minecraft-modern-theme'),
|
||||
'cancel_reply_link' => __('Abbrechen', 'minecraft-modern-theme'),
|
||||
'label_submit' => __('Kommentar absenden', 'minecraft-modern-theme'),
|
||||
'comment_notes_before' => '',
|
||||
'comment_notes_after' => '',
|
||||
'class_form' => 'comment-form',
|
||||
'class_submit' => 'submit btn-comment-submit',
|
||||
) );
|
||||
elseif ( ! is_user_logged_in() ) :
|
||||
?>
|
||||
<div class="comments-closed-notice">
|
||||
<i class="fas fa-lock"></i>
|
||||
<?php _e('Kommentare sind für diesen Beitrag deaktiviert.', 'minecraft-modern-theme'); ?>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
|
||||
</div><!-- #comments -->
|
||||
|
||||
<?php
|
||||
/**
|
||||
* Callback für den Kommentar-Template.
|
||||
* Wird in functions.php nicht definiert, daher hier.
|
||||
*/
|
||||
if ( ! function_exists('minecraft_modern_comment_template') ) :
|
||||
function minecraft_modern_comment_template( $comment, $args, $depth ) {
|
||||
$tag = ( 'div' === $args['style'] ) ? 'div' : 'li';
|
||||
?>
|
||||
<<?php echo $tag; ?> id="comment-<?php comment_ID(); ?>" <?php comment_class( empty($args['has_children']) ? '' : 'parent', $comment ); ?>>
|
||||
<article id="div-comment-<?php comment_ID(); ?>" class="comment-body">
|
||||
|
||||
<div class="comment-meta">
|
||||
<div class="comment-author-avatar">
|
||||
<?php echo get_avatar( $comment, $args['avatar_size'], '', '', array('class' => 'comment-avatar') ); ?>
|
||||
</div>
|
||||
<div class="comment-author-info">
|
||||
<span class="comment-author-name">
|
||||
<?php
|
||||
$author_url = get_comment_author_url($comment);
|
||||
if ( $author_url ) {
|
||||
echo '<a href="' . esc_url($author_url) . '" rel="external nofollow">' . get_comment_author($comment) . '</a>';
|
||||
} else {
|
||||
echo esc_html( get_comment_author($comment) );
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
<span class="comment-date">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
<a href="<?php echo esc_url( get_comment_link($comment, $args) ); ?>">
|
||||
<time datetime="<?php comment_date('c'); ?>">
|
||||
<?php
|
||||
printf(
|
||||
__('%1$s um %2$s Uhr', 'minecraft-modern-theme'),
|
||||
get_comment_date('', $comment),
|
||||
get_comment_time('', false, false, $comment)
|
||||
);
|
||||
?>
|
||||
</time>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<?php if ( '0' === $comment->comment_approved ) : ?>
|
||||
<div class="comment-awaiting-moderation">
|
||||
<i class="fas fa-clock"></i> <?php _e('Dein Kommentar wartet auf Freigabe.', 'minecraft-modern-theme'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="comment-content">
|
||||
<?php comment_text(); ?>
|
||||
</div>
|
||||
|
||||
<footer class="comment-footer">
|
||||
<?php
|
||||
comment_reply_link( array_merge( $args, array(
|
||||
'add_below' => 'div-comment',
|
||||
'depth' => $depth,
|
||||
'max_depth' => $args['max_depth'],
|
||||
'before' => '<div class="reply">',
|
||||
'after' => '</div>',
|
||||
) ) );
|
||||
|
||||
edit_comment_link( '<i class="fas fa-pencil-alt"></i> ' . __('Bearbeiten', 'minecraft-modern-theme'), '<div class="edit-link">', '</div>' );
|
||||
?>
|
||||
</footer>
|
||||
|
||||
</article>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
?>
|
||||
74
Minecraft-Modern-Theme/css/assistant-widget.css
Normal file
74
Minecraft-Modern-Theme/css/assistant-widget.css
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
#mm-assistant-chat {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 110px;
|
||||
right: 0;
|
||||
width: 320px;
|
||||
background: #1a1d22; /* Dunklerer Hintergrund */
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 15px 45px rgba(0,0,0,0.5);
|
||||
border: 1px solid #333;
|
||||
overflow: hidden;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
background: #0099ff;
|
||||
padding: 12px 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
background-color: #00ff00;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
box-shadow: 0 0 5px #00ff00;
|
||||
}
|
||||
|
||||
#mm-assistant-content {
|
||||
padding: 20px;
|
||||
max-height: 350px;
|
||||
overflow-y: auto;
|
||||
color: #e0e0e0;
|
||||
line-height: 1.6;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.chat-input-area {
|
||||
background: #111;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
border-top: 1px solid #333;
|
||||
}
|
||||
|
||||
#mm-assistant-input {
|
||||
flex: 1;
|
||||
background: #222;
|
||||
border: 1px solid #444;
|
||||
color: white;
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#mm-assistant-send {
|
||||
background: #0099ff;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 5px 12px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
#mm-assistant-send:hover { background: #0077cc; }
|
||||
139
Minecraft-Modern-Theme/css/virtual-assistant.css
Normal file
139
Minecraft-Modern-Theme/css/virtual-assistant.css
Normal file
@@ -0,0 +1,139 @@
|
||||
/* Modernes Design für Virtuellen Assistenten (unten rechts) */
|
||||
/* Positionierung wird jetzt dynamisch über die Klasse mm-bot-pos-* am #mm-bot-root gesetzt */
|
||||
#mm-assistant-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.18);
|
||||
border-radius: 16px;
|
||||
padding: 0;
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
#mm-assistant-btn:hover {
|
||||
box-shadow: 0 4px 16px rgba(0,153,255,0.25);
|
||||
}
|
||||
#mm-assistant-btn img {
|
||||
display: block;
|
||||
background: #181c22;
|
||||
border-radius: 16px;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
}
|
||||
#mm-assistant-chat {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 110px;
|
||||
right: 0;
|
||||
width: 340px;
|
||||
max-width: 95vw;
|
||||
background: #23272e;
|
||||
color: #fff;
|
||||
border-radius: 18px;
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.35);
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
animation: mmFadeIn 0.25s;
|
||||
}
|
||||
@keyframes mmFadeIn {
|
||||
from { opacity: 0; transform: translateY(30px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
#mm-assistant-chat > div:first-child {
|
||||
background: #0099ff;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
padding: 14px 18px 10px 18px;
|
||||
border-bottom: 1px solid #1a1d22;
|
||||
border-radius: 18px 18px 0 0;
|
||||
}
|
||||
#mm-assistant-content {
|
||||
min-height: 40px;
|
||||
font-size: 1rem;
|
||||
padding: 18px 18px 8px 18px;
|
||||
background: #23272e;
|
||||
}
|
||||
#mm-assistant-input {
|
||||
width: 100%;
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-size: 1rem;
|
||||
background: #1a1d22;
|
||||
color: #fff;
|
||||
margin-bottom: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#mm-assistant-input::placeholder {
|
||||
color: #aaa;
|
||||
}
|
||||
#mm-assistant-send {
|
||||
width: 100%;
|
||||
background: #0099ff;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 10px 0;
|
||||
font-size: 1.1rem;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
#mm-assistant-send:hover {
|
||||
background: #007acc;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
#mm-assistant-chat {
|
||||
width: 98vw;
|
||||
min-width: 0;
|
||||
border-radius: 12px;
|
||||
right: -8px;
|
||||
}
|
||||
#mm-virtual-assistant {
|
||||
right: 8px;
|
||||
bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* BUG-FIX: Doppelter #mm-assistant-chat Block und veraltete Chat-Stile entfernt.
|
||||
Die Regeln .chat-header, .status-dot, .chat-input-area sind Relikte des alten
|
||||
Widget-Designs und werden vom aktuellen mm-bot-* Markup nicht mehr verwendet.
|
||||
Sie wurden entfernt um Konflikte mit den modernen Stilen oben zu vermeiden. */
|
||||
#mm-bot-root { position:fixed; bottom:30px; right:30px; z-index:999999; font-family:-apple-system,system-ui,sans-serif; }
|
||||
#mm-bot-launcher { background:#0099ff; border:none; border-radius:50%; width:60px; height:60px; cursor:pointer; box-shadow:0 4px 12px rgba(0,0,0,.25); transition:.3s ease; display:flex; align-items:center; justify-content:center; overflow:hidden; }
|
||||
#mm-bot-launcher:hover { transform:scale(1.08); background:#0088ee; }
|
||||
#mm-bot-launcher img { width:42px; height:42px; border-radius:4px; }
|
||||
|
||||
#mm-bot-chat { position:absolute; bottom:80px; right:0; width:340px; background:#1e2124; border-radius:15px; box-shadow:0 12px 40px rgba(0,0,0,.45); display:flex; flex-direction:column; overflow:hidden; border:1px solid #333; }
|
||||
.mm-bot-header { background:#2f3136; color:#fff; padding:14px 18px; display:flex; align-items:center; gap:12px; font-weight:700; border-bottom:1px solid #111; }
|
||||
.mm-bot-status { width:10px; height:10px; background:#43b581; border-radius:50%; box-shadow:0 0 8px #43b581; flex-shrink:0; }
|
||||
|
||||
#mm-bot-content { height:320px; padding:16px; overflow-y:auto; background:#36393f; display:flex; flex-direction:column; gap:10px; scroll-behavior:smooth; }
|
||||
.mm-msg { padding:10px 14px; border-radius:12px; font-size:14px; line-height:1.5; max-width:88%; word-break:break-word; }
|
||||
.mm-msg.bot { background:#40444b; color:#dcddde; align-self:flex-start; border-bottom-left-radius:3px; }
|
||||
.mm-msg.user { background:#0099ff; color:#fff; align-self:flex-end; border-bottom-right-radius:3px; }
|
||||
.mm-msg a { color:#00b0f4; text-decoration:none; font-weight:600; }
|
||||
.mm-msg a:hover { text-decoration:underline; }
|
||||
.mm-loading { opacity:.6; font-size:20px; letter-spacing:4px; }
|
||||
|
||||
.mm-bot-quick { display:flex; flex-wrap:wrap; gap:6px; margin-top:4px; }
|
||||
.mm-quick-btn { background:#2f3136; color:#dcddde; border:1px solid #444; border-radius:20px; padding:5px 12px; font-size:12px; cursor:pointer; transition:.2s; white-space:nowrap; }
|
||||
.mm-quick-btn:hover { background:#0099ff; color:#fff; border-color:#0099ff; }
|
||||
|
||||
.mm-bot-input-area { padding:12px 14px; background:#2f3136; display:flex; gap:8px; border-top:1px solid #222; }
|
||||
#mm-bot-field { flex:1; background:#40444b; border:1px solid #222; border-radius:8px; color:#fff; padding:9px 12px; outline:none; font-size:14px; }
|
||||
#mm-bot-field:focus { border-color:#0099ff; }
|
||||
/* BUG-FIX: ID war '#id-mm-bot-send', korrektes HTML-Element hat id="mm-bot-send" */
|
||||
#mm-bot-send { background:#0099ff; border:none; color:#fff; border-radius:8px; padding:0 16px; cursor:pointer; font-size:16px; }
|
||||
#mm-bot-send:hover { background:#00b0f4; }
|
||||
#mm-bot-close { margin-left:auto; background:none; border:none; color:#888; font-size:24px; cursor:pointer; line-height:1; padding:0; }
|
||||
#mm-bot-close:hover { color:#fff; }
|
||||
|
||||
#mm-bot-chat code { background:#222; padding:2px 6px; border-radius:4px; color:#ffa500; font-family:monospace; font-size:13px; }
|
||||
|
||||
@media (max-width:400px) {
|
||||
#mm-bot-chat { width:calc(100vw - 20px); right:-10px; }
|
||||
}
|
||||
@@ -15,13 +15,19 @@
|
||||
|
||||
<!-- 2. UNTERER BEREICH: Menü, Copyright, Legal -->
|
||||
<div class="footer-bottom-bar">
|
||||
|
||||
|
||||
<div class="footer-left-group">
|
||||
<!-- Copyright -->
|
||||
<div class="site-info">
|
||||
<?php
|
||||
$copyright_text = get_theme_mod( 'footer_copyright', '© ' . date('Y') . ' ' . get_bloginfo('name') );
|
||||
|
||||
// BUG-FIX: get_theme_mod() mit leerem Default ('') aus dem Customizer
|
||||
// lieferte einen leeren String statt des Auto-Texts, wenn der User
|
||||
// das Feld explizit gespeichert hatte. Jetzt wird auf empty() geprüft.
|
||||
$copyright_text = get_theme_mod( 'footer_copyright', '' );
|
||||
if ( empty( $copyright_text ) ) {
|
||||
$copyright_text = '© ' . date('Y') . ' ' . get_bloginfo('name');
|
||||
}
|
||||
|
||||
if ( get_theme_mod('show_footer_credit', true) ) {
|
||||
$full_footer_text = $copyright_text . ' <span class="footer-separator">|</span> <span class="footer-credit">
|
||||
<a href="https://m-viper.de" target="_blank" rel="noopener noreferrer">
|
||||
@@ -35,18 +41,16 @@
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Footer Menü ( falls vorhanden ) -->
|
||||
<!-- Footer Menü (falls vorhanden) -->
|
||||
<?php if ( has_nav_menu( 'footer' ) ) : ?>
|
||||
<nav class="footer-navigation">
|
||||
<?php
|
||||
wp_nav_menu(
|
||||
array(
|
||||
'theme_location' => 'footer',
|
||||
'menu_class' => 'footer-menu',
|
||||
'container' => false,
|
||||
'depth' => 1, // Nur eine Ebene
|
||||
)
|
||||
);
|
||||
wp_nav_menu( array(
|
||||
'theme_location' => 'footer',
|
||||
'menu_class' => 'footer-menu',
|
||||
'container' => false,
|
||||
'depth' => 1,
|
||||
) );
|
||||
?>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
@@ -56,29 +60,30 @@
|
||||
<!-- Impressum & Datenschutz -->
|
||||
<div class="footer-legal-links">
|
||||
<?php
|
||||
$impressum_url = get_theme_mod('footer_impressum_url');
|
||||
$impressum_url = get_theme_mod('footer_impressum_url');
|
||||
$datenschutz_url = get_theme_mod('footer_datenschutz_url');
|
||||
$links = array();
|
||||
$links = array();
|
||||
|
||||
if (!empty($impressum_url)) {
|
||||
if ( ! empty($impressum_url) ) {
|
||||
$links[] = '<a href="' . esc_url($impressum_url) . '"><i class="fas fa-info-circle"></i> Impressum</a>';
|
||||
}
|
||||
|
||||
if (!empty($datenschutz_url)) {
|
||||
if ( ! empty($datenschutz_url) ) {
|
||||
$links[] = '<a href="' . esc_url($datenschutz_url) . '"><i class="fas fa-shield-alt"></i> Datenschutz</a>';
|
||||
}
|
||||
|
||||
if (!empty($links)) {
|
||||
echo implode('', $links); // Kein Trennzeichen mehr, da wir Icons haben
|
||||
if ( ! empty($links) ) {
|
||||
echo implode('', $links);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!-- Ende footer-bottom-bar -->
|
||||
</div> <!-- Ende Container -->
|
||||
|
||||
<!-- THEME TOGGLE (Fixiert unten rechts) -->
|
||||
</div><!-- Ende footer-bottom-bar -->
|
||||
</div><!-- Ende Container -->
|
||||
|
||||
<a href="#" id="scroll-to-top" aria-label="Zurück nach oben" title="Nach oben scrollen">
|
||||
<i class="fas fa-chevron-up"></i>
|
||||
</a>
|
||||
|
||||
<button class="theme-toggle" aria-label="Dark/Light Mode umschalten" title="Dark / Light Mode">
|
||||
<div class="theme-toggle-icons">
|
||||
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
|
||||
@@ -20,7 +20,6 @@ if ( get_theme_mod('slider_enabled', false) ) :
|
||||
<?php if ( $title ) : ?>
|
||||
<h2 class="slider-title"><?php echo esc_html( $title ); ?></h2>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $subtitle ) : ?>
|
||||
<p class="slider-subtitle"><?php echo esc_html( $subtitle ); ?></p>
|
||||
<?php endif; ?>
|
||||
@@ -41,10 +40,6 @@ if ( get_theme_mod('slider_enabled', false) ) :
|
||||
<div class="swiper-button-next"></div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<!-- ================================================= -->
|
||||
<!-- ANNOUNCEMENT ANKER (unter Slider, ohne Scroll-Bug) -->
|
||||
<!-- ================================================= -->
|
||||
<div id="mm-announcement-anchor"></div>
|
||||
|
||||
<?php else : ?>
|
||||
@@ -60,29 +55,16 @@ if ( get_theme_mod('slider_enabled', false) ) :
|
||||
?>
|
||||
|
||||
<section class="hero-section"
|
||||
style="<?php
|
||||
echo $hero_bg
|
||||
? "background-image: linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)), url('" . esc_url( $hero_bg ) . "')"
|
||||
: '';
|
||||
?>">
|
||||
style="<?php echo $hero_bg ? "background-image: linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)), url('" . esc_url( $hero_bg ) . "')" : ''; ?>">
|
||||
<div class="container">
|
||||
<h1 class="hero-title"><?php echo esc_html( $hero_title ); ?></h1>
|
||||
<p class="hero-subtitle"><?php echo esc_html( $hero_subtitle ); ?></p>
|
||||
|
||||
<div class="hero-buttons">
|
||||
<a href="<?php echo esc_url( $btn1_url ); ?>" class="hero-button-1">
|
||||
<?php echo esc_html( $btn1_text ); ?>
|
||||
</a>
|
||||
<a href="<?php echo esc_url( $btn2_url ); ?>" class="hero-button-2">
|
||||
<?php echo esc_html( $btn2_text ); ?>
|
||||
</a>
|
||||
<a href="<?php echo esc_url( $btn1_url ); ?>" class="hero-button-1"><?php echo esc_html( $btn1_text ); ?></a>
|
||||
<a href="<?php echo esc_url( $btn2_url ); ?>" class="hero-button-2"><?php echo esc_html( $btn2_text ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ================================================= -->
|
||||
<!-- ANNOUNCEMENT ANKER (unter Hero, ohne Scroll-Bug) -->
|
||||
<!-- ================================================= -->
|
||||
<div id="mm-announcement-anchor"></div>
|
||||
|
||||
<?php endif; ?>
|
||||
@@ -92,22 +74,19 @@ if ( get_theme_mod('slider_enabled', false) ) :
|
||||
<!-- ===================================================== -->
|
||||
<main id="primary" class="site-main">
|
||||
<div class="container">
|
||||
|
||||
|
||||
<?php
|
||||
// Hole Sidebar-Einstellungen
|
||||
$sidebar_enabled = get_theme_mod( 'homepage_sidebar_enabled', false );
|
||||
$sidebar_enabled = get_theme_mod( 'homepage_sidebar_enabled', false );
|
||||
$sidebar_position = get_theme_mod( 'homepage_sidebar_position', 'right' );
|
||||
|
||||
// Prüfe ob mindestens ein Sidebar-Bereich aktiv ist
|
||||
|
||||
$has_sidebar_content = (
|
||||
is_active_sidebar( 'homepage-sidebar-top' ) ||
|
||||
is_active_sidebar( 'homepage-sidebar-top' ) ||
|
||||
is_active_sidebar( 'homepage-sidebar-middle-1' ) ||
|
||||
is_active_sidebar( 'homepage-sidebar-middle-2' ) ||
|
||||
is_active_sidebar( 'homepage-sidebar-bottom' ) ||
|
||||
is_active_sidebar( 'homepage-sidebar-bottom' ) ||
|
||||
is_active_sidebar( 'homepage-sidebar-extra' )
|
||||
);
|
||||
|
||||
// Setze CSS-Klassen basierend auf Sidebar-Status
|
||||
|
||||
$content_class = 'content-area';
|
||||
if ( $sidebar_enabled && $has_sidebar_content ) {
|
||||
$content_class = 'content-area with-sidebar sidebar-' . esc_attr( $sidebar_position );
|
||||
@@ -115,39 +94,10 @@ if ( get_theme_mod('slider_enabled', false) ) :
|
||||
?>
|
||||
|
||||
<div class="<?php echo esc_attr( $content_class ); ?>">
|
||||
|
||||
|
||||
<?php if ( $sidebar_enabled && $sidebar_position === 'left' && $has_sidebar_content ) : ?>
|
||||
<!-- SIDEBAR LINKS -->
|
||||
<aside class="homepage-sidebar sidebar-left">
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-top' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-top">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-top' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-middle-1' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-middle-1">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-middle-1' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-middle-2' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-middle-2">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-middle-2' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-bottom' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-bottom">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-bottom' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-extra' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-extra">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-extra' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php minecraft_modern_render_sidebar_sections(); ?>
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -155,71 +105,32 @@ if ( get_theme_mod('slider_enabled', false) ) :
|
||||
<div class="main-content">
|
||||
<?php if ( have_posts() ) : ?>
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class( 'post' ); ?>>
|
||||
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class('post'); ?>>
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<div class="post-thumbnail">
|
||||
<a href="<?php the_permalink(); ?>">
|
||||
<?php the_post_thumbnail( 'medium_large' ); ?>
|
||||
<?php the_post_thumbnail('medium_large'); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="post-content">
|
||||
<h2 class="post-title">
|
||||
<a href="<?php the_permalink(); ?>">
|
||||
<?php the_title(); ?>
|
||||
</a>
|
||||
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||||
</h2>
|
||||
|
||||
<div class="post-full-content">
|
||||
<?php the_content(); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
|
||||
<?php endwhile; ?>
|
||||
<?php else : ?>
|
||||
|
||||
<p><?php esc_html_e( 'Keine Beiträge gefunden.', 'minecraft-modern-theme' ); ?></p>
|
||||
|
||||
<p><?php esc_html_e('Keine Beiträge gefunden.', 'minecraft-modern-theme'); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( $sidebar_enabled && $sidebar_position === 'right' && $has_sidebar_content ) : ?>
|
||||
<!-- SIDEBAR RECHTS -->
|
||||
<aside class="homepage-sidebar sidebar-right">
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-top' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-top">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-top' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-middle-1' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-middle-1">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-middle-1' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-middle-2' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-middle-2">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-middle-2' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-bottom' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-bottom">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-bottom' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( is_active_sidebar( 'homepage-sidebar-extra' ) ) : ?>
|
||||
<div class="sidebar-section sidebar-extra">
|
||||
<?php dynamic_sidebar( 'homepage-sidebar-extra' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php minecraft_modern_render_sidebar_sections(); ?>
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -227,190 +138,4 @@ if ( get_theme_mod('slider_enabled', false) ) :
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- ===================================================== -->
|
||||
<!-- ZUSÄTZLICHES CSS FÜR SIDEBAR LAYOUT -->
|
||||
<!-- ===================================================== -->
|
||||
<style>
|
||||
/* Content ohne Sidebar - volle Breite */
|
||||
.content-area .main-content {
|
||||
width: 100%;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
/* Container mit Sidebar-Layout */
|
||||
.content-area.with-sidebar {
|
||||
display: grid;
|
||||
gap: 30px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
/* Sidebar rechts (Standard) */
|
||||
.content-area.with-sidebar.sidebar-right {
|
||||
grid-template-columns: 1fr 300px;
|
||||
}
|
||||
|
||||
.content-area.with-sidebar.sidebar-right .main-content {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.content-area.with-sidebar.sidebar-right .homepage-sidebar {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
/* Sidebar links */
|
||||
.content-area.with-sidebar.sidebar-left {
|
||||
grid-template-columns: 300px 1fr;
|
||||
}
|
||||
|
||||
.content-area.with-sidebar.sidebar-left .homepage-sidebar {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.content-area.with-sidebar.sidebar-left .main-content {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
/* Entfernt das Sticky-Verhalten der Sidebar komplett */
|
||||
.homepage-sidebar {
|
||||
position: relative !important;
|
||||
top: auto !important;
|
||||
background: var(--card-background, #1e2029);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
max-height: calc(200vh - 10vh);
|
||||
}
|
||||
|
||||
/* Sidebar Sections - Bereiche innerhalb der Sidebar */
|
||||
.homepage-sidebar .sidebar-section {
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.homepage-sidebar .sidebar-section:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Spezielle Styling für bestimmte Bereiche */
|
||||
.homepage-sidebar .sidebar-top {
|
||||
border-bottom: 2px solid var(--primary-accent, #00d4ff);
|
||||
}
|
||||
|
||||
.homepage-sidebar .sidebar-bottom {
|
||||
padding-top: 20px;
|
||||
border-top: 2px solid var(--primary-accent, #00d4ff);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.homepage-sidebar .widget {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.homepage-sidebar .widget:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.homepage-sidebar .widget-title {
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid var(--primary-accent, #00d4ff);
|
||||
color: var(--primary-accent, #00d4ff);
|
||||
}
|
||||
|
||||
.homepage-sidebar ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.homepage-sidebar ul li {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.homepage-sidebar ul li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.homepage-sidebar a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.homepage-sidebar a:hover {
|
||||
color: var(--primary-accent, #00d4ff);
|
||||
}
|
||||
|
||||
/* Mobile: Sidebar unter Content */
|
||||
@media (max-width: 768px) {
|
||||
.content-area.with-sidebar.sidebar-right,
|
||||
.content-area.with-sidebar.sidebar-left {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.content-area.with-sidebar .homepage-sidebar {
|
||||
order: 3 !important; /* Immer unten auf mobilen Geräten */
|
||||
position: relative;
|
||||
top: 0;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.content-area.with-sidebar .main-content {
|
||||
order: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark Mode Anpassungen */
|
||||
body.dark-mode .homepage-sidebar {
|
||||
background: #1e1e1e;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
body.dark-mode .homepage-sidebar ul li {
|
||||
border-bottom-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* Light Mode Anpassungen */
|
||||
body.light-mode .homepage-sidebar {
|
||||
background: #ffffff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
body.light-mode .homepage-sidebar .sidebar-section {
|
||||
border-bottom-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
body.light-mode .homepage-sidebar ul li {
|
||||
border-bottom-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
body.light-mode .homepage-sidebar .widget-title {
|
||||
color: var(--primary-accent, #00d4ff);
|
||||
}
|
||||
|
||||
/* Scrollbar Styling für Sidebar */
|
||||
.homepage-sidebar::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.homepage-sidebar::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.homepage-sidebar::-webkit-scrollbar-thumb {
|
||||
background: var(--primary-accent, #00d4ff);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.homepage-sidebar::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--primary-accent-hover, #00b8e6);
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
File diff suppressed because it is too large
Load Diff
98
Minecraft-Modern-Theme/get-channel-id.php
Normal file
98
Minecraft-Modern-Theme/get-channel-id.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* Hilfsskript: Finde Channel-ID für einen @Handle
|
||||
* Verwendet direkt die YouTube API (ohne WordPress)
|
||||
*/
|
||||
|
||||
// API Key aus wp-config.php lesen
|
||||
$wp_config_path = __DIR__ . '/../../../wp-config.php';
|
||||
$api_key = '';
|
||||
|
||||
if ( file_exists( $wp_config_path ) ) {
|
||||
$wp_config_content = file_get_contents( $wp_config_path );
|
||||
// Versuche YOUTUBE_API_KEY zu finden
|
||||
if ( preg_match( "/define\s*\(\s*['\"]YOUTUBE_API_KEY['\"]\s*,\s*['\"]([^'\"]+)['\"]/", $wp_config_content, $matches ) ) {
|
||||
$api_key = $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Direkte Eingabe hier (NUR FÜR TESTS!)
|
||||
if ( empty( $api_key ) ) {
|
||||
// TEMPORÄR: Trage hier deinen API Key ein
|
||||
$api_key = 'AIzaSyD-jSXZO-R4NJBySF0WL6SoFJmBDk2Gdbk'; // ← Dein API Key aus dem Customizer
|
||||
}
|
||||
|
||||
if ( ! isset( $argv[1] ) ) {
|
||||
echo "Verwendung: php get-channel-id.php @DeinHandle\n";
|
||||
echo "Beispiel: php get-channel-id.php @afartv\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$handle = $argv[1];
|
||||
|
||||
if ( empty( $api_key ) ) {
|
||||
echo "❌ Kein YouTube API Key gefunden!\n";
|
||||
echo " Trage den API Key temporär in Zeile 19 ein ODER\n";
|
||||
echo " Definiere YOUTUBE_API_KEY in wp-config.php\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// @ entfernen falls vorhanden
|
||||
$handle = ltrim( $handle, '@' );
|
||||
|
||||
echo "=== Channel-ID Abfrage ===\n\n";
|
||||
echo "Handle: @$handle\n";
|
||||
echo "API Key: " . substr($api_key, 0, 10) . "... (" . strlen($api_key) . " chars)\n\n";
|
||||
|
||||
// YouTube Data API v3: search.list
|
||||
$search_url = 'https://www.googleapis.com/youtube/v3/search?' . http_build_query( array(
|
||||
'part' => 'snippet',
|
||||
'q' => '@' . $handle,
|
||||
'type' => 'channel',
|
||||
'key' => $api_key,
|
||||
) );
|
||||
|
||||
echo "Sende API-Anfrage...\n";
|
||||
|
||||
$context = stream_context_create( array(
|
||||
'http' => array(
|
||||
'timeout' => 10,
|
||||
),
|
||||
) );
|
||||
|
||||
$response = file_get_contents( $search_url, false, $context );
|
||||
|
||||
if ( $response === false ) {
|
||||
echo "❌ API-Anfrage fehlgeschlagen\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$data = json_decode( $response, true );
|
||||
|
||||
if ( isset( $data['error'] ) ) {
|
||||
echo "❌ YouTube API Fehler:\n";
|
||||
echo " Code: " . $data['error']['code'] . "\n";
|
||||
echo " Nachricht: " . $data['error']['message'] . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( empty( $data['items'] ) ) {
|
||||
echo "❌ Kein Kanal gefunden für @$handle\n";
|
||||
echo " Versuche es mit einem anderen @Handle oder mit der vollständigen Kanal-URL.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$channel = $data['items'][0];
|
||||
$channel_id = $channel['id']['channelId'];
|
||||
$channel_title = $channel['snippet']['title'];
|
||||
|
||||
echo "\n✅ Kanal gefunden!\n\n";
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
||||
echo "Kanal-Titel: $channel_title\n";
|
||||
echo "Channel-ID: $channel_id\n";
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
|
||||
|
||||
echo "📋 Kopiere diese Channel-ID in dein Livestream-Post:\n";
|
||||
echo " Livestreams → Bearbeiten → YouTube Kanal-ID: $channel_id\n\n";
|
||||
|
||||
echo "✅ Fertig!\n";
|
||||
@@ -3,77 +3,144 @@
|
||||
<head>
|
||||
<meta charset="<?php bloginfo( 'charset' ); ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="referrer" content="strict-origin-when-cross-origin">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
<body <?php body_class(); ?>>
|
||||
<?php wp_body_open(); ?>
|
||||
|
||||
<header id="masthead" class="site-header">
|
||||
<?php
|
||||
$menu_style = get_theme_mod( 'header_menu_style', 'classic' );
|
||||
$branding_pos = get_theme_mod( 'sidebar_branding_position', 'left' );
|
||||
?>
|
||||
|
||||
<?php if ( $menu_style === 'sidebar' ) : ?>
|
||||
<!-- ══════════════════════════════════════════════════════════════
|
||||
LAYOUT 3: SIDEBAR
|
||||
═══════════════════════════════════════════════════════════════ -->
|
||||
<aside class="header-sidebar" id="header-sidebar" aria-hidden="true">
|
||||
<div class="header-sidebar-inner">
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php mm_nav(); ?>
|
||||
</div>
|
||||
<button class="sidebar-menu-close" aria-label="Menü schließen"><i class="fas fa-times"></i></button>
|
||||
</aside>
|
||||
<div class="header-sidebar-overlay" id="sidebar-overlay"></div>
|
||||
<header id="masthead" class="site-header site-header--sidebar branding-<?php echo esc_attr( $branding_pos ); ?>">
|
||||
<div class="container">
|
||||
<div class="header-main">
|
||||
<div class="site-branding">
|
||||
<?php
|
||||
if ( function_exists( 'the_custom_logo' ) && has_custom_logo() ) {
|
||||
the_custom_logo();
|
||||
}
|
||||
?>
|
||||
|
||||
<?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; ?>
|
||||
</div>
|
||||
|
||||
<!-- NAVIGATION START -->
|
||||
<nav id="site-navigation" class="main-navigation" role="navigation" aria-label="<?php esc_attr_e('Hauptmenü','minecraft-modern-theme'); ?>">
|
||||
<!-- Mobile Toggle Button -->
|
||||
<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
|
||||
<?php
|
||||
wp_nav_menu( array(
|
||||
'theme_location' => 'primary',
|
||||
'container' => false,
|
||||
'menu_class' => 'primary-menu',
|
||||
'fallback_cb' => false,
|
||||
) );
|
||||
?>
|
||||
</nav>
|
||||
<!-- NAVIGATION ENDE -->
|
||||
|
||||
<div class="header-info">
|
||||
<div class="social-links">
|
||||
<?php
|
||||
$social_icons = array(
|
||||
'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',
|
||||
'teamspeak' => 'fab fa-teamspeak',
|
||||
'spotify' => 'fab fa-spotify'
|
||||
);
|
||||
|
||||
foreach ( $social_icons as $key => $class ) {
|
||||
if ( get_theme_mod( 'social_' . $key ) ) {
|
||||
echo '<a href="' . esc_url( get_theme_mod( 'social_' . $key ) ) . '" target="_blank" rel="noopener"><i class="' . esc_attr( $class ) . '"></i></a>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- .header-main -->
|
||||
<button class="sidebar-menu-toggle" aria-label="Menü öffnen" aria-expanded="false" aria-controls="header-sidebar">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<?php if ( $branding_pos === 'right' ) : ?>
|
||||
<?php mm_icons(); ?>
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php elseif ( $branding_pos === 'center' ) : ?>
|
||||
<div class="header-center-spacer"></div>
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php mm_icons(); ?>
|
||||
<?php else : ?>
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php mm_icons(); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<?php elseif ( $menu_style === 'centered' ) : ?>
|
||||
<!-- ══════════════════════════════════════════════════════════════
|
||||
LAYOUT 2: ZENTRIERT
|
||||
═══════════════════════════════════════════════════════════════ -->
|
||||
<header id="masthead" class="site-header site-header--centered">
|
||||
<div class="container">
|
||||
<!-- Zeile 1: Branding + Icons -->
|
||||
<div class="header-row header-row-branding pos-<?php echo esc_attr( $branding_pos ); ?>">
|
||||
<?php if ( $branding_pos === 'left' ) : ?>
|
||||
<?php mm_branding( true ); ?>
|
||||
<div class="header-spacer"></div>
|
||||
<?php mm_icons(); ?>
|
||||
<?php elseif ( $branding_pos === 'right' ) : ?>
|
||||
<?php mm_icons(); ?>
|
||||
<div class="header-spacer"></div>
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php else : ?>
|
||||
<div class="header-spacer"></div>
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php mm_icons(); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<!-- Zeile 2: Navigation zentriert -->
|
||||
<div class="header-row header-row-nav">
|
||||
<?php mm_nav(); ?>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<?php elseif ( $menu_style === 'mega' ) : ?>
|
||||
<!-- ══════════════════════════════════════════════════════════════
|
||||
LAYOUT 4: MEGA-MENÜ
|
||||
═══════════════════════════════════════════════════════════════ -->
|
||||
<header id="masthead" class="site-header site-header--mega">
|
||||
<div class="container">
|
||||
<!-- Zeile 1: Branding + Icons -->
|
||||
<div class="header-row header-row-branding pos-<?php echo esc_attr( $branding_pos ); ?>">
|
||||
<?php if ( $branding_pos === 'left' ) : ?>
|
||||
<?php mm_branding( true ); ?>
|
||||
<div class="header-spacer"></div>
|
||||
<?php mm_icons(); ?>
|
||||
<?php elseif ( $branding_pos === 'right' ) : ?>
|
||||
<?php mm_icons(); ?>
|
||||
<div class="header-spacer"></div>
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php else : ?>
|
||||
<div class="header-spacer"></div>
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php mm_icons(); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Zeile 2: Menü volle Breite -->
|
||||
<div class="header-mega-nav-bar">
|
||||
<div class="container">
|
||||
<?php mm_nav('mega-nav'); ?>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<?php else : ?>
|
||||
<!-- ══════════════════════════════════════════════════════════════
|
||||
LAYOUT 1: CLASSIC
|
||||
═══════════════════════════════════════════════════════════════ -->
|
||||
<header id="masthead" class="site-header site-header--classic">
|
||||
<div class="container">
|
||||
<?php if ( $branding_pos === 'center' ) : ?>
|
||||
<!-- Center: Branding oben zentriert, Menü darunter -->
|
||||
<div class="header-row header-row-branding pos-center">
|
||||
<div class="header-spacer"></div>
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php mm_icons(); ?>
|
||||
</div>
|
||||
<div class="header-row header-row-nav">
|
||||
<?php mm_nav(); ?>
|
||||
</div>
|
||||
<?php elseif ( $branding_pos === 'right' ) : ?>
|
||||
<!-- Right: Icons + Nav links, Branding rechts -->
|
||||
<div class="header-main">
|
||||
<?php mm_nav(); ?>
|
||||
<div class="header-spacer"></div>
|
||||
<?php mm_icons(); ?>
|
||||
<?php mm_branding( true ); ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<!-- Left: Branding links, Nav Mitte, Icons rechts -->
|
||||
<div class="header-main">
|
||||
<?php mm_branding( true ); ?>
|
||||
<?php mm_nav(); ?>
|
||||
<?php mm_icons(); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<?php endif; ?>
|
||||
2099
Minecraft-Modern-Theme/inc/assistant-ajax.php
Normal file
2099
Minecraft-Modern-Theme/inc/assistant-ajax.php
Normal file
File diff suppressed because it is too large
Load Diff
913
Minecraft-Modern-Theme/inc/assistant-widget.php
Normal file
913
Minecraft-Modern-Theme/inc/assistant-widget.php
Normal file
@@ -0,0 +1,913 @@
|
||||
<?php
|
||||
// BUG-FIX: Das 'assistant_position' Setting wurde hier in einem eigenen
|
||||
// customize_register-Hook registriert, BEVOR customizer.php die Section
|
||||
// 'assistant_settings' anlegt. Das führte dazu, dass das Control keiner
|
||||
// sichtbaren Section zugeordnet war.
|
||||
// Die Registrierung wurde in inc/customizer.php verschoben (direkt nach
|
||||
// den anderen assistant_*-Controls). Dieser Hook-Block kann daher entfallen.
|
||||
/**
|
||||
* Assistant Widget – Virtueller Support-Assistent
|
||||
*
|
||||
* Vollständig integriert mit allen Plugins:
|
||||
* → LiteBans Manager
|
||||
* → MC Player History
|
||||
* → BungeeCord Status
|
||||
* → Multi Rules
|
||||
* → WP Multi Wiki
|
||||
* → WP Ingame Shop Pro
|
||||
* → WP Multi Ticket Pro
|
||||
* → WP Business Forum
|
||||
* → MC MultiServer Gallery PRO
|
||||
* → FAQ (Custom Post Type)
|
||||
*
|
||||
* @version 3.1
|
||||
* @author M_Viper
|
||||
*
|
||||
* WICHTIG: Die eigentliche Antwort-Logik liegt in assistant-ajax.php.
|
||||
* Diese Datei enthält nur: Admin-Backend, Widget-Frontend, JS.
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
// =========================================================================
|
||||
// AJAX-Handler laden (assistant-ajax.php)
|
||||
// =========================================================================
|
||||
$mm_ajax_file = get_template_directory() . '/inc/assistant-ajax.php';
|
||||
if ( file_exists( $mm_ajax_file ) ) {
|
||||
require_once $mm_ajax_file;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 1. ADMIN-BACKEND – BOT-ZENTRALE
|
||||
// =========================================================================
|
||||
|
||||
add_action( 'admin_menu', function () {
|
||||
// Dashicon für Chatbot verwenden (z.B. dashicons-format-chat)
|
||||
add_menu_page(
|
||||
'Bot Setup',
|
||||
'Bot Setup',
|
||||
'manage_options',
|
||||
'bot-setup',
|
||||
'mm_render_bot_admin',
|
||||
'dashicons-format-chat',
|
||||
65
|
||||
);
|
||||
} );
|
||||
|
||||
add_action( 'admin_init', function () {
|
||||
register_setting( 'mm_bot_settings', 'mm_bot_data', [
|
||||
'sanitize_callback' => 'mm_bot_sanitize_settings',
|
||||
] );
|
||||
} );
|
||||
|
||||
function mm_bot_sanitize_settings( $input ) {
|
||||
$clean = [];
|
||||
|
||||
$text_fields = [ 'server_ip', 'server_ver', 'server_specs', 'bot_name', 'welcome' ];
|
||||
$url_fields = [
|
||||
'url_wiki', 'url_rules', 'url_tickets', 'url_faq',
|
||||
'url_team', 'url_shop', 'url_gallery', 'url_player_history',
|
||||
'url_forum', 'link_discord', 'litebans_dashboard_url',
|
||||
];
|
||||
|
||||
foreach ( $text_fields as $f ) {
|
||||
$clean[ $f ] = isset( $input[ $f ] ) ? sanitize_text_field( $input[ $f ] ) : '';
|
||||
}
|
||||
foreach ( $url_fields as $f ) {
|
||||
$clean[ $f ] = isset( $input[ $f ] ) ? esc_url_raw( $input[ $f ] ) : '';
|
||||
}
|
||||
|
||||
$clean['qa'] = [];
|
||||
if ( ! empty( $input['qa'] ) && is_array( $input['qa'] ) ) {
|
||||
foreach ( $input['qa'] as $item ) {
|
||||
if ( empty( $item['keys'] ) ) continue;
|
||||
$clean['qa'][] = [
|
||||
'keys' => sanitize_text_field( $item['keys'] ),
|
||||
'val' => wp_kses_post( $item['val'] ),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $clean;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 2. ADMIN-SEITE
|
||||
// =========================================================================
|
||||
|
||||
// BUG-FIX: Funktion außerhalb von mm_render_bot_admin() definieren.
|
||||
// Innerhalb einer Funktion definierte benannte Funktionen erzeugen einen
|
||||
// Fatal Error "Cannot redeclare", wenn die äußere Funktion jemals ein
|
||||
// zweites Mal ausgeführt wird (z.B. durch AJAX, REST, bestimmte Plugins).
|
||||
if ( ! function_exists( 'mm_find_page_by_shortcode' ) ) :
|
||||
function mm_find_page_by_shortcode( $shortcodes ) {
|
||||
global $wpdb;
|
||||
$conditions = [];
|
||||
foreach ( (array) $shortcodes as $sc ) {
|
||||
$conditions[] = $wpdb->prepare( 'post_content LIKE %s', '%[' . $wpdb->esc_like( $sc ) . '%' );
|
||||
}
|
||||
if ( empty( $conditions ) ) return '';
|
||||
$where = implode( ' OR ', $conditions );
|
||||
$page = $wpdb->get_row(
|
||||
"SELECT ID FROM {$wpdb->posts}
|
||||
WHERE post_status = 'publish'
|
||||
AND post_type IN ('page','post')
|
||||
AND ({$where})
|
||||
LIMIT 1"
|
||||
);
|
||||
return $page ? get_permalink( $page->ID ) : '';
|
||||
}
|
||||
endif;
|
||||
|
||||
function mm_render_bot_admin() {
|
||||
$data = get_option( 'mm_bot_data', [] );
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><span class="dashicons dashicons-robot"></span> Bot-Zentrale</h1>
|
||||
|
||||
<style>
|
||||
.bot-card { background:#fff; padding:20px; border:1px solid #ccd0d4; border-radius:8px; margin-top:20px; box-shadow:0 2px 4px rgba(0,0,0,.05); }
|
||||
.bot-card h2 { margin-top:0; color:#0073aa; border-bottom:1px solid #eee; padding-bottom:12px; }
|
||||
.bot-card p.description { color:#666; font-style:italic; margin-top:4px; }
|
||||
.badge { display:inline-block; background:#0099ff; color:#fff; font-size:11px; padding:1px 7px; border-radius:10px; margin-left:6px; vertical-align:middle; }
|
||||
.badge.inactive { background:#999; }
|
||||
</style>
|
||||
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields( 'mm_bot_settings' ); ?>
|
||||
|
||||
<!-- KARTE 1: Server -->
|
||||
<div class="bot-card">
|
||||
<h2>1. Server-Infos</h2>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th><label>Server-IP / Adresse</label></th>
|
||||
<td>
|
||||
<input type="text" name="mm_bot_data[server_ip]" value="<?php echo esc_attr( $data['server_ip'] ?? '' ); ?>" class="regular-text" placeholder="play.example.net">
|
||||
<p class="description">Wird bei Fragen nach der Server-IP angezeigt.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label>Minecraft-Version</label></th>
|
||||
<td><input type="text" name="mm_bot_data[server_ver]" value="<?php echo esc_attr( $data['server_ver'] ?? '' ); ?>" class="small-text" placeholder="1.21.1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label>Hardware / Specs</label></th>
|
||||
<td>
|
||||
<input type="text" name="mm_bot_data[server_specs]" value="<?php echo esc_attr( $data['server_specs'] ?? '' ); ?>" class="large-text" placeholder="z.B. Ryzen 9, 64 GB RAM, NVMe SSD">
|
||||
<p class="description">Wird bei Fragen nach der Server-Hardware angezeigt.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- KARTE 2: Bot-Einstellungen -->
|
||||
<div class="bot-card">
|
||||
<h2>2. Bot-Einstellungen</h2>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th><label>Bot-Name</label></th>
|
||||
<td><input type="text" name="mm_bot_data[bot_name]" value="<?php echo esc_attr( $data['bot_name'] ?? '' ); ?>" class="regular-text" placeholder="Viper-Bot"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label>Minecraft-UUID / Name (Avatar)</label></th>
|
||||
<td>
|
||||
<?php
|
||||
$uuid = get_theme_mod( 'assistant_minecraft_uuid', 'Steve' );
|
||||
?>
|
||||
<input type="text" name="assistant_mc_uuid_preview" value="<?php echo esc_attr( $uuid ); ?>" class="regular-text" disabled>
|
||||
<p class="description">UUID / Name wird im Theme-Customizer unter "Assistent" gesetzt.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label>Begrüßungstext</label></th>
|
||||
<td>
|
||||
<textarea name="mm_bot_data[welcome]" rows="3" class="large-text"><?php echo esc_textarea( $data['welcome'] ?? '' ); ?></textarea>
|
||||
<p class="description">Erster Text der beim Öffnen des Assistenten angezeigt wird.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- KARTE 3: Links -->
|
||||
<div class="bot-card">
|
||||
<h2>3. Wichtige Links</h2>
|
||||
<p class="description" style="margin-bottom:12px;">
|
||||
💡 Wenn eine Seite mit dem passenden Shortcode gefunden wird, erscheint ein <strong>„Vorschlag übernehmen"</strong>-Button.
|
||||
</p>
|
||||
|
||||
<?php
|
||||
$autodetect = [
|
||||
'url_wiki' => mm_find_page_by_shortcode( ['wmw_wiki', 'wmw_search', 'wmw_article'] ),
|
||||
'url_rules' => mm_find_page_by_shortcode( ['mrp_rules', 'mc_rules', 'multi_rules'] ),
|
||||
'url_tickets' => mm_find_page_by_shortcode( ['wmtp_tickets', 'wm_tickets', 'multi_ticket'] ),
|
||||
'url_shop' => mm_find_page_by_shortcode( ['wis_shop', 'ingame_shop', 'wis_items'] ),
|
||||
'url_gallery' => mm_find_page_by_shortcode( ['mc_gallery', 'mc_gallery_overview', 'mc_gallery_upload', 'mc_gallery_all_albums'] ),
|
||||
'url_faq' => mm_find_page_by_shortcode( ['faq_list', 'faq', 'faq_page'] ),
|
||||
'url_player_history' => mm_find_page_by_shortcode( ['mc_player_history', 'mc_players', 'player_history'] ),
|
||||
'url_forum' => mm_find_page_by_shortcode( ['business_forum'] ),
|
||||
'litebans_dashboard_url' => mm_find_page_by_shortcode( ['litebans_dashboard', 'litebans', 'wp_litebans'] ),
|
||||
];
|
||||
|
||||
$links = [
|
||||
'url_wiki' => [ 'label' => '📖 Wiki-URL', 'plugin' => 'WP Multi Wiki', 'active' => post_type_exists( 'wmw_article' ) ],
|
||||
'url_rules' => [ 'label' => '📜 Regelwerk-URL', 'plugin' => 'Multi Rules', 'active' => function_exists( 'mrp_get_plugin_version' ) ],
|
||||
'url_tickets' => [ 'label' => '🎫 Ticket/Support-URL', 'plugin' => 'WP Multi Ticket Pro', 'active' => class_exists( 'WP_Multi_Ticket_Pro' ) ],
|
||||
'url_shop' => [ 'label' => '🛒 Shop-URL', 'plugin' => 'WP Ingame Shop Pro', 'active' => class_exists( 'WIS_Activator' ) ],
|
||||
'url_gallery' => [ 'label' => '📷 Galerie-URL', 'plugin' => 'MC MultiServer Gallery PRO', 'active' => post_type_exists( 'mc_gallery' ) ],
|
||||
'url_faq' => [ 'label' => '❓ FAQ-URL', 'plugin' => 'FAQ Post Type', 'active' => post_type_exists( 'faq' ) ],
|
||||
'url_player_history' => [ 'label' => '👤 Spieler-History-URL', 'plugin' => 'MC Player History', 'active' => function_exists( 'mcph_get_plugin_version' ) ],
|
||||
'url_forum' => [ 'label' => '💬 Forum-URL', 'plugin' => 'WP Business Forum', 'active' => class_exists( 'WBF_DB' ) ],
|
||||
'url_team' => [ 'label' => '👥 Team-URL', 'plugin' => '', 'active' => true ],
|
||||
'link_discord' => [ 'label' => '💬 Discord-Einladung', 'plugin' => '', 'active' => true ],
|
||||
'litebans_dashboard_url' => [ 'label' => '🔨 LiteBans Dashboard-URL', 'plugin' => 'LiteBans Manager', 'active' => class_exists( 'WP_LiteBans_Pro' ) ],
|
||||
];
|
||||
?>
|
||||
|
||||
<style>
|
||||
.mm-url-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
||||
.mm-url-row input.large-text { flex: 1; min-width: 200px; }
|
||||
.mm-suggest-btn {
|
||||
background: #e8f5e9; color: #2e7d32; border: 1px solid #a5d6a7;
|
||||
border-radius: 4px; padding: 5px 10px; font-size: 12px;
|
||||
cursor: pointer; white-space: nowrap; line-height: 1.4;
|
||||
transition: background .2s;
|
||||
}
|
||||
.mm-suggest-btn:hover { background: #c8e6c9; }
|
||||
.mm-suggest-url { font-size: 11px; color: #666; max-width: 260px;
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
display: inline-block; vertical-align: middle; }
|
||||
.mm-autofill-all {
|
||||
margin-bottom: 12px; background: #0073aa; color: #fff;
|
||||
border: none; border-radius: 4px; padding: 7px 16px;
|
||||
cursor: pointer; font-size: 13px;
|
||||
}
|
||||
.mm-autofill-all:hover { background: #005f8d; }
|
||||
</style>
|
||||
|
||||
<?php
|
||||
$has_any_suggestion = ! empty( array_filter( $autodetect ) );
|
||||
if ( $has_any_suggestion ) : ?>
|
||||
<button type="button" class="mm-autofill-all" id="mm-autofill-all">
|
||||
⚡ Alle erkannten URLs automatisch übernehmen
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<table class="form-table">
|
||||
<?php foreach ( $links as $key => $cfg ) :
|
||||
$badge = '';
|
||||
if ( $cfg['plugin'] ) {
|
||||
$cls = $cfg['active'] ? 'badge' : 'badge inactive';
|
||||
$txt = $cfg['active'] ? 'aktiv' : 'inaktiv';
|
||||
$badge = '<span class="' . $cls . '">' . esc_html( $cfg['plugin'] ) . ' ' . $txt . '</span>';
|
||||
}
|
||||
$saved = $data[ $key ] ?? '';
|
||||
$suggested = $autodetect[ $key ] ?? '';
|
||||
$show_suggest = $suggested && $suggested !== $saved;
|
||||
?>
|
||||
<tr>
|
||||
<th><label for="mm_link_<?php echo esc_attr( $key ); ?>"><?php echo $cfg['label'] . $badge; ?></label></th>
|
||||
<td>
|
||||
<div class="mm-url-row">
|
||||
<input type="url"
|
||||
id="mm_link_<?php echo esc_attr( $key ); ?>"
|
||||
name="mm_bot_data[<?php echo esc_attr( $key ); ?>]"
|
||||
value="<?php echo esc_url( $saved ); ?>"
|
||||
class="large-text"
|
||||
data-key="<?php echo esc_attr( $key ); ?>">
|
||||
<?php if ( $show_suggest ) : ?>
|
||||
<button type="button"
|
||||
class="mm-suggest-btn"
|
||||
data-target="mm_link_<?php echo esc_attr( $key ); ?>"
|
||||
data-url="<?php echo esc_url( $suggested ); ?>">
|
||||
✓ Vorschlag übernehmen
|
||||
</button>
|
||||
<span class="mm-suggest-url" title="<?php echo esc_attr( $suggested ); ?>">
|
||||
<?php echo esc_html( $suggested ); ?>
|
||||
</span>
|
||||
<?php elseif ( $saved && $suggested && $suggested === $saved ) : ?>
|
||||
<span style="color:#2e7d32;font-size:12px;">✔ Erkannt & gesetzt</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- KARTE 4: Individuelle Q&A -->
|
||||
<div class="bot-card">
|
||||
<h2>4. Individuelle Q&A</h2>
|
||||
<p class="description">
|
||||
Schlüsselwörter (kommagetrennt) → Antwort. Hat höchste Priorität vor allen Plugin-Abfragen.
|
||||
</p>
|
||||
<table class="form-table" style="width:100%;">
|
||||
<tr>
|
||||
<th style="width:200px;">Schlüsselwörter</th>
|
||||
<th>Antwort (HTML erlaubt)</th>
|
||||
<th style="width:50px;"></th>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="mm-qa-rows">
|
||||
<?php
|
||||
$qa = $data['qa'] ?? [];
|
||||
foreach ( $qa as $i => $item ) :
|
||||
if ( empty( $item['keys'] ) ) continue;
|
||||
?>
|
||||
<div class="qa-item" style="display:flex;gap:10px;margin-bottom:10px;align-items:center;">
|
||||
<input type="text" name="mm_bot_data[qa][<?php echo $i; ?>][keys]"
|
||||
value="<?php echo esc_attr( $item['keys'] ); ?>"
|
||||
style="flex:1;" placeholder="discord, invite, join discord">
|
||||
<input type="text" name="mm_bot_data[qa][<?php echo $i; ?>][val]"
|
||||
value="<?php echo esc_attr( $item['val'] ); ?>"
|
||||
style="flex:2;" placeholder="Antworttext oder HTML">
|
||||
<button type="button" class="button remove-qa" title="Entfernen">✕</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<button type="button" id="add-qa" class="button button-primary">+ Neue Q&A-Zeile</button>
|
||||
</div>
|
||||
|
||||
<?php submit_button( 'Einstellungen speichern' ); ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
jQuery(function($){
|
||||
// Q&A Zeilen
|
||||
$('#add-qa').on('click', function(){
|
||||
var i = Date.now();
|
||||
$('#mm-qa-rows').append(
|
||||
'<div class="qa-item" style="display:flex;gap:10px;margin-bottom:10px;align-items:center;">' +
|
||||
'<input type="text" name="mm_bot_data[qa]['+i+'][keys]" style="flex:1;" placeholder="discord, invite">' +
|
||||
'<input type="text" name="mm_bot_data[qa]['+i+'][val]" style="flex:2;" placeholder="Antwort...">' +
|
||||
'<button type="button" class="button remove-qa" title="Entfernen">✕</button>' +
|
||||
'</div>'
|
||||
);
|
||||
});
|
||||
$(document).on('click', '.remove-qa', function(){
|
||||
$(this).closest('.qa-item').remove();
|
||||
});
|
||||
|
||||
// Einzelnen Vorschlag übernehmen
|
||||
$(document).on('click', '.mm-suggest-btn', function(){
|
||||
var $btn = $(this);
|
||||
var target = $btn.data('target');
|
||||
var url = $btn.data('url');
|
||||
$('#' + target).val(url);
|
||||
$btn.replaceWith('<span style="color:#2e7d32;font-size:12px;">✔ Übernommen</span>');
|
||||
$(this).siblings('.mm-suggest-url').remove();
|
||||
});
|
||||
|
||||
// Alle auf einmal übernehmen
|
||||
$('#mm-autofill-all').on('click', function(){
|
||||
$('.mm-suggest-btn').each(function(){
|
||||
var $btn = $(this);
|
||||
var target = $btn.data('target');
|
||||
var url = $btn.data('url');
|
||||
if ( url && ! $('#' + target).val() ) {
|
||||
$('#' + target).val(url);
|
||||
$btn.closest('.mm-url-row').find('.mm-suggest-url').remove();
|
||||
$btn.replaceWith('<span style="color:#2e7d32;font-size:12px;">✔ Übernommen</span>');
|
||||
}
|
||||
});
|
||||
$(this).prop('disabled', true).text('✔ Fertig – bitte speichern');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 3. ASSETS LADEN
|
||||
// =========================================================================
|
||||
|
||||
add_action( 'wp_enqueue_scripts', function () {
|
||||
// CSS aus Theme-Ordner (falls vorhanden), sonst Inline-Fallback
|
||||
$css_file = get_template_directory() . '/css/assistant-widget.css';
|
||||
if ( file_exists( $css_file ) ) {
|
||||
wp_enqueue_style(
|
||||
'mm-assistant-widget',
|
||||
get_template_directory_uri() . '/css/assistant-widget.css',
|
||||
[],
|
||||
'3.1'
|
||||
);
|
||||
}
|
||||
} );
|
||||
|
||||
// =========================================================================
|
||||
// 4. FRONTEND WIDGET
|
||||
// =========================================================================
|
||||
|
||||
add_action( 'wp_footer', 'mm_bot_render_widget', 50 );
|
||||
|
||||
function mm_bot_render_widget() {
|
||||
// Sichtbarkeit prüfen: Assistent nur anzeigen, wenn im Customizer aktiviert
|
||||
// BUG-FIX: Early return MUSS als erstes kommen, bevor andere Variablen gelesen werden.
|
||||
if ( ! get_theme_mod( 'assistant_enabled', false ) ) {
|
||||
return;
|
||||
}
|
||||
$data = get_option( 'mm_bot_data', [] );
|
||||
$uuid = sanitize_text_field( trim( get_theme_mod( 'assistant_minecraft_uuid', 'Steve' ) ) );
|
||||
// BUG-FIX: $avatar_view muss VOR $body_offset definiert werden.
|
||||
$avatar_view = get_theme_mod( 'assistant_avatar_view', 'head' );
|
||||
// Offset für Chat-Fenster, wenn Ganzkörper-Avatar aktiv ist
|
||||
$body_offset = ( $avatar_view === 'body' ) ? 'margin-right: 60px;' : '';
|
||||
$name = ! empty( $data['bot_name'] ) ? esc_html( $data['bot_name'] ) : 'Viper-Bot';
|
||||
$welcome = ! empty( $data['welcome'] ) ? $data['welcome'] : 'Hallo! Wie kann ich dir helfen? 👋';
|
||||
$nonce = wp_create_nonce( 'mm_bot_nonce' );
|
||||
$ajax = admin_url( 'admin-ajax.php' );
|
||||
|
||||
// ── Quick-Buttons: nur anzeigen wenn Plugin aktiv + URL gesetzt ──────
|
||||
$quick = [];
|
||||
|
||||
// Server-Status (immer wenn IP konfiguriert oder BungeeCord-Plugin aktiv)
|
||||
$servers = get_option( 'mcss_servers', [] );
|
||||
if ( ! empty( $data['server_ip'] ) || ! empty( $servers ) ) {
|
||||
$quick[] = [ 'label' => '🖥️ Server-Status', 'q' => 'server status' ];
|
||||
}
|
||||
|
||||
// Regeln – nur wenn URL im Backend gesetzt
|
||||
if ( ! empty( $data['url_rules'] ) ) {
|
||||
$quick[] = [ 'label' => '📜 Regelwerk', 'q' => 'regeln' ];
|
||||
}
|
||||
|
||||
// Wiki – nur wenn URL im Backend gesetzt
|
||||
if ( ! empty( $data['url_wiki'] ) ) {
|
||||
$quick[] = [ 'label' => '📖 Wiki', 'q' => 'wiki' ];
|
||||
}
|
||||
|
||||
// Shop – nur wenn URL im Backend gesetzt
|
||||
global $wpdb;
|
||||
if ( ! empty( $data['url_shop'] ) ) {
|
||||
$quick[] = [ 'label' => '🛒 Shop', 'q' => 'shop' ];
|
||||
}
|
||||
|
||||
// Ticket / Support – nur wenn URL im Backend gesetzt
|
||||
if ( ! empty( $data['url_tickets'] ) ) {
|
||||
$quick[] = [ 'label' => '🎫 Support-Ticket', 'q' => 'ticket erstellen' ];
|
||||
}
|
||||
|
||||
// Forum
|
||||
if ( class_exists( 'WBF_DB' ) && ! empty( $data['url_forum'] ) ) {
|
||||
$quick[] = [ 'label' => '💬 Forum', 'q' => 'forum' ];
|
||||
}
|
||||
|
||||
// Galerie – nur wenn URL im Backend gesetzt
|
||||
if ( ! empty( $data['url_gallery'] ) ) {
|
||||
$quick[] = [ 'label' => '📷 Galerie', 'q' => 'galerie' ];
|
||||
}
|
||||
|
||||
// Ban-Status
|
||||
$lb = get_option( 'wp_litebans_pro_settings', [] );
|
||||
if ( ! empty( $lb['db_name'] ) ) {
|
||||
$quick[] = [ 'label' => '🔨 Strafen prüfen', 'q' => 'meine strafen' ];
|
||||
}
|
||||
|
||||
// Spieler-History – nur wenn URL im Backend gesetzt
|
||||
if ( ! empty( $data['url_player_history'] ) ) {
|
||||
$quick[] = [ 'label' => '⏱️ Spielzeit', 'q' => 'spielzeit' ];
|
||||
}
|
||||
|
||||
// Discord
|
||||
if ( ! empty( $data['link_discord'] ) ) {
|
||||
$quick[] = [ 'label' => '💬 Discord', 'q' => 'discord' ];
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
$assistant_position = get_theme_mod( 'assistant_position', 'bottom_right' );
|
||||
$pos_class = 'mm-bot-pos-' . esc_attr( $assistant_position );
|
||||
?>
|
||||
<div id="mm-bot-root" class="<?php echo $pos_class; ?>">
|
||||
|
||||
<!-- Chat-Fenster -->
|
||||
<div id="mm-bot-chat" style="display:none;<?php echo $body_offset; ?>" aria-label="Assistent" role="dialog">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="mm-bot-header">
|
||||
<div class="mm-bot-status" title="Online"></div>
|
||||
<?php
|
||||
// Avatar-URL je nach Ansicht
|
||||
if ($avatar_view === 'body') {
|
||||
$avatar_url = 'https://mc-heads.net/body/' . rawurlencode($uuid) . '/32';
|
||||
} elseif ($avatar_view === '3dhead') {
|
||||
$avatar_url = 'https://visage.surgeplay.com/head/48/' . rawurlencode($uuid);
|
||||
} else {
|
||||
$avatar_url = 'https://mc-heads.net/avatar/' . rawurlencode($uuid) . '/32';
|
||||
}
|
||||
?>
|
||||
<img class="mm-bot-avatar-small" src="<?php echo esc_url($avatar_url); ?>" alt="<?php echo $name; ?>">
|
||||
<span class="mm-bot-title"><?php echo $name; ?></span>
|
||||
<button id="mm-bot-close" aria-label="Schließen">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Nachrichten -->
|
||||
<div id="mm-bot-content" role="log" aria-live="polite">
|
||||
<div class="mm-msg bot">
|
||||
<?php echo nl2br( wp_kses_post( $welcome ) ); ?>
|
||||
</div>
|
||||
|
||||
<?php if ( ! empty( $quick ) ) : ?>
|
||||
<div class="mm-bot-quick">
|
||||
<?php foreach ( $quick as $btn ) : ?>
|
||||
<button class="mm-quick-btn"
|
||||
data-q="<?php echo esc_attr( $btn['q'] ); ?>"
|
||||
type="button">
|
||||
<?php echo esc_html( $btn['label'] ); ?>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Eingabe -->
|
||||
<div class="mm-bot-input-area">
|
||||
<input type="text"
|
||||
id="mm-bot-field"
|
||||
placeholder="Deine Frage eingeben…"
|
||||
autocomplete="off"
|
||||
maxlength="300"
|
||||
aria-label="Nachricht eingeben">
|
||||
<button id="mm-bot-send" type="button" aria-label="Senden">➤</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Launcher-Button -->
|
||||
<button id="mm-bot-launcher" type="button" aria-label="Assistenten öffnen" title="<?php echo $name; ?>" style="background:transparent;border:none;box-shadow:none;width:auto;height:auto;padding:0;display:flex;align-items:center;justify-content:center;overflow:visible;">
|
||||
<?php
|
||||
// Launcher-Avatar-URL je nach Ansicht (größer)
|
||||
if ($avatar_view === 'body') {
|
||||
$launcher_url = 'https://mc-heads.net/body/' . rawurlencode($uuid) . '/144';
|
||||
$img_style = 'width:72px;height:144px;object-fit:contain;';
|
||||
if ($assistant_position === 'bottom_right' || $assistant_position === 'top_right') {
|
||||
$img_style .= 'transform:scaleX(-1);';
|
||||
}
|
||||
} elseif ($avatar_view === '3dhead') {
|
||||
$launcher_url = 'https://visage.surgeplay.com/head/80/' . rawurlencode($uuid);
|
||||
$img_style = 'width:60px;height:60px;object-fit:cover;';
|
||||
if ($assistant_position === 'bottom_left' || $assistant_position === 'top_left') {
|
||||
$img_style .= 'transform:scaleX(-1);';
|
||||
}
|
||||
} else {
|
||||
$launcher_url = 'https://mc-heads.net/avatar/' . rawurlencode($uuid) . '/60';
|
||||
$img_style = 'width:60px;height:60px;object-fit:cover;';
|
||||
}
|
||||
?>
|
||||
<img src="<?php echo esc_url($launcher_url); ?>" alt="<?php echo $name; ?>" style="<?php echo $img_style; ?>border-radius:8px;background:none;box-shadow:none;">
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function($){
|
||||
'use strict';
|
||||
|
||||
var $chat = $('#mm-bot-chat');
|
||||
var $field = $('#mm-bot-field');
|
||||
var $content = $('#mm-bot-content');
|
||||
var nonce = <?php echo wp_json_encode( $nonce ); ?>;
|
||||
var ajaxUrl = <?php echo wp_json_encode( $ajax ); ?>;
|
||||
var isLoading = false;
|
||||
|
||||
// ── Öffnen / Schließen ────────────────────────────────────
|
||||
$('#mm-bot-launcher').on('click', function(){
|
||||
$chat.fadeToggle(200);
|
||||
if ($chat.is(':visible')) {
|
||||
$field.trigger('focus');
|
||||
scrollBottom();
|
||||
}
|
||||
});
|
||||
|
||||
$('#mm-bot-close').on('click', function(){
|
||||
$chat.fadeOut(200);
|
||||
});
|
||||
|
||||
// ── Quick-Buttons ─────────────────────────────────────────
|
||||
$(document).on('click', '.mm-quick-btn', function(){
|
||||
sendMessage( $(this).data('q') );
|
||||
});
|
||||
|
||||
// ── Senden ────────────────────────────────────────────────
|
||||
$('#mm-bot-send').on('click', function(){ sendMessage(); });
|
||||
$field.on('keydown', function(e){
|
||||
if (e.which === 13 && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
sendMessage();
|
||||
}
|
||||
});
|
||||
|
||||
function sendMessage(forceText) {
|
||||
if (isLoading) return;
|
||||
|
||||
var val = forceText !== undefined
|
||||
? String(forceText).trim()
|
||||
: $field.val().trim();
|
||||
|
||||
if (!val) return;
|
||||
|
||||
// Nutzernachricht anzeigen
|
||||
appendMsg('user', $('<span>').text(val).html());
|
||||
if (forceText === undefined) $field.val('');
|
||||
|
||||
// Loader
|
||||
isLoading = true;
|
||||
var $loader = $('<div class="mm-msg bot mm-loading" aria-label="Lädt">···</div>');
|
||||
$content.append($loader);
|
||||
scrollBottom();
|
||||
|
||||
$.ajax({
|
||||
url: ajaxUrl,
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
action: 'mm_assistant_query', // ← Neuer Action-Name
|
||||
q: val,
|
||||
nonce: nonce
|
||||
},
|
||||
success: function(res){
|
||||
$loader.remove();
|
||||
isLoading = false;
|
||||
|
||||
var text;
|
||||
if (res && res.success && res.data && res.data.reply) {
|
||||
// Neues Format: {reply: '...', parts: [...]}
|
||||
text = res.data.reply;
|
||||
} else if (res && res.success && typeof res.data === 'string') {
|
||||
// Altes Format: direkter String (Fallback)
|
||||
text = res.data;
|
||||
} else {
|
||||
text = '⚠️ Keine Antwort erhalten.';
|
||||
}
|
||||
|
||||
appendMsg('bot', text);
|
||||
},
|
||||
error: function(){
|
||||
$loader.remove();
|
||||
isLoading = false;
|
||||
appendMsg('bot', '⚠️ Verbindungsfehler. Bitte versuche es erneut.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function appendMsg(type, html) {
|
||||
var $msg = $('<div class="mm-msg ' + type + '">').html(html);
|
||||
$content.append($msg);
|
||||
scrollBottom();
|
||||
}
|
||||
|
||||
function scrollBottom() {
|
||||
$content.scrollTop($content[0].scrollHeight);
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ── Wrapper ── */
|
||||
#mm-bot-root {
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
}
|
||||
/* Positionsklassen */
|
||||
#mm-bot-root.mm-bot-pos-bottom_right { bottom: 30px; right: 100px; }
|
||||
#mm-bot-root.mm-bot-pos-bottom_left { bottom: 90px; left: 30px; }
|
||||
#mm-bot-root.mm-bot-pos-top_right { top: 30px; right: 30px; }
|
||||
#mm-bot-root.mm-bot-pos-top_left { top: 30px; left: 30px; }
|
||||
|
||||
/* Chat-Fenster dynamisch positionieren */
|
||||
#mm-bot-root.mm-bot-pos-bottom_right #mm-bot-chat { bottom: 78px; right: 0; left: auto; top: auto; }
|
||||
#mm-bot-root.mm-bot-pos-bottom_left #mm-bot-chat { bottom: 78px; left: 0; right: auto; top: auto; }
|
||||
#mm-bot-root.mm-bot-pos-top_right #mm-bot-chat { top: 78px; right: 0; left: auto; bottom: auto; }
|
||||
#mm-bot-root.mm-bot-pos-top_left #mm-bot-chat { top: 78px; left: 0; right: auto; bottom: auto; }
|
||||
|
||||
/* ── Launcher ── */
|
||||
#mm-bot-launcher {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
padding: 0 !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: visible;
|
||||
border-radius: 0 !important;
|
||||
cursor: pointer;
|
||||
transition: none;
|
||||
}
|
||||
#mm-bot-launcher img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 8px;
|
||||
background: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* ── Chat-Fenster ── */
|
||||
#mm-bot-chat {
|
||||
position: absolute;
|
||||
bottom: 78px;
|
||||
right: 0;
|
||||
width: 350px;
|
||||
background: #1e2124;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 16px 48px rgba(0,0,0,.55);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
border: 1px solid #2a2d31;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
.mm-bot-header {
|
||||
background: #2f3136;
|
||||
color: #fff;
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border-bottom: 1px solid #1a1a1a;
|
||||
}
|
||||
.mm-bot-status {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #43b581;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 8px #43b581;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.mm-bot-avatar-small {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.mm-bot-title {
|
||||
font-weight: 700;
|
||||
font-size: 15px;
|
||||
flex: 1;
|
||||
}
|
||||
#mm-bot-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #888;
|
||||
font-size: 22px;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
padding: 0 2px;
|
||||
transition: color .2s;
|
||||
}
|
||||
#mm-bot-close:hover { color: #fff; }
|
||||
|
||||
/* ── Nachrichten ── */
|
||||
#mm-bot-content {
|
||||
height: 340px;
|
||||
padding: 14px 14px 6px;
|
||||
overflow-y: auto;
|
||||
background: #36393f;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
.mm-msg {
|
||||
padding: 10px 14px;
|
||||
border-radius: 14px;
|
||||
font-size: 13.5px;
|
||||
line-height: 1.55;
|
||||
max-width: 90%;
|
||||
word-break: break-word;
|
||||
}
|
||||
.mm-msg.bot {
|
||||
background: #40444b;
|
||||
color: #dcddde;
|
||||
align-self: flex-start;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
.mm-msg.user {
|
||||
background: #0099ff;
|
||||
color: #fff;
|
||||
align-self: flex-end;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
.mm-msg a {
|
||||
color: #5bc0eb;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
.mm-msg a:hover { text-decoration: underline; }
|
||||
.mm-msg code {
|
||||
background: #1a1a1a;
|
||||
color: #ffa500;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 12.5px;
|
||||
}
|
||||
.mm-msg hr {
|
||||
border: 0;
|
||||
border-top: 1px solid rgba(255,255,255,.12);
|
||||
margin: 8px 0;
|
||||
}
|
||||
.mm-msg img {
|
||||
max-width: 100%;
|
||||
border-radius: 6px;
|
||||
margin-top: 6px;
|
||||
display: block;
|
||||
}
|
||||
.mm-msg small { opacity: .75; font-size: 12px; }
|
||||
.mm-msg b { color: #fff; }
|
||||
.mm-msg.bot b { color: #e3e4e6; }
|
||||
|
||||
/* TinyMCE Regelwerk-Inhalt im Chat */
|
||||
.mm-msg p { margin: 4px 0; }
|
||||
.mm-msg ul, .mm-msg ol {
|
||||
margin: 4px 0 4px 16px;
|
||||
padding: 0;
|
||||
}
|
||||
.mm-msg li { margin-bottom: 2px; list-style: disc; }
|
||||
.mm-msg ol li { list-style: decimal; }
|
||||
.mm-msg strong, .mm-msg b { font-weight: 700; }
|
||||
.mm-msg em { font-style: italic; }
|
||||
.mm-msg h1, .mm-msg h2, .mm-msg h3,
|
||||
.mm-msg h4, .mm-msg h5, .mm-msg h6 {
|
||||
margin: 6px 0 4px;
|
||||
font-size: 14px;
|
||||
color: #e3e4e6;
|
||||
}
|
||||
|
||||
.mm-loading {
|
||||
opacity: .55;
|
||||
font-size: 22px;
|
||||
letter-spacing: 5px;
|
||||
padding: 6px 14px;
|
||||
}
|
||||
|
||||
/* ── Quick-Buttons ── */
|
||||
.mm-bot-quick {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.mm-quick-btn {
|
||||
background: #2f3136;
|
||||
color: #b9bbbe;
|
||||
border: 1px solid #3f4147;
|
||||
border-radius: 20px;
|
||||
padding: 5px 12px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: background .2s, color .2s, border-color .2s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.mm-quick-btn:hover {
|
||||
background: #0099ff;
|
||||
color: #fff;
|
||||
border-color: #0099ff;
|
||||
}
|
||||
|
||||
/* ── Eingabe ── */
|
||||
.mm-bot-input-area {
|
||||
padding: 10px 12px;
|
||||
background: #2f3136;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
border-top: 1px solid #1a1a1a;
|
||||
}
|
||||
#mm-bot-field {
|
||||
flex: 1;
|
||||
background: #40444b;
|
||||
border: 1px solid #1a1a1a;
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
padding: 9px 12px;
|
||||
outline: none;
|
||||
font-size: 13.5px;
|
||||
transition: border-color .2s;
|
||||
}
|
||||
#mm-bot-field::placeholder { color: #72767d; }
|
||||
#mm-bot-field:focus { border-color: #0099ff; }
|
||||
|
||||
#mm-bot-send {
|
||||
background: #0099ff;
|
||||
border: none;
|
||||
color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 0 16px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
transition: background .2s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
#mm-bot-send:hover { background: #00b0f4; }
|
||||
|
||||
/* ── Responsive ── */
|
||||
@media (max-width: 420px) {
|
||||
#mm-bot-root { bottom: 16px; right: 12px; }
|
||||
#mm-bot-chat { width: calc(100vw - 24px); right: -12px; }
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
@@ -1,478 +1,465 @@
|
||||
<?php
|
||||
/**
|
||||
* Minecraft Modern Theme - Customizer Settings
|
||||
*
|
||||
* Enthält Einstellungen für:
|
||||
* - Header Slider & Hero
|
||||
* - Theme Presets (Nether, End, Classic)
|
||||
* - Farben & Darstellung
|
||||
* - Social Media
|
||||
* - Footer
|
||||
* - Login
|
||||
* - Sidebar
|
||||
* - Import/Export
|
||||
* FIXES:
|
||||
* - Google Font via wp_enqueue_style() statt <link> direkt in wp_head
|
||||
* - slider_loop Setting ergänzt (war in slider-init.js referenziert, aber nie definiert)
|
||||
* - Scroll-to-Top Toggle ergänzt
|
||||
* - footer_copyright Default mit aktuellem Jahr zur Laufzeit
|
||||
* - Import_Export_Control Klasse aus dem Callback extrahiert
|
||||
*/
|
||||
|
||||
// =========================================================================
|
||||
// Import/Export Control – außerhalb des Callbacks definiert
|
||||
// =========================================================================
|
||||
if ( class_exists('WP_Customize_Control') && ! class_exists('MM_Import_Export_Control') ) :
|
||||
class MM_Import_Export_Control extends WP_Customize_Control {
|
||||
public $type = 'mm_import_export';
|
||||
|
||||
public function render_content() {
|
||||
$export_url = admin_url('admin-post.php?action=export_theme_settings');
|
||||
$nonce = wp_create_nonce('theme-import-nonce');
|
||||
?>
|
||||
<div class="mm-import-export-wrapper">
|
||||
<p class="description" style="margin-bottom:16px;">
|
||||
<strong><?php _e('Hinweis:', 'minecraft-modern-theme'); ?></strong>
|
||||
<?php _e('Hier kannst du alle Theme-Einstellungen und Inhalte sichern und wiederherstellen.', 'minecraft-modern-theme'); ?>
|
||||
</p>
|
||||
|
||||
<div style="background:#e7f3ff;border:1px solid #b3d9ff;border-radius:4px;padding:12px;margin-bottom:16px;font-size:12px;line-height:1.5;">
|
||||
<strong>📦 Was wird gesichert:</strong><br>
|
||||
✓ Customizer-Einstellungen (Farben, Social Links, Menü-Design, etc.)<br>
|
||||
✓ Livestream API Keys (YouTube, Twitch)<br>
|
||||
✓ Homepage-Seite (Titel, Inhalt, Highlight-Bild)<br>
|
||||
✓ Navigation Menüs inkl. aller Items & Struktur<br>
|
||||
✓ Widget-Konfigurationen<br>
|
||||
✓ Team-Mitglieder (mit UUID, Avatar, Banner)<br>
|
||||
✓ FAQ-Einträge & Kategorien<br>
|
||||
✓ Custom CSS<br>
|
||||
✓ Announcement-Bar Einstellungen
|
||||
</div>
|
||||
|
||||
<a href="<?php echo esc_url($export_url); ?>" class="button button-primary" style="display:inline-flex;align-items:center;gap:6px;margin-bottom:20px;">
|
||||
<span class="dashicons dashicons-download"></span>
|
||||
<?php _e('Einstellungen exportieren', 'minecraft-modern-theme'); ?>
|
||||
</a>
|
||||
|
||||
<hr style="margin:16px 0;">
|
||||
|
||||
<label style="display:block;margin-bottom:8px;font-weight:600;">
|
||||
<?php _e('Backup wiederherstellen:', 'minecraft-modern-theme'); ?>
|
||||
</label>
|
||||
<input type="file" id="mm-import-file" accept=".json" style="width:100%;margin-bottom:10px;">
|
||||
<button type="button" class="button" id="mm-import-btn" disabled style="display:inline-flex;align-items:center;gap:6px;">
|
||||
<span class="dashicons dashicons-upload"></span>
|
||||
<?php _e('Einstellungen importieren', 'minecraft-modern-theme'); ?>
|
||||
</button>
|
||||
|
||||
<p class="description" style="margin-top:12px;padding:10px;background:#fff3cd;border-left:4px solid #ffc107;color:#856404;">
|
||||
⚠️ <?php _e('Beim Import werden alle aktuellen Einstellungen überschrieben!', 'minecraft-modern-theme'); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function($){
|
||||
var ajaxUrl = '<?php echo esc_js(admin_url('admin-ajax.php')); ?>';
|
||||
var nonce = '<?php echo esc_js($nonce); ?>';
|
||||
|
||||
$('#mm-import-file').on('change', function(){
|
||||
$('#mm-import-btn').prop('disabled', $(this).val() === '');
|
||||
});
|
||||
|
||||
$('#mm-import-btn').on('click', function(){
|
||||
var file = $('#mm-import-file')[0].files[0];
|
||||
if (!file) return;
|
||||
if (!confirm('<?php echo esc_js(__('Alle aktuellen Einstellungen werden überschrieben. Fortfahren?', 'minecraft-modern-theme')); ?>')) return;
|
||||
|
||||
var $btn = $(this).prop('disabled', true).text('<?php echo esc_js(__('Importiere…', 'minecraft-modern-theme')); ?>');
|
||||
var fd = new FormData();
|
||||
fd.append('import_file', file);
|
||||
fd.append('action', 'import_theme_settings');
|
||||
fd.append('nonce', nonce);
|
||||
|
||||
$.ajax({ url: ajaxUrl, type: 'POST', data: fd, processData: false, contentType: false,
|
||||
success: function(r){
|
||||
if (r.success) { alert('✅ ' + r.data); location.reload(); }
|
||||
else { alert('❌ ' + r.data); $btn.prop('disabled', false).text('<?php echo esc_js(__('Einstellungen importieren', 'minecraft-modern-theme')); ?>'); }
|
||||
},
|
||||
error: function(){ alert('<?php echo esc_js(__('Technischer Fehler.', 'minecraft-modern-theme')); ?>'); $btn.prop('disabled', false); }
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
endif;
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Customizer Register
|
||||
// =========================================================================
|
||||
function minecraft_modern_customize_register( $wp_customize ) {
|
||||
|
||||
// =========================================================================
|
||||
// === 1. HEADER-BEREICH ===================================================
|
||||
// 9. Virtueller Assistent
|
||||
// =========================================================================
|
||||
|
||||
// --- Sektion: Header Slider ---
|
||||
$wp_customize->add_section( 'header_slider', array(
|
||||
'title' => 'Header Slider',
|
||||
'priority' => 20,
|
||||
'description' => 'Konfiguriere den großen Slider auf der Startseite.',
|
||||
// BUG-FIX: add_section() muss VOR add_setting()/add_control() stehen.
|
||||
// Vorher war add_setting/add_control für 'assistant_avatar_view' aufgerufen
|
||||
// bevor die Section 'assistant_settings' überhaupt registriert war.
|
||||
$wp_customize->add_section( 'assistant_settings', array(
|
||||
'title' => __( 'Virtueller Assistent', 'minecraft-modern-theme' ),
|
||||
'priority' => 80,
|
||||
'description' => __( 'Steuert den virtuellen Assistenten im Frontend. Avatar basiert auf Minecraft-UUID.', 'minecraft-modern-theme' ),
|
||||
) );
|
||||
|
||||
// Checkbox zum Aktivieren des Sliders
|
||||
$wp_customize->add_setting( 'slider_enabled', array(
|
||||
$wp_customize->add_setting( 'assistant_enabled', array(
|
||||
'default' => false,
|
||||
'transport' => 'refresh',
|
||||
'sanitize_callback' => 'wp_validate_boolean',
|
||||
) );
|
||||
$wp_customize->add_control( 'slider_enabled', array(
|
||||
'label' => 'Header Slider aktivieren',
|
||||
$wp_customize->add_control( 'assistant_enabled', array(
|
||||
'label' => __( 'Virtuellen Assistenten aktivieren', 'minecraft-modern-theme' ),
|
||||
'section' => 'assistant_settings',
|
||||
'type' => 'checkbox',
|
||||
) );
|
||||
|
||||
$wp_customize->add_setting( 'assistant_minecraft_uuid', array(
|
||||
'default' => '',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
) );
|
||||
$wp_customize->add_control( 'assistant_minecraft_uuid', array(
|
||||
'label' => __( 'Minecraft UUID für Avatar', 'minecraft-modern-theme' ),
|
||||
'section' => 'assistant_settings',
|
||||
'type' => 'text',
|
||||
'description' => __( 'Gib die Minecraft-UUID für den Avatar des Assistenten ein.', 'minecraft-modern-theme' ),
|
||||
) );
|
||||
|
||||
$wp_customize->add_setting( 'assistant_avatar_view', array(
|
||||
'default' => 'head',
|
||||
'sanitize_callback' => function ( $v ) {
|
||||
return in_array( $v, array( 'head', 'body', '3dhead' ), true ) ? $v : 'head';
|
||||
},
|
||||
) );
|
||||
$wp_customize->add_control( 'assistant_avatar_view', array(
|
||||
'label' => __( 'Avatar-Ansicht', 'minecraft-modern-theme' ),
|
||||
'section' => 'assistant_settings',
|
||||
'type' => 'select',
|
||||
'choices' => array(
|
||||
'head' => __( 'Kopf', 'minecraft-modern-theme' ),
|
||||
'body' => __( 'Ganzkörper', 'minecraft-modern-theme' ),
|
||||
'3dhead' => __( '3D Kopf', 'minecraft-modern-theme' ),
|
||||
),
|
||||
'description' => __( 'Wähle, wie der Minecraft-Avatar im Assistenten angezeigt wird.', 'minecraft-modern-theme' ),
|
||||
) );
|
||||
|
||||
// BUG-FIX: assistant_position war in assistant-widget.php in einem eigenen
|
||||
// customize_register-Hook registriert – also BEVOR diese Section existierte.
|
||||
// Jetzt korrekt hier innerhalb von minecraft_modern_customize_register().
|
||||
$wp_customize->add_setting( 'assistant_position', array(
|
||||
'default' => 'bottom_right',
|
||||
'transport' => 'refresh',
|
||||
'sanitize_callback' => function ( $v ) {
|
||||
$allowed = array( 'bottom_right', 'bottom_left', 'top_right', 'top_left' );
|
||||
return in_array( $v, $allowed, true ) ? $v : 'bottom_right';
|
||||
},
|
||||
) );
|
||||
$wp_customize->add_control( 'assistant_position', array(
|
||||
'label' => __( 'Position des Assistenten', 'minecraft-modern-theme' ),
|
||||
'section' => 'assistant_settings',
|
||||
'type' => 'select',
|
||||
'choices' => array(
|
||||
'bottom_right' => __( 'Unten rechts', 'minecraft-modern-theme' ),
|
||||
'bottom_left' => __( 'Unten links', 'minecraft-modern-theme' ),
|
||||
'top_right' => __( 'Oben rechts', 'minecraft-modern-theme' ),
|
||||
'top_left' => __( 'Oben links', 'minecraft-modern-theme' ),
|
||||
),
|
||||
) );
|
||||
|
||||
// =========================================================================
|
||||
// 1. HEADER SLIDER
|
||||
// =========================================================================
|
||||
$wp_customize->add_section( 'header_slider', array(
|
||||
'title' => __('Header Slider', 'minecraft-modern-theme'),
|
||||
'priority' => 20,
|
||||
'description' => __('Konfiguriere den großen Slider auf der Startseite.', 'minecraft-modern-theme'),
|
||||
) );
|
||||
|
||||
$wp_customize->add_setting( 'slider_enabled', array( 'default' => false, 'transport' => 'refresh', 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'slider_enabled', array( 'label' => __('Header Slider aktivieren', 'minecraft-modern-theme'), 'section' => 'header_slider', 'type' => 'checkbox' ) );
|
||||
|
||||
// FIX: slider_loop war in slider-init.js als sliderSettings.loop referenziert, aber nie definiert
|
||||
$wp_customize->add_setting( 'slider_loop', array( 'default' => true, 'transport' => 'refresh', 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'slider_loop', array(
|
||||
'label' => __('Slider Endlos-Loop aktivieren', 'minecraft-modern-theme'),
|
||||
'description' => __('Der Slider springt nach dem letzten Slide wieder zum ersten zurück.', 'minecraft-modern-theme'),
|
||||
'section' => 'header_slider',
|
||||
'settings' => 'slider_enabled',
|
||||
'type' => 'checkbox',
|
||||
) );
|
||||
|
||||
// Dynamische Slider-Bilder, Titel und Untertitel
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
for ( $i = 1; $i <= 5; $i++ ) {
|
||||
$wp_customize->add_setting( 'slider_image_' . $i, array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, 'slider_image_' . $i, array(
|
||||
'label' => sprintf( 'Banner %d - Bild', $i ),
|
||||
'section' => 'header_slider',
|
||||
'settings' => 'slider_image_' . $i,
|
||||
'label' => sprintf( __('Banner %d - Bild', 'minecraft-modern-theme'), $i ), 'section' => 'header_slider',
|
||||
) ) );
|
||||
|
||||
$wp_customize->add_setting( 'slider_title_' . $i, array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'slider_title_' . $i, array(
|
||||
'label' => sprintf( 'Banner %d - Titel', $i ),
|
||||
'section' => 'header_slider',
|
||||
'settings' => 'slider_title_' . $i,
|
||||
'type' => 'text',
|
||||
) );
|
||||
|
||||
$wp_customize->add_control( 'slider_title_' . $i, array( 'label' => sprintf( __('Banner %d - Titel', 'minecraft-modern-theme'), $i ), 'section' => 'header_slider', 'type' => 'text' ) );
|
||||
$wp_customize->add_setting( 'slider_subtitle_' . $i, array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'slider_subtitle_' . $i, array(
|
||||
'label' => sprintf( 'Banner %d - Untertitel', $i ),
|
||||
'section' => 'header_slider',
|
||||
'settings' => 'slider_subtitle_' . $i,
|
||||
'type' => 'text',
|
||||
) );
|
||||
$wp_customize->add_control( 'slider_subtitle_' . $i, array( 'label' => sprintf( __('Banner %d - Untertitel', 'minecraft-modern-theme'), $i ), 'section' => 'header_slider', 'type' => 'text' ) );
|
||||
}
|
||||
|
||||
// Slider Text- & Stil-Einstellungen
|
||||
$wp_customize->add_setting( 'slider_font_family', array( 'default' => 'Raleway', 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'slider_font_family', array(
|
||||
'label' => 'Schriftart', 'section' => 'header_slider', 'settings' => 'slider_font_family', 'type' => 'select',
|
||||
'choices' => array( 'Raleway' => 'Raleway', 'Poppins' => 'Poppins', 'Montserrat' => 'Montserrat', 'Oswald' => 'Oswald', 'Roboto' => 'Roboto', 'Lato' => 'Lato' ),
|
||||
'label' => __('Schriftart', 'minecraft-modern-theme'), 'section' => 'header_slider', 'type' => 'select',
|
||||
'choices' => array( 'Raleway' => 'Raleway', 'Poppins' => 'Poppins', 'Montserrat' => 'Montserrat', 'Oswald' => 'Oswald', 'Roboto' => 'Roboto', 'Lato' => 'Lato' ),
|
||||
) );
|
||||
|
||||
$wp_customize->add_setting( 'slider_font_size', array( 'default' => 'mittel', 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'slider_font_size', array(
|
||||
'label' => 'Schriftgröße', 'section' => 'header_slider', 'settings' => 'slider_font_size', 'type' => 'select',
|
||||
'choices' => array( 'klein' => 'Klein', 'mittel' => 'Mittel', 'gross' => 'Groß', 'extra-gross' => 'Extra Groß' ),
|
||||
'label' => __('Schriftgröße', 'minecraft-modern-theme'), 'section' => 'header_slider', 'type' => 'select',
|
||||
'choices' => array( 'klein' => __('Klein', 'minecraft-modern-theme'), 'mittel' => __('Mittel', 'minecraft-modern-theme'), 'gross' => __('Groß', 'minecraft-modern-theme'), 'extra-gross' => __('Extra Groß', 'minecraft-modern-theme') ),
|
||||
) );
|
||||
|
||||
$wp_customize->add_setting( 'slider_font_color', array( 'default' => '#ffffff', 'sanitize_callback' => 'sanitize_hex_color' ) );
|
||||
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'slider_font_color', array(
|
||||
'label' => 'Schriftfarbe', 'section' => 'header_slider', 'settings' => 'slider_font_color',
|
||||
'label' => __('Schriftfarbe', 'minecraft-modern-theme'), 'section' => 'header_slider',
|
||||
) ) );
|
||||
|
||||
// Header-Höhe
|
||||
|
||||
$wp_customize->add_setting( 'header_height', array( 'default' => 'mittel', 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'header_height', array(
|
||||
'label' => 'Header-Höhe', 'section' => 'header_slider', 'settings' => 'header_height', 'type' => 'select',
|
||||
'choices' => array( 'klein' => 'Klein', 'mittel' => 'Mittel', 'gross' => 'Groß' ),
|
||||
'label' => __('Header-Höhe', 'minecraft-modern-theme'), 'section' => 'header_slider', 'type' => 'select',
|
||||
'choices' => array( 'klein' => __('Klein', 'minecraft-modern-theme'), 'mittel' => __('Mittel', 'minecraft-modern-theme'), 'gross' => __('Groß', 'minecraft-modern-theme') ),
|
||||
) );
|
||||
|
||||
$wp_customize->add_setting( 'slider_hide_arrows', array( 'default' => false, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'slider_hide_arrows', array(
|
||||
'label' => 'Pfeile ausblenden', 'section' => 'header_slider', 'settings' => 'slider_hide_arrows', 'type' => 'checkbox',
|
||||
) );
|
||||
$wp_customize->add_control( 'slider_hide_arrows', array( 'label' => __('Pfeile ausblenden', 'minecraft-modern-theme'), 'section' => 'header_slider', 'type' => 'checkbox' ) );
|
||||
|
||||
$wp_customize->add_setting( 'slider_hide_pagination', array( 'default' => false, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'slider_hide_pagination', array(
|
||||
'label' => 'Paginierung (Punkte) ausblenden', 'section' => 'header_slider', 'settings' => 'slider_hide_pagination', 'type' => 'checkbox',
|
||||
) );
|
||||
$wp_customize->add_control( 'slider_hide_pagination', array( 'label' => __('Paginierung (Punkte) ausblenden', 'minecraft-modern-theme'), 'section' => 'header_slider', 'type' => 'checkbox' ) );
|
||||
|
||||
// --- Sektion: Startseiten-Hero (Fallback) ---
|
||||
|
||||
// =========================================================================
|
||||
// 2. HERO SECTION (Fallback)
|
||||
// =========================================================================
|
||||
$wp_customize->add_section( 'hero_section', array(
|
||||
'title' => 'Startseiten-Hero (wenn Slider deaktiviert)',
|
||||
'priority' => 21,
|
||||
'description' => 'Diese Inhalte werden angezeigt, wenn der Slider ausgeschaltet ist.',
|
||||
'title' => __('Startseiten-Hero (wenn Slider deaktiviert)', 'minecraft-modern-theme'),
|
||||
'priority' => 21,
|
||||
) );
|
||||
$wp_customize->add_setting( 'hero_title', array( 'default' => 'Willkommen auf unserem Server', 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'hero_title', array( 'label' => 'Haupttitel', 'section' => 'hero_section', 'settings' => 'hero_title', 'type' => 'text' ) );
|
||||
$wp_customize->add_setting( 'hero_subtitle', array( 'default' => 'Trete einer Community voller Abenteuer bei.', 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'hero_subtitle', array( 'label' => 'Untertitel', 'section' => 'hero_section', 'settings' => 'hero_subtitle', 'type' => 'text' ) );
|
||||
|
||||
$wp_customize->add_setting( 'hero_title', array( 'default' => __('Willkommen auf unserem Server', 'minecraft-modern-theme'), 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'hero_title', array( 'label' => __('Haupttitel', 'minecraft-modern-theme'), 'section' => 'hero_section', 'type' => 'text' ) );
|
||||
$wp_customize->add_setting( 'hero_subtitle', array( 'default' => __('Trete einer Community voller Abenteuer bei.', 'minecraft-modern-theme'), 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'hero_subtitle', array( 'label' => __('Untertitel', 'minecraft-modern-theme'), 'section' => 'hero_section', 'type' => 'text' ) );
|
||||
$wp_customize->add_setting( 'hero_bg_image', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, 'hero_bg_image', array(
|
||||
'label' => 'Hintergrundbild', 'section' => 'hero_section', 'settings' => 'hero_bg_image',
|
||||
) ) );
|
||||
$wp_customize->add_setting( 'hero_button_1_text', array( 'default' => 'Zum Forum', 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'hero_button_1_text', array( 'label' => 'Button 1 Text', 'section' => 'hero_section', 'settings' => 'hero_button_1_text', 'type' => 'text' ) );
|
||||
$wp_customize->add_setting( 'hero_button_1_url', array( 'default' => '#', 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( 'hero_button_1_url', array( 'label' => 'Button 1 URL', 'section' => 'hero_section', 'settings' => 'hero_button_1_url', 'type' => 'url' ) );
|
||||
$wp_customize->add_setting( 'hero_button_2_text', array( 'default' => 'Zum Teamspeak', 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'hero_button_2_text', array( 'label' => 'Button 2 Text', 'section' => 'hero_section', 'settings' => 'hero_button_2_text', 'type' => 'text' ) );
|
||||
$wp_customize->add_setting( 'hero_button_2_url', array( 'default' => '#', 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( 'hero_button_2_url', array( 'label' => 'Button 2 URL', 'section' => 'hero_section', 'settings' => 'hero_button_2_url', 'type' => 'url' ) );
|
||||
|
||||
// --- Checkbox: Seitentitel auf Startseite verstecken ---
|
||||
$wp_customize->add_setting( 'show_home_title', array(
|
||||
'default' => false,
|
||||
'sanitize_callback' => 'wp_validate_boolean',
|
||||
) );
|
||||
$wp_customize->add_control( 'show_home_title', array(
|
||||
'label' => 'Seitentitel "Home" anzeigen',
|
||||
'description' => 'Aktiviere diese Option, wenn der Titel "Home" über dem Slider/Inhalt angezeigt werden soll.',
|
||||
'section' => 'hero_section',
|
||||
'settings' => 'show_home_title',
|
||||
'type' => 'checkbox',
|
||||
) );
|
||||
$wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, 'hero_bg_image', array( 'label' => __('Hintergrundbild', 'minecraft-modern-theme'), 'section' => 'hero_section' ) ) );
|
||||
$wp_customize->add_setting( 'hero_button_1_text', array( 'default' => __('Zum Forum', 'minecraft-modern-theme'), 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'hero_button_1_text', array( 'label' => __('Button 1 Text', 'minecraft-modern-theme'), 'section' => 'hero_section', 'type' => 'text' ) );
|
||||
$wp_customize->add_setting( 'hero_button_1_url', array( 'default' => '#', 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( 'hero_button_1_url', array( 'label' => __('Button 1 URL', 'minecraft-modern-theme'), 'section' => 'hero_section', 'type' => 'url' ) );
|
||||
$wp_customize->add_setting( 'hero_button_2_text', array( 'default' => __('Zum Teamspeak', 'minecraft-modern-theme'), 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( 'hero_button_2_text', array( 'label' => __('Button 2 Text', 'minecraft-modern-theme'), 'section' => 'hero_section', 'type' => 'text' ) );
|
||||
$wp_customize->add_setting( 'hero_button_2_url', array( 'default' => '#', 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( 'hero_button_2_url', array( 'label' => __('Button 2 URL', 'minecraft-modern-theme'), 'section' => 'hero_section', 'type' => 'url' ) );
|
||||
$wp_customize->add_setting( 'show_home_title', array( 'default' => false, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'show_home_title', array( 'label' => __('Seitentitel "Home" anzeigen', 'minecraft-modern-theme'), 'section' => 'hero_section', 'type' => 'checkbox' ) );
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// === 2. FARBEN & DARSTELLUNG (KOMBINIERT) ================================
|
||||
// 3. FARBEN & DARSTELLUNG
|
||||
// =========================================================================
|
||||
|
||||
// --- Sektion: Farben & Darstellung ---
|
||||
$wp_customize->add_section( 'theme_appearance_settings', array(
|
||||
'title' => 'Farben & Darstellung',
|
||||
'priority' => 30,
|
||||
) );
|
||||
|
||||
// =========================================================================
|
||||
// === NEU: THEME PRESETS (VOREINSTELLUNGEN) ==============================
|
||||
// =========================================================================
|
||||
|
||||
$wp_customize->add_setting( 'theme_color_preset', array(
|
||||
'default' => 'classic',
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
'transport' => 'refresh',
|
||||
'title' => __('Farben & Darstellung', 'minecraft-modern-theme'), 'priority' => 30,
|
||||
) );
|
||||
|
||||
$wp_customize->add_setting( 'theme_color_preset', array( 'default' => 'classic', 'sanitize_callback' => 'sanitize_key', 'transport' => 'refresh' ) );
|
||||
$wp_customize->add_control( 'theme_color_preset', array(
|
||||
'label' => 'Theme Preset (Farbschema)',
|
||||
'description' => 'Wähle ein voreingestelltes Farbschema (z. B. für Nether oder End Dimension).',
|
||||
'section' => 'theme_appearance_settings',
|
||||
'settings' => 'theme_color_preset',
|
||||
'type' => 'select',
|
||||
'priority' => 1, // Zeig es ganz oben in dieser Sektion an
|
||||
'choices' => array(
|
||||
'classic' => 'Classic Minecraft (Diamant-Blau)',
|
||||
'nether' => 'Nether (Lava-Rot)',
|
||||
'end' => 'The End (Ender-Purpur)',
|
||||
'label' => __('Theme Preset (Farbschema)', 'minecraft-modern-theme'),
|
||||
'section' => 'theme_appearance_settings',
|
||||
'type' => 'select',
|
||||
'priority' => 1,
|
||||
'choices' => array(
|
||||
'classic' => __('Classic Minecraft (Diamant-Blau)', 'minecraft-modern-theme'),
|
||||
'nether' => __('Nether (Lava-Rot)', 'minecraft-modern-theme'),
|
||||
'end' => __('The End (Ender-Purpur)', 'minecraft-modern-theme'),
|
||||
),
|
||||
) );
|
||||
|
||||
// =========================================================================
|
||||
// === ENDE THEME PRESETS ==================================================
|
||||
// =========================================================================
|
||||
|
||||
// Akzentfarbe
|
||||
$wp_customize->add_setting( 'primary_accent_color', array( 'default' => '#00d4ff', 'sanitize_callback' => 'sanitize_hex_color', 'transport' => 'refresh' ) );
|
||||
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'primary_accent_color', array(
|
||||
'label' => 'Akzentfarbe', 'section' => 'theme_appearance_settings', 'settings' => 'primary_accent_color',
|
||||
) ) );
|
||||
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'primary_accent_color', array( 'label' => __('Akzentfarbe', 'minecraft-modern-theme'), 'section' => 'theme_appearance_settings' ) ) );
|
||||
|
||||
// Hintergrundfarbe
|
||||
$wp_customize->add_setting( 'background_color', array(
|
||||
'default' => '#ffffff',
|
||||
'sanitize_callback' => 'sanitize_hex_color',
|
||||
'transport' => 'refresh',
|
||||
) );
|
||||
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'background_color', array(
|
||||
'label' => 'Hintergrundfarbe',
|
||||
'section' => 'theme_appearance_settings',
|
||||
'settings' => 'background_color',
|
||||
) ) );
|
||||
|
||||
// Dark / Light Mode
|
||||
$wp_customize->add_setting( 'default_theme_mode', array( 'default' => 'dark', 'sanitize_callback' => 'sanitize_key' ) );
|
||||
$wp_customize->add_control( 'default_theme_mode', array(
|
||||
'label' => 'Standard-Theme-Modus', 'section' => 'theme_appearance_settings', 'type' => 'radio',
|
||||
'choices' => array( 'dark' => 'Dark Mode (Standard)', 'light' => 'Light Mode' ),
|
||||
'label' => __('Standard-Theme-Modus', 'minecraft-modern-theme'),
|
||||
'section' => 'theme_appearance_settings',
|
||||
'type' => 'radio',
|
||||
'choices' => array( 'dark' => __('Dark Mode', 'minecraft-modern-theme'), 'light' => __('Light Mode', 'minecraft-modern-theme') ),
|
||||
) );
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// === 3. SIDEBAR EINSTELLUNGEN ============================================
|
||||
// =========================================================================
|
||||
|
||||
$wp_customize->add_section( 'sidebar_settings', array(
|
||||
'title' => 'Sidebar Einstellungen',
|
||||
'priority' => 35,
|
||||
'description' => 'Konfiguriere die Sidebar auf der Startseite.',
|
||||
) );
|
||||
|
||||
// Sidebar aktivieren
|
||||
$wp_customize->add_setting( 'homepage_sidebar_enabled', array(
|
||||
'default' => false,
|
||||
'sanitize_callback' => 'wp_validate_boolean',
|
||||
) );
|
||||
$wp_customize->add_control( 'homepage_sidebar_enabled', array(
|
||||
'label' => 'Sidebar auf Startseite aktivieren',
|
||||
'description' => 'Zeigt eine Sidebar neben dem Hauptinhalt an.',
|
||||
'section' => 'sidebar_settings',
|
||||
'settings' => 'homepage_sidebar_enabled',
|
||||
// FIX: Scroll-to-Top war nie im Customizer steuerbar
|
||||
$wp_customize->add_setting( 'show_scroll_to_top', array( 'default' => true, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'show_scroll_to_top', array(
|
||||
'label' => __('Scroll-to-Top Button anzeigen', 'minecraft-modern-theme'),
|
||||
'description' => __('Zeigt einen Button unten rechts zum Hochscrollen an.', 'minecraft-modern-theme'),
|
||||
'section' => 'theme_appearance_settings',
|
||||
'type' => 'checkbox',
|
||||
) );
|
||||
|
||||
// Sidebar Position
|
||||
$wp_customize->add_setting( 'homepage_sidebar_position', array(
|
||||
'default' => 'right',
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
) );
|
||||
|
||||
// =========================================================================
|
||||
// 4. SIDEBAR
|
||||
// =========================================================================
|
||||
$wp_customize->add_section( 'sidebar_settings', array( 'title' => __('Sidebar Einstellungen', 'minecraft-modern-theme'), 'priority' => 35 ) );
|
||||
$wp_customize->add_setting( 'homepage_sidebar_enabled', array( 'default' => false, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'homepage_sidebar_enabled', array( 'label' => __('Sidebar auf Startseite aktivieren', 'minecraft-modern-theme'), 'section' => 'sidebar_settings', 'type' => 'checkbox' ) );
|
||||
$wp_customize->add_setting( 'homepage_sidebar_position', array( 'default' => 'right', 'sanitize_callback' => 'sanitize_key' ) );
|
||||
$wp_customize->add_control( 'homepage_sidebar_position', array(
|
||||
'label' => 'Sidebar Position',
|
||||
'section' => 'sidebar_settings',
|
||||
'settings' => 'homepage_sidebar_position',
|
||||
'type' => 'select',
|
||||
'choices' => array(
|
||||
'left' => 'Links',
|
||||
'right' => 'Rechts',
|
||||
),
|
||||
'label' => __('Sidebar Position', 'minecraft-modern-theme'), 'section' => 'sidebar_settings', 'type' => 'select',
|
||||
'choices' => array( 'left' => __('Links', 'minecraft-modern-theme'), 'right' => __('Rechts', 'minecraft-modern-theme') ),
|
||||
) );
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// === 4. SOCIAL MEDIA =====================================================
|
||||
// 5. SOCIAL MEDIA
|
||||
// =========================================================================
|
||||
|
||||
$wp_customize->add_section( 'social_links', array( 'title' => 'Social Media Links', 'priority' => 40 ) );
|
||||
$social_platforms = array( 'discord' => 'Discord', 'youtube' => 'YouTube', 'twitter' => 'Twitter (X)', 'facebook' => 'Facebook', 'instagram' => 'Instagram', 'tiktok' => 'TikTok', 'twitch' => 'Twitch', 'steam' => 'Steam', 'github' => 'GitHub', 'linkedin' => 'LinkedIn', 'pinterest' => 'Pinterest', 'reddit' => 'Reddit', 'teamspeak' => 'Teamspeak', 'spotify' => 'Spotify' );
|
||||
foreach ($social_platforms as $key => $label) {
|
||||
$wp_customize->add_section( 'social_links', array( 'title' => __('Social Media Links', 'minecraft-modern-theme'), 'priority' => 40 ) );
|
||||
$social_platforms = array(
|
||||
'bluesky' => 'BlueSky', 'discord' => 'Discord', 'youtube' => 'YouTube', 'twitter' => 'Twitter (X)',
|
||||
'facebook' => 'Facebook', 'instagram' => 'Instagram', 'tiktok' => 'TikTok',
|
||||
'twitch' => 'Twitch', 'steam' => 'Steam', 'github' => 'GitHub',
|
||||
'linkedin' => 'LinkedIn', 'pinterest' => 'Pinterest', 'reddit' => 'Reddit',
|
||||
'mastodon' => 'Mastodon', 'threads' => 'Threads', 'kickstarter' => 'Kickstarter',
|
||||
'teamspeak' => 'Teamspeak', 'spotify' => 'Spotify', 'stoat' => 'Stoat',
|
||||
);
|
||||
foreach ( $social_platforms as $key => $label ) {
|
||||
$wp_customize->add_setting( 'social_' . $key, array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( 'social_' . $key, array(
|
||||
'label' => $label . ' URL', 'section' => 'social_links', 'settings' => 'social_' . $key, 'type' => 'url',
|
||||
) );
|
||||
$wp_customize->add_control( 'social_' . $key, array( 'label' => $label . ' URL', 'section' => 'social_links', 'type' => 'url' ) );
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// === 5. FOOTER-BEREICH ==================================================
|
||||
// 6. FOOTER
|
||||
// =========================================================================
|
||||
$wp_customize->add_section( 'footer_settings', array( 'title' => __('Footer-Einstellungen', 'minecraft-modern-theme'), 'priority' => 50 ) );
|
||||
|
||||
$wp_customize->add_section( 'footer_settings', array( 'title' => 'Footer-Einstellungen', 'priority' => 50 ) );
|
||||
|
||||
// Copyright-Text
|
||||
$wp_customize->add_setting( 'footer_copyright', array( 'default' => '© ' . date('Y') . ' ' . get_bloginfo('name'), 'sanitize_callback' => 'wp_kses_post' ) );
|
||||
// FIX: Default mit aktuellem Jahr zur Laufzeit auswerten, nicht bei class-load
|
||||
$wp_customize->add_setting( 'footer_copyright', array(
|
||||
'default' => '', // Leer = dynamisch berechnet in footer.php
|
||||
'sanitize_callback' => 'wp_kses_post',
|
||||
) );
|
||||
$wp_customize->add_control( 'footer_copyright', array(
|
||||
'label' => 'Copyright-Text', 'section' => 'footer_settings', 'settings' => 'footer_copyright', 'type' => 'textarea',
|
||||
'label' => __('Copyright-Text', 'minecraft-modern-theme'),
|
||||
'description' => __('Leer lassen für automatischen Text mit aktuellem Jahr.', 'minecraft-modern-theme'),
|
||||
'section' => 'footer_settings',
|
||||
'type' => 'textarea',
|
||||
) );
|
||||
|
||||
// Impressum & Datenschutz Links
|
||||
$wp_customize->add_setting( 'footer_impressum_url', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( 'footer_impressum_url', array(
|
||||
'label' => 'URL für Impressum', 'section' => 'footer_settings', 'settings' => 'footer_impressum_url', 'type' => 'url',
|
||||
) );
|
||||
$wp_customize->add_setting( 'footer_impressum_url', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( 'footer_impressum_url', array( 'label' => __('URL für Impressum', 'minecraft-modern-theme'), 'section' => 'footer_settings', 'type' => 'url' ) );
|
||||
$wp_customize->add_setting( 'footer_datenschutz_url', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
$wp_customize->add_control( 'footer_datenschutz_url', array(
|
||||
'label' => 'URL für Datenschutz', 'section' => 'footer_settings', 'settings' => 'footer_datenschutz_url', 'type' => 'url',
|
||||
) );
|
||||
|
||||
// Footer-Credit
|
||||
$wp_customize->add_control( 'footer_datenschutz_url', array( 'label' => __('URL für Datenschutz', 'minecraft-modern-theme'), 'section' => 'footer_settings', 'type' => 'url' ) );
|
||||
$wp_customize->add_setting( 'show_footer_credit', array( 'default' => true, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'show_footer_credit', array(
|
||||
'label' => 'Footer-Credit ("Minecraft Theme Erstellt von...") anzeigen', 'section' => 'footer_settings', 'settings' => 'show_footer_credit', 'type' => 'checkbox',
|
||||
) );
|
||||
$wp_customize->add_control( 'show_footer_credit', array( 'label' => __('Footer-Credit anzeigen', 'minecraft-modern-theme'), 'section' => 'footer_settings', 'type' => 'checkbox' ) );
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// === 6. ZUSÄTZLICHE FUNKTIONEN ==========================================
|
||||
// 7. FAQ & TEAM
|
||||
// =========================================================================
|
||||
$wp_customize->add_section( 'faq_settings', array( 'title' => __('FAQ Einstellungen', 'minecraft-modern-theme'), 'priority' => 60 ) );
|
||||
$wp_customize->add_setting( 'faq_enabled', array( 'default' => true, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'faq_enabled', array( 'label' => __('FAQ System aktivieren', 'minecraft-modern-theme'), 'section' => 'faq_settings', 'type' => 'checkbox' ) );
|
||||
|
||||
// --- Sektion: FAQ Einstellungen ---
|
||||
$wp_customize->add_section( 'faq_settings', array( 'title' => 'FAQ Einstellungen', 'priority' => 60 ) );
|
||||
$wp_customize->add_setting( 'faq_enabled', array( 'default' => true, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'faq_enabled', array(
|
||||
'label' => 'FAQ System aktivieren', 'section' => 'faq_settings', 'settings' => 'faq_enabled', 'type' => 'checkbox',
|
||||
) );
|
||||
$wp_customize->add_section( 'team_settings', array( 'title' => __('Team Einstellungen', 'minecraft-modern-theme'), 'priority' => 65 ) );
|
||||
$wp_customize->add_setting( 'team_enabled', array( 'default' => true, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'team_enabled', array( 'label' => __('Team Showcase aktivieren', 'minecraft-modern-theme'), 'section' => 'team_settings', 'type' => 'checkbox' ) );
|
||||
|
||||
// --- Sektion: Team Einstellungen ---
|
||||
$wp_customize->add_section( 'team_settings', array( 'title' => 'Team Einstellungen', 'priority' => 65 ) );
|
||||
$wp_customize->add_setting( 'team_enabled', array( 'default' => true, 'sanitize_callback' => 'wp_validate_boolean' ) );
|
||||
$wp_customize->add_control( 'team_enabled', array(
|
||||
'label' => 'Team Showcase aktivieren', 'section' => 'team_settings', 'settings' => 'team_enabled', 'type' => 'checkbox',
|
||||
) );
|
||||
|
||||
// =========================================================================
|
||||
// === 7. LOGIN-BEREICH ====================================================
|
||||
// 8. LOGIN
|
||||
// =========================================================================
|
||||
$wp_customize->add_section( 'login_settings', array( 'title' => __('Login-Einstellungen', 'minecraft-modern-theme'), 'priority' => 70 ) );
|
||||
$wp_customize->add_setting( 'login_background_image', array( 'sanitize_callback' => 'esc_url_raw', 'transport' => 'refresh' ) );
|
||||
$wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, 'login_background_image', array( 'label' => __('Login-Hintergrundbild', 'minecraft-modern-theme'), 'section' => 'login_settings' ) ) );
|
||||
$wp_customize->add_setting( 'login_logo', array( 'sanitize_callback' => 'esc_url_raw', 'transport' => 'refresh' ) );
|
||||
$wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, 'login_logo', array( 'label' => __('Login-Logo', 'minecraft-modern-theme'), 'section' => 'login_settings' ) ) );
|
||||
|
||||
$wp_customize->add_section( 'login_settings', array(
|
||||
'title' => 'Login-Einstellungen',
|
||||
'priority' => 70,
|
||||
'description' => 'Passe das Aussehen der wp-admin Login-Seite an.',
|
||||
) );
|
||||
|
||||
// Login-Hintergrundbild
|
||||
$wp_customize->add_setting( 'login_background_image', array(
|
||||
'sanitize_callback' => 'esc_url_raw',
|
||||
'transport' => 'refresh',
|
||||
) );
|
||||
$wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, 'login_background_image', array(
|
||||
'label' => 'Login-Hintergrundbild',
|
||||
'section' => 'login_settings',
|
||||
'settings' => 'login_background_image',
|
||||
) ) );
|
||||
|
||||
// Login-Logo
|
||||
$wp_customize->add_setting( 'login_logo', array(
|
||||
'sanitize_callback' => 'esc_url_raw',
|
||||
'transport' => 'refresh',
|
||||
) );
|
||||
$wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, 'login_logo', array(
|
||||
'label' => 'Login-Logo (ersetzt das WordPress-Logo)',
|
||||
'section' => 'login_settings',
|
||||
'settings' => 'login_logo',
|
||||
) ) );
|
||||
|
||||
// Multi-Avatar UUIDs
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$wp_customize->add_setting( 'login_avatar_uuid_' . $i, array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'transport' => 'refresh',
|
||||
) );
|
||||
for ( $i = 1; $i <= 5; $i++ ) {
|
||||
$wp_customize->add_setting( 'login_avatar_uuid_' . $i, array( 'sanitize_callback' => 'sanitize_text_field', 'transport' => 'refresh' ) );
|
||||
$wp_customize->add_control( 'login_avatar_uuid_' . $i, array(
|
||||
'label' => sprintf( 'Avatar %d UUID', $i ),
|
||||
'description' => sprintf( 'Gib die UUID für den %d. Avatar an. (Leer lassen, um zu deaktivieren)', $i ),
|
||||
'section' => 'login_settings',
|
||||
'settings' => 'login_avatar_uuid_' . $i,
|
||||
'type' => 'text',
|
||||
'label' => sprintf( __('Avatar %d UUID', 'minecraft-modern-theme'), $i ),
|
||||
'section' => 'login_settings',
|
||||
'type' => 'text',
|
||||
) );
|
||||
}
|
||||
|
||||
// Slider-Geschwindigkeit
|
||||
$wp_customize->add_setting( 'login_avatar_slider_speed', array(
|
||||
'default' => 4,
|
||||
'sanitize_callback' => 'absint',
|
||||
'transport' => 'refresh',
|
||||
) );
|
||||
$wp_customize->add_setting( 'login_avatar_slider_speed', array( 'default' => 4, 'sanitize_callback' => 'absint', 'transport' => 'refresh' ) );
|
||||
$wp_customize->add_control( 'login_avatar_slider_speed', array(
|
||||
'label' => 'Avatar-Wechsel (in Sekunden)',
|
||||
'description' => 'Wie viele Sekunden soll ein Avatar angezeigt werden?',
|
||||
'label' => __('Avatar-Wechsel (Sekunden)', 'minecraft-modern-theme'),
|
||||
'section' => 'login_settings',
|
||||
'settings' => 'login_avatar_slider_speed',
|
||||
'type' => 'number',
|
||||
'input_attrs' => array( 'min' => 2, 'max' => 10, 'step' => 1 ),
|
||||
) );
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// === 8. EXPORT / IMPORT SECTION =========================================
|
||||
// 8.5. VIDEO / LIVESTREAM EINSTELLUNGEN
|
||||
// =========================================================================
|
||||
|
||||
$wp_customize->add_section( 'theme_mods_import_export', array(
|
||||
'title' => __( 'Einstellungen sichern', 'minecraft-modern-theme' ),
|
||||
'priority' => 999,
|
||||
'description' => '',
|
||||
$wp_customize->add_section( 'video_livestream_settings', array(
|
||||
'title' => __('Video & Livestream', 'minecraft-modern-theme'),
|
||||
'description' => __('Einstellungen für YouTube Livestream-Erkennung. Hauptmethode: Livestream-Posts unter "Livestreams" erstellen. Optional: Zusätzlichen Hauptkanal hier eintragen.', 'minecraft-modern-theme'),
|
||||
'priority' => 75,
|
||||
) );
|
||||
|
||||
// Füge ein Custom Control mit HTML hinzu
|
||||
$wp_customize->add_setting( 'import_export_placeholder', array(
|
||||
$wp_customize->add_setting( 'youtube_api_key', array(
|
||||
'default' => '',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'transport' => 'refresh',
|
||||
) );
|
||||
$wp_customize->add_control( 'youtube_api_key', array(
|
||||
'label' => __('YouTube API Key', 'minecraft-modern-theme'),
|
||||
'description' => __('Erforderlich für automatische YouTube Live-Erkennung. <a href="https://console.cloud.google.com/" target="_blank">Hier API Key erstellen</a>', 'minecraft-modern-theme'),
|
||||
'section' => 'video_livestream_settings',
|
||||
'type' => 'text',
|
||||
'input_attrs' => array(
|
||||
'placeholder' => 'AIzaSyD...',
|
||||
),
|
||||
) );
|
||||
|
||||
// Custom Control Class für Export/Import
|
||||
class Import_Export_Control extends WP_Customize_Control {
|
||||
public $type = 'import_export';
|
||||
|
||||
public function render_content() {
|
||||
$export_url = admin_url('admin-post.php?action=export_theme_settings');
|
||||
$nonce = wp_create_nonce('theme-import-nonce');
|
||||
?>
|
||||
<div class="import-export-wrapper" style="margin-top: 15px;">
|
||||
<p class="description" style="margin-bottom: 20px;">
|
||||
<strong>Hinweis:</strong> Hier kannst du alle deine Theme-Einstellungen sichern und wiederherstellen.
|
||||
</p>
|
||||
|
||||
<a href="<?php echo esc_url($export_url); ?>" class="button button-primary button-hero" id="export-settings-btn" style="display: inline-flex; align-items: center; gap: 8px; margin-bottom: 20px;">
|
||||
<span class="dashicons dashicons-download" style="margin-top:3px;"></span> Einstellungen Exportieren
|
||||
</a>
|
||||
|
||||
<div style="border-top: 2px solid #ddd; padding-top: 20px; margin-top: 20px;">
|
||||
<label style="display:block; margin-bottom:10px; font-weight:bold;">
|
||||
Backup wiederherstellen:
|
||||
</label>
|
||||
<input type="file" id="import-settings-file" accept=".json" style="width:100%; margin-bottom:10px;">
|
||||
<button type="button" class="button button-secondary" id="import-settings-btn" disabled style="display: inline-flex; align-items: center; gap: 8px;">
|
||||
<span class="dashicons dashicons-upload" style="margin-top:3px;"></span> Einstellungen Importieren
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="description" style="margin-top:15px; padding: 10px; background: #fff3cd; border-left: 4px solid #ffc107;">
|
||||
<strong>⚠️ Warnung:</strong> Beim Import werden alle aktuellen Einstellungen überschrieben!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
var ajaxUrl = '<?php echo admin_url('admin-ajax.php'); ?>';
|
||||
var nonce = '<?php echo $nonce; ?>';
|
||||
|
||||
$('#import-settings-file').on('change', function() {
|
||||
$('#import-settings-btn').prop('disabled', $(this).val() === '');
|
||||
});
|
||||
$wp_customize->add_setting( 'twitch_client_id', array(
|
||||
'default' => '',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'transport' => 'refresh',
|
||||
) );
|
||||
$wp_customize->add_control( 'twitch_client_id', array(
|
||||
'label' => __('Twitch Client ID', 'minecraft-modern-theme'),
|
||||
'description' => __('Erforderlich für Twitch Live-Erkennung. <a href="https://dev.twitch.tv/console/apps" target="_blank">Hier App erstellen</a>', 'minecraft-modern-theme'),
|
||||
'section' => 'video_livestream_settings',
|
||||
'type' => 'text',
|
||||
'input_attrs' => array(
|
||||
'placeholder' => 'xxxxxxxxxxxxxx',
|
||||
),
|
||||
) );
|
||||
|
||||
$('#import-settings-btn').on('click', function() {
|
||||
var fileInput = $('#import-settings-file')[0];
|
||||
|
||||
if (fileInput.files.length === 0) {
|
||||
alert('Bitte wähle eine JSON-Datei aus.');
|
||||
return;
|
||||
}
|
||||
$wp_customize->add_setting( 'twitch_client_secret', array(
|
||||
'default' => '',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'transport' => 'refresh',
|
||||
) );
|
||||
$wp_customize->add_control( 'twitch_client_secret', array(
|
||||
'label' => __('Twitch Client Secret', 'minecraft-modern-theme'),
|
||||
'description' => __('Nur für Live-Prüfung. Wird serverseitig genutzt.', 'minecraft-modern-theme'),
|
||||
'section' => 'video_livestream_settings',
|
||||
'type' => 'text',
|
||||
'input_attrs' => array(
|
||||
'placeholder' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
),
|
||||
) );
|
||||
|
||||
if (!confirm('WARNUNG: Alle aktuellen Einstellungen werden überschrieben. Bist du sicher?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('import_file', fileInput.files[0]);
|
||||
formData.append('action', 'import_theme_settings');
|
||||
formData.append('nonce', nonce);
|
||||
|
||||
var $btn = $(this);
|
||||
var originalText = $btn.html();
|
||||
$btn.prop('disabled', true).html('<span class="dashicons dashicons-update" style="margin-top:3px; animation: rotation 1s infinite linear;"></span> Importiere...');
|
||||
|
||||
$.ajax({
|
||||
url: ajaxUrl,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
alert('✅ ' + response.data);
|
||||
location.reload();
|
||||
} else {
|
||||
alert('❌ Fehler: ' + response.data);
|
||||
$btn.prop('disabled', false).html(originalText);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('❌ Ein technischer Fehler ist aufgetreten.');
|
||||
$btn.prop('disabled', false).html(originalText);
|
||||
}
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@keyframes rotation {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
$wp_customize->add_control( new Import_Export_Control( $wp_customize, 'import_export_placeholder', array(
|
||||
// =========================================================================
|
||||
// 9. EXPORT / IMPORT
|
||||
// =========================================================================
|
||||
$wp_customize->add_section( 'theme_mods_import_export', array(
|
||||
'title' => __('Einstellungen sichern', 'minecraft-modern-theme'),
|
||||
'priority' => 999,
|
||||
) );
|
||||
$wp_customize->add_setting( 'import_export_placeholder', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
$wp_customize->add_control( new MM_Import_Export_Control( $wp_customize, 'import_export_placeholder', array(
|
||||
'section' => 'theme_mods_import_export',
|
||||
) ) );
|
||||
}
|
||||
@@ -480,110 +467,81 @@ add_action( 'customize_register', 'minecraft_modern_customize_register' );
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// === DYNAMISCHES CSS =====================================================
|
||||
// DYNAMISCHES CSS – FIX: Google Font via wp_enqueue_style(), nicht <link> in wp_head
|
||||
// =========================================================================
|
||||
function minecraft_modern_enqueue_dynamic_styles() {
|
||||
$font = get_theme_mod( 'slider_font_family', 'Raleway' );
|
||||
|
||||
function minecraft_modern_dynamic_css_output() {
|
||||
$accent_color = get_theme_mod( 'primary_accent_color', '#00d4ff' );
|
||||
$slider_font = get_theme_mod( 'slider_font_family', 'Raleway' );
|
||||
$slider_color = get_theme_mod( 'slider_font_color', '#ffffff' );
|
||||
$slider_size_setting = get_theme_mod( 'slider_font_size', 'mittel' );
|
||||
// Google Font sauber einbinden
|
||||
$font_url = 'https://fonts.googleapis.com/css2?family=' . urlencode($font) . ':wght@400;600;700&display=swap';
|
||||
wp_enqueue_style( 'minecraft-modern-google-font', $font_url, array(), null );
|
||||
|
||||
// Dynamisches CSS als inline style
|
||||
$accent_color = get_theme_mod( 'primary_accent_color', '#00d4ff' );
|
||||
$slider_color = get_theme_mod( 'slider_font_color', '#ffffff' );
|
||||
$slider_size_setting = get_theme_mod( 'slider_font_size', 'mittel' );
|
||||
$header_height_setting = get_theme_mod( 'header_height', 'mittel' );
|
||||
|
||||
// Header-Höhe umwandeln
|
||||
$header_height_value = '300px';
|
||||
if ( $header_height_setting === 'klein' ) {
|
||||
$header_height_value = '200px';
|
||||
} elseif ( $header_height_setting === 'gross' ) {
|
||||
$header_height_value = '400px';
|
||||
}
|
||||
$height_map = array( 'klein' => '200px', 'mittel' => '300px', 'gross' => '400px' );
|
||||
$header_height_value = isset($height_map[$header_height_setting]) ? $height_map[$header_height_setting] : '300px';
|
||||
|
||||
// Schriftgrößen umwandeln
|
||||
$font_sizes = array(
|
||||
'klein' => array( 'title' => '2.5rem', 'subtitle' => '1.2rem' ),
|
||||
'mittel' => array( 'title' => '3.5rem', 'subtitle' => '1.4rem' ),
|
||||
'gross' => array( 'title' => '4.5rem', 'subtitle' => '1.6rem' ),
|
||||
'extra-gross' => array( 'title' => '5.5rem', 'subtitle' => '1.8rem' ),
|
||||
);
|
||||
$chosen_sizes = isset( $font_sizes[$slider_size_setting] ) ? $font_sizes[$slider_size_setting] : $font_sizes['mittel'];
|
||||
$sizes = isset($font_sizes[$slider_size_setting]) ? $font_sizes[$slider_size_setting] : $font_sizes['mittel'];
|
||||
|
||||
$fonts_to_load = array($slider_font);
|
||||
$fonts_url = 'https://fonts.googleapis.com/css2?family=' . implode( ':wght@400;600;700&family=', $fonts_to_load ) . '&display=swap';
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" href="<?php echo esc_url($fonts_url); ?>">
|
||||
<style type="text/css">
|
||||
$css = "
|
||||
:root {
|
||||
--primary-accent: <?php echo esc_attr($accent_color); ?>;
|
||||
--header-height: <?php echo esc_attr($header_height_value); ?>;
|
||||
--primary-accent: " . esc_attr($accent_color) . ";
|
||||
--header-height: " . esc_attr($header_height_value) . ";
|
||||
}
|
||||
.slider-title, .slider-subtitle, .hero-title, .hero-subtitle, .hero-button-1, .hero-button-2 {
|
||||
font-family: '<?php echo esc_attr($slider_font); ?>', sans-serif;
|
||||
color: <?php echo esc_attr($slider_color); ?>;
|
||||
}
|
||||
.slider-title, .hero-title {
|
||||
font-size: <?php echo esc_attr($chosen_sizes['title']); ?>;
|
||||
}
|
||||
.slider-subtitle, .hero-subtitle {
|
||||
font-size: <?php echo esc_attr($chosen_sizes['subtitle']); ?>;
|
||||
font-family: '" . esc_attr($font) . "', sans-serif;
|
||||
color: " . esc_attr($slider_color) . ";
|
||||
}
|
||||
.slider-title, .hero-title { font-size: " . esc_attr($sizes['title']) . "; }
|
||||
.slider-subtitle, .hero-subtitle { font-size: " . esc_attr($sizes['subtitle']) . "; }
|
||||
.site-header { border-bottom: 4px solid var(--primary-accent); }
|
||||
.hero-slider { border-bottom: 4px solid var(--primary-accent); }
|
||||
.site-footer { border-top: 4px solid var(--primary-accent); }
|
||||
";
|
||||
|
||||
/* Trennlinie unter dem Header */
|
||||
.site-header {
|
||||
border-bottom: 4px solid var(--primary-accent);
|
||||
}
|
||||
|
||||
/* Trennlinie unter dem Slider */
|
||||
.hero-slider {
|
||||
border-bottom: 4px solid var(--primary-accent);
|
||||
}
|
||||
|
||||
/* Trennlinie am oberen Rand des Footers */
|
||||
.site-footer {
|
||||
border-top: 4px solid var(--primary-accent);
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
wp_add_inline_style( 'minecraft-modern-style', $css );
|
||||
}
|
||||
add_action( 'wp_head', 'minecraft_modern_dynamic_css_output' );
|
||||
add_action( 'wp_enqueue_scripts', 'minecraft_modern_enqueue_dynamic_styles', 20 );
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// === THEME PRESET LOGIC (JAVASCRIPT) =====================================
|
||||
// PRESET LOGIC (JS im Customizer)
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Verbindet das Preset-Dropdown mit der Akzentfarbe-Einstellung.
|
||||
* Sobald ein Preset gewählt wird, wird die Farbe im Customizer aktualisiert.
|
||||
*/
|
||||
function minecraft_preset_customize_js() {
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
// Definiere die Farben für die Presets
|
||||
var presetColors = {
|
||||
'classic': '#00d4ff', // Diamant Blau
|
||||
'nether': '#ff3333', // Lava Rot
|
||||
'end': '#aa00ff' // Ender Purpur
|
||||
};
|
||||
|
||||
// Warten bis der Customizer bereit ist
|
||||
wp.customize.bind('ready', function() {
|
||||
|
||||
// Listener für das Preset-Dropdown
|
||||
wp.customize('theme_color_preset', function(setting) {
|
||||
setting.bind(function(to) {
|
||||
// Wenn eine Farbe für das gewählte Preset existiert...
|
||||
if (presetColors[to]) {
|
||||
// ...setze die Akzentfarbe auf diesen Wert.
|
||||
// Das aktualisiert auch den Color Picker und die Live-Vorschau.
|
||||
wp.customize('primary_accent_color').set(presetColors[to]);
|
||||
}
|
||||
});
|
||||
function minecraft_preset_customize_js() { ?>
|
||||
<script>
|
||||
(function($){
|
||||
var presetColors = { classic: '#00d4ff', nether: '#ff3333', end: '#aa00ff' };
|
||||
wp.customize.bind('ready', function(){
|
||||
wp.customize('theme_color_preset', function(setting){
|
||||
setting.bind(function(to){
|
||||
if (presetColors[to]) {
|
||||
wp.customize('primary_accent_color').set(presetColors[to]);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
})(jQuery);
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
add_action('customize_controls_print_footer_scripts', 'minecraft_preset_customize_js');
|
||||
<?php }
|
||||
add_action( 'customize_controls_print_footer_scripts', 'minecraft_preset_customize_js' );
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// FIX: slider_loop an JS übergeben (in functions.php in wp_localize_script ergänzen)
|
||||
// Der folgende Filter hängt den Wert an sliderSettings an.
|
||||
// Alternativ: direkt in functions.php bei wp_localize_script 'loop' hinzufügen.
|
||||
// =========================================================================
|
||||
add_filter( 'minecraft_modern_slider_settings', function( $settings ) {
|
||||
$settings['loop'] = get_theme_mod('slider_loop', true) ? '1' : '0';
|
||||
return $settings;
|
||||
} );
|
||||
@@ -1,160 +1,141 @@
|
||||
<?php
|
||||
/**
|
||||
* Minecraft Modern Theme - Updater & Dashboard Status
|
||||
*
|
||||
* Diese Datei prüft auf neue Versionen via Gitea API und zeigt den Status im Dashboard an.
|
||||
* Aus Sicherheitsgründen ist das automatische Update deaktiviert, um Datenverlust zu vermeiden.
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// === THEME VERSION AUTOMATISCH AUS style.css LADEN (PARENT THEME PRIORITÄT) ===
|
||||
function minecraft_modern_get_theme_version() {
|
||||
// Holt das aktuell aktive Theme (child oder parent)
|
||||
$theme = wp_get_theme();
|
||||
class Minecraft_Modern_Theme_Manager {
|
||||
|
||||
// Wenn ein Child-Theme aktiv ist und ein Parent vorhanden ist, nutze die Parent-Version
|
||||
$parent = $theme->parent();
|
||||
if ( $parent && $parent->exists() ) {
|
||||
$parent_version = $parent->get( 'Version' );
|
||||
if ( ! empty( $parent_version ) ) {
|
||||
return $parent_version;
|
||||
// BUG-FIX: Hardcoded 'Minecraft-Modern-Theme' schlug auf Linux-Servern
|
||||
// (case-sensitive Dateisystem) fehl, wenn das Verzeichnis kleingeschrieben ist.
|
||||
// get_template() liefert immer den echten Verzeichnisnamen.
|
||||
private $theme_slug;
|
||||
private $repo = 'M_Viper/Minecraft-Modern-Theme';
|
||||
private $transient_key = 'mm_theme_update_check';
|
||||
|
||||
public function __construct() {
|
||||
$this->theme_slug = get_template();
|
||||
|
||||
add_action( 'admin_notices', [ $this, 'display_update_notice' ] );
|
||||
add_action( 'wp_dashboard_setup', [ $this, 'add_dashboard_widget' ] );
|
||||
add_action( 'admin_init', [ $this, 'handle_refresh_request' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt die API-Daten von Gitea (mit Transient-Cache).
|
||||
*/
|
||||
private function get_latest_release() {
|
||||
$update_data = get_transient( $this->transient_key );
|
||||
|
||||
if ( false === $update_data ) {
|
||||
$api_url = "https://git.viper.ipv64.net/api/v1/repos/{$this->repo}/releases/latest";
|
||||
$response = wp_remote_get( $api_url, [ 'timeout' => 10 ] );
|
||||
|
||||
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
|
||||
set_transient( $this->transient_key, [ 'error' => true ], 2 * HOUR_IN_SECONDS );
|
||||
return [ 'error' => true ];
|
||||
}
|
||||
|
||||
$data = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
$new_version = ltrim( $data->tag_name, 'vV' );
|
||||
|
||||
$update_data = [
|
||||
'version' => $new_version,
|
||||
'url' => "https://git.viper.ipv64.net/{$this->repo}/releases",
|
||||
];
|
||||
|
||||
set_transient( $this->transient_key, $update_data, 12 * HOUR_IN_SECONDS );
|
||||
}
|
||||
|
||||
return $update_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die gelbe Info-Box oben im Admin-Bereich an, wenn ein Update verfügbar ist.
|
||||
*/
|
||||
public function display_update_notice() {
|
||||
if ( ! current_user_can( 'update_themes' ) ) return;
|
||||
|
||||
$latest = $this->get_latest_release();
|
||||
if ( isset( $latest['error'] ) ) return;
|
||||
|
||||
$current_version = wp_get_theme( $this->theme_slug )->get( 'Version' );
|
||||
if ( ! $current_version ) return;
|
||||
|
||||
if ( version_compare( $current_version, $latest['version'], '<' ) ) {
|
||||
?>
|
||||
<div class="notice notice-warning is-dismissible">
|
||||
<p>
|
||||
<span class="dashicons dashicons-update" style="color: #dba617; margin-right: 5px;"></span>
|
||||
<strong>Minecraft Modern Update verfügbar:</strong>
|
||||
Version <strong><?php echo esc_html( $latest['version'] ); ?></strong> ist bereit zum Download.
|
||||
<a href="<?php echo esc_url( $latest['url'] ); ?>" target="_blank" style="margin-left: 10px; font-weight: bold;">
|
||||
Zum Download →
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Version des aktuell aktiven Themes (wenn kein Parent existiert oder Parent keine Version hat)
|
||||
return $theme->get( 'Version' );
|
||||
}
|
||||
|
||||
// === THEME UPDATE NOTIFICATION SYSTEM ===
|
||||
|
||||
// Funktion zum Leeren des Caches (wenn man auf "Update prüfen" klickt)
|
||||
function minecraft_modern_clear_cache() {
|
||||
if ( isset( $_GET['mm_clear_cache'] ) && current_user_can( 'manage_options' ) ) {
|
||||
check_admin_referer( 'mm_clear_cache_action' );
|
||||
delete_transient( 'minecraft_modern_latest_release' );
|
||||
wp_redirect( admin_url( 'index.php' ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
add_action( 'admin_init', 'minecraft_modern_clear_cache' );
|
||||
|
||||
// Funktion zum Abrufen der neuesten Release-Informationen
|
||||
function minecraft_modern_get_latest_release_info( $force_refresh = false ) {
|
||||
$transient_key = 'minecraft_modern_latest_release';
|
||||
|
||||
// Wenn erzwungen wird (oder Cache leer), frische Daten holen
|
||||
if ( $force_refresh ) {
|
||||
delete_transient( $transient_key );
|
||||
}
|
||||
|
||||
$release_info = get_transient( $transient_key );
|
||||
|
||||
if ( false === $release_info ) {
|
||||
// Timeout auf 10 Sekunden erhöht für langsame Verbindungen
|
||||
$response = wp_remote_get(
|
||||
'https://git.viper.ipv64.net/api/v1/repos/M_Viper/Minecraft-Modern-Theme/releases/latest',
|
||||
array( 'timeout' => 10 )
|
||||
/**
|
||||
* Fügt das Widget zum WordPress-Dashboard hinzu.
|
||||
*/
|
||||
public function add_dashboard_widget() {
|
||||
wp_add_dashboard_widget(
|
||||
'mm_theme_status_widget',
|
||||
'Minecraft Modern Theme Status',
|
||||
[ $this, 'render_widget_content' ]
|
||||
);
|
||||
|
||||
if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$release_data = json_decode( $body, true );
|
||||
|
||||
if ( $release_data && isset( $release_data['tag_name'] ) ) {
|
||||
// Tag bereinigen (falls 'v' davor steht, z.B. v1.6 -> 1.6)
|
||||
$tag_name = $release_data['tag_name'];
|
||||
if ( strpos( $tag_name, 'v' ) === 0 ) {
|
||||
$tag_name = ltrim( $tag_name, 'v' );
|
||||
}
|
||||
}
|
||||
|
||||
$release_info = array(
|
||||
'version' => $tag_name,
|
||||
'download_url' => $release_data['zipball_url'],
|
||||
'release_notes' => isset( $release_data['body'] ) ? $release_data['body'] : '',
|
||||
'published_at' => isset( $release_data['published_at'] ) ? $release_data['published_at'] : ''
|
||||
);
|
||||
|
||||
// Cache für 6 Stunden
|
||||
set_transient( $transient_key, $release_info, 6 * HOUR_IN_SECONDS );
|
||||
/**
|
||||
* HTML-Inhalt des Dashboard-Widgets.
|
||||
*/
|
||||
public function render_widget_content() {
|
||||
$current_version = wp_get_theme( $this->theme_slug )->get( 'Version' );
|
||||
$latest = $this->get_latest_release();
|
||||
|
||||
echo '<div class="mm-status-widget">';
|
||||
echo '<p><span class="dashicons dashicons-admin-appearance"></span> <strong>Installiert:</strong> ' . esc_html( $current_version ?: '–' ) . '</p>';
|
||||
|
||||
if ( isset( $latest['version'] ) ) {
|
||||
echo '<p><span class="dashicons dashicons-cloud"></span> <strong>Aktuellste:</strong> ' . esc_html( $latest['version'] ) . '</p>';
|
||||
|
||||
if ( $current_version && version_compare( $current_version, $latest['version'], '<' ) ) {
|
||||
echo '<div style="background: #fff8e5; border-left: 4px solid #ffb900; padding: 12px; margin: 15px 0;">';
|
||||
echo '<p style="margin: 0 0 10px; color: #856404;"><strong>Update verfügbar!</strong></p>';
|
||||
echo '<a href="' . esc_url( $latest['url'] ) . '" class="button button-primary" target="_blank">Download ZIP von Gitea</a>';
|
||||
echo '</div>';
|
||||
} else {
|
||||
// Fehlerhafte Daten leer cachen
|
||||
set_transient( $transient_key, array(), HOUR_IN_SECONDS );
|
||||
echo '<p style="color: #46b450; font-weight: bold; margin-top: 15px;">';
|
||||
echo '<span class="dashicons dashicons-yes"></span> Theme ist aktuell.</p>';
|
||||
}
|
||||
} else {
|
||||
// Fehler beim Abrufen
|
||||
set_transient( $transient_key, array(), HOUR_IN_SECONDS );
|
||||
echo '<p style="color: #d63638;"><span class="dashicons dashicons-warning"></span> Prüfung fehlgeschlagen.</p>';
|
||||
}
|
||||
|
||||
$refresh_url = wp_nonce_url( admin_url( 'index.php?mm_refresh_check=1' ), 'mm_refresh_action' );
|
||||
echo '<hr><p><small><a href="' . esc_url( $refresh_url ) . '">Update-Cache jetzt leeren</a></small></p>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet den Klick auf "Update-Cache jetzt leeren".
|
||||
*/
|
||||
public function handle_refresh_request() {
|
||||
if ( isset( $_GET['mm_refresh_check'] ) && check_admin_referer( 'mm_refresh_action' ) ) {
|
||||
delete_transient( $this->transient_key );
|
||||
wp_redirect( admin_url( 'index.php' ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
return $release_info;
|
||||
}
|
||||
|
||||
// === BENACHRICHTIGUNG IM ADMIN-BEREICH ===
|
||||
function minecraft_modern_show_update_notification() {
|
||||
if ( ! is_admin() || ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current_version = minecraft_modern_get_theme_version();
|
||||
$latest_release = minecraft_modern_get_latest_release_info();
|
||||
|
||||
if ( ! empty( $latest_release ) && isset( $latest_release['version'] ) && version_compare( $current_version, $latest_release['version'], '<' ) ) {
|
||||
?>
|
||||
<div class="notice notice-warning is-dismissible">
|
||||
<h3><?php _e( 'Minecraft Modern Theme Update Available', 'minecraft-modern-theme' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
__( 'You are using version %1$s of the Minecraft Modern Theme. Version %2$s is now available.', 'minecraft-modern-theme' ),
|
||||
'<strong>' . esc_html( $current_version ) . '</strong>',
|
||||
'<strong>' . esc_html( $latest_release['version'] ) . '</strong>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<a href="<?php echo esc_url( $latest_release['download_url'] ); ?>" class="button button-primary" target="_blank">
|
||||
<?php _e( 'Download Latest Version', 'minecraft-modern-theme' ); ?>
|
||||
</a>
|
||||
<a href="https://git.viper.ipv64.net/M_Viper/Minecraft-Modern-Theme/releases" class="button" target="_blank">
|
||||
<?php _e( 'View Release Notes', 'minecraft-modern-theme' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
add_action( 'admin_notices', 'minecraft_modern_show_update_notification' );
|
||||
|
||||
// === DASHBOARD WIDGET ===
|
||||
function minecraft_modern_add_dashboard_widget() {
|
||||
wp_add_dashboard_widget(
|
||||
'minecraft_modern_update_widget',
|
||||
'Minecraft Modern Theme Status',
|
||||
'minecraft_modern_update_widget_function'
|
||||
);
|
||||
}
|
||||
add_action( 'wp_dashboard_setup', 'minecraft_modern_add_dashboard_widget' );
|
||||
|
||||
function minecraft_modern_update_widget_function() {
|
||||
$current_version = minecraft_modern_get_theme_version();
|
||||
$latest_release = minecraft_modern_get_latest_release_info();
|
||||
|
||||
echo '<p><strong>' . __( 'Current Version:', 'minecraft-modern-theme' ) . '</strong> ' . esc_html( $current_version ) . '</p>';
|
||||
|
||||
if ( ! empty( $latest_release ) && isset( $latest_release['version'] ) ) {
|
||||
echo '<p><strong>' . __( 'Latest Version:', 'minecraft-modern-theme' ) . '</strong> ' . esc_html( $latest_release['version'] ) . '</p>';
|
||||
|
||||
if ( version_compare( $current_version, $latest_release['version'], '<' ) ) {
|
||||
echo '<p><strong>' . __( 'Status:', 'minecraft-modern-theme' ) . '</strong> <span style="color:#d63638;">' . __( 'Update Available', 'minecraft-modern-theme' ) . '</span></p>';
|
||||
echo '<p><a href="' . esc_url( $latest_release['download_url'] ) . '" class="button button-primary" target="_blank">' . __( 'Download Update', 'minecraft-modern-theme' ) . '</a></p>';
|
||||
} else {
|
||||
echo '<p><strong>' . __( 'Status:', 'minecraft-modern-theme' ) . '</strong> <span style="color:#46b450;">' . __( 'Up to Date', 'minecraft-modern-theme' ) . '</span></p>';
|
||||
}
|
||||
} else {
|
||||
echo '<p><strong>' . __( 'Status:', 'minecraft-modern-theme' ) . '</strong> ' . __( 'Unable to check for updates', 'minecraft-modern-theme' ) . '</p>';
|
||||
}
|
||||
|
||||
// Link für "Jetzt prüfen"
|
||||
$refresh_url = wp_nonce_url( admin_url( 'index.php?mm_clear_cache=1' ), 'mm_clear_cache_action' );
|
||||
echo '<p><a href="' . esc_url( $refresh_url ) . '" onclick="return confirm(\'Cache leeren und neu prüfen?\');">' . __( 'Check for Updates Now', 'minecraft-modern-theme' ) . '</a></p>';
|
||||
|
||||
echo '<p><a href="https://git.viper.ipv64.net/M_Viper/Minecraft-Modern-Theme/releases" target="_blank">' . __( 'View All Releases', 'minecraft-modern-theme' ) . '</a></p>';
|
||||
}
|
||||
new Minecraft_Modern_Theme_Manager();
|
||||
@@ -3,25 +3,73 @@
|
||||
<main id="primary" class="site-main">
|
||||
<div class="container">
|
||||
<div class="content-area">
|
||||
|
||||
<?php if ( have_posts() ) : ?>
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class('post'); ?>>
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<div class="post-thumbnail">
|
||||
<a href="<?php the_permalink(); ?>"><?php the_post_thumbnail('medium_large'); ?></a>
|
||||
|
||||
<div class="archive-posts-grid">
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class('post archive-post-card'); ?>>
|
||||
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<div class="archive-card-thumb">
|
||||
<a href="<?php the_permalink(); ?>">
|
||||
<?php the_post_thumbnail('medium_large', array('loading' => 'lazy')); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="archive-card-body">
|
||||
|
||||
<?php $cats = get_the_category(); if ( $cats ) : ?>
|
||||
<div class="archive-card-cats">
|
||||
<a href="<?php echo esc_url( get_category_link( $cats[0]->term_id ) ); ?>" class="post-category-badge">
|
||||
<?php echo esc_html( $cats[0]->name ); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2 class="archive-card-title">
|
||||
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||||
</h2>
|
||||
|
||||
<div class="archive-card-meta">
|
||||
<span><i class="fas fa-calendar-alt"></i> <?php echo esc_html( get_the_date() ); ?></span>
|
||||
<span><i class="fas fa-user"></i> <?php the_author(); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="archive-card-excerpt">
|
||||
<?php the_excerpt(); ?>
|
||||
</div>
|
||||
|
||||
<a href="<?php the_permalink(); ?>" class="archive-card-read-more">
|
||||
<?php _e('Weiterlesen', 'minecraft-modern-theme'); ?> <i class="fas fa-arrow-right"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="post-content">
|
||||
<h2 class="post-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
|
||||
<div class="post-excerpt">
|
||||
<?php the_excerpt(); ?>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<?php endwhile; ?>
|
||||
</article>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
|
||||
<!-- FIX: Pagination fehlte komplett -->
|
||||
<div class="archive-pagination">
|
||||
<?php
|
||||
the_posts_pagination( array(
|
||||
'mid_size' => 2,
|
||||
'prev_text' => '<i class="fas fa-chevron-left"></i> ' . __('Zurück', 'minecraft-modern-theme'),
|
||||
'next_text' => __('Weiter', 'minecraft-modern-theme') . ' <i class="fas fa-chevron-right"></i>',
|
||||
) );
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php else : ?>
|
||||
<p><?php _e( 'Keine Beiträge gefunden.', 'minecraft-modern-theme' ); ?></p>
|
||||
|
||||
<div class="no-posts-found">
|
||||
<i class="fas fa-inbox fa-2x"></i>
|
||||
<p><?php _e('Keine Beiträge gefunden.', 'minecraft-modern-theme'); ?></p>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -7,8 +7,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
if (position === "top") {
|
||||
document.body.insertAdjacentElement('afterbegin', bar);
|
||||
}
|
||||
else if (position === "below-slider") {
|
||||
} else if (position === "below-slider") {
|
||||
const anchor = document.getElementById("mm-announcement-anchor");
|
||||
if (anchor) {
|
||||
anchor.replaceWith(bar);
|
||||
@@ -16,69 +15,62 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
const header = document.getElementById("masthead");
|
||||
if (header) header.insertAdjacentElement('afterend', bar);
|
||||
}
|
||||
}
|
||||
else if (position === "below-header") {
|
||||
const header = document.getElementById("masthead");
|
||||
if (header) header.insertAdjacentElement('afterend', bar);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// "below-header" und alle anderen Positionen
|
||||
const header = document.getElementById("masthead");
|
||||
if (header) header.insertAdjacentElement('afterend', bar);
|
||||
}
|
||||
|
||||
// --- 2. Schließen-Button ---
|
||||
const closeBtn = bar.querySelector(".mm-announcement-close");
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener("click", function () {
|
||||
bar.style.display = "none";
|
||||
bar.style.transition = 'opacity 0.3s ease';
|
||||
bar.style.opacity = '0';
|
||||
setTimeout(function() { bar.style.display = "none"; }, 300);
|
||||
});
|
||||
}
|
||||
|
||||
// --- 2. Countdown Timer Logik ---
|
||||
// --- 3. Countdown Timer ---
|
||||
const timerElement = document.querySelector('.mm-countdown-timer');
|
||||
|
||||
|
||||
if (timerElement) {
|
||||
const targetDateString = timerElement.getAttribute('data-date');
|
||||
const expiredMessage = timerElement.getAttribute('data-expired');
|
||||
|
||||
// Prüfen ob Datum gesetzt ist
|
||||
if (targetDateString) {
|
||||
const countDownDate = new Date(targetDateString).getTime();
|
||||
const expiredMessage = timerElement.getAttribute('data-expired') || 'Abgelaufen';
|
||||
|
||||
const updateTimer = setInterval(function() {
|
||||
const now = new Date().getTime();
|
||||
const distance = countDownDate - now;
|
||||
|
||||
if (distance < 0) {
|
||||
clearInterval(updateTimer);
|
||||
timerElement.innerHTML = expiredMessage;
|
||||
// Optional: Rot einfärben wenn abgelaufen
|
||||
timerElement.style.color = '#ff3333';
|
||||
return;
|
||||
}
|
||||
|
||||
// Zeitberechnung
|
||||
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
||||
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||
|
||||
// Formatierung (z.B. 05 statt 5)
|
||||
const fDays = days > 0 ? days + "d " : "";
|
||||
const fHours = hours < 10 ? "0" + hours : hours;
|
||||
const fMinutes = minutes < 10 ? "0" + minutes : minutes;
|
||||
const fSeconds = seconds < 10 ? "0" + seconds : seconds;
|
||||
|
||||
timerElement.innerHTML = fDays + fHours + ":" + fMinutes + ":" + fSeconds;
|
||||
}, 1000);
|
||||
|
||||
// Sofort einmal ausführen, um Ladezeit zu vermeiden
|
||||
// Wir lösen das Interval manuell für den ersten Durchlauf aus,
|
||||
// indem wir den Code kopieren oder den Timeout kurz setzen.
|
||||
// Für diesen Fall reicht der erste Tick nach 1 Sekunde,
|
||||
// aber wir können es direkt aufrufen:
|
||||
// (Hier nutzen wir einfach den ersten Tick des Intervals)
|
||||
} else {
|
||||
if (!targetDateString) {
|
||||
timerElement.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
const countDownDate = new Date(targetDateString).getTime();
|
||||
|
||||
// FIX: Tick-Funktion auslagern und SOFORT aufrufen – kein 1s-Flackern beim Laden
|
||||
function tick() {
|
||||
const now = new Date().getTime();
|
||||
const distance = countDownDate - now;
|
||||
|
||||
if (distance < 0) {
|
||||
clearInterval(timerInterval);
|
||||
timerElement.innerHTML = expiredMessage;
|
||||
timerElement.style.color = '#ff3333';
|
||||
return;
|
||||
}
|
||||
|
||||
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
||||
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||
|
||||
const fDays = days > 0 ? days + 'd ' : '';
|
||||
const fHours = String(hours).padStart(2, '0');
|
||||
const fMinutes = String(minutes).padStart(2, '0');
|
||||
const fSeconds = String(seconds).padStart(2, '0');
|
||||
|
||||
timerElement.innerHTML = fDays + fHours + ':' + fMinutes + ':' + fSeconds;
|
||||
}
|
||||
|
||||
tick(); // Sofort ausführen
|
||||
const timerInterval = setInterval(tick, 1000);
|
||||
}
|
||||
});
|
||||
1
Minecraft-Modern-Theme/js/assistant-widget.js
Normal file
1
Minecraft-Modern-Theme/js/assistant-widget.js
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -1,17 +1,124 @@
|
||||
// /js/header-scroll.js
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// WICHTIG: Das Skript nur ausführen, wenn wir NICHT im Customizer sind.
|
||||
// Diese Prüfung ist robuster und funktioniert ohne PHP.
|
||||
if ( window.location.href.includes('/wp-admin/customize.php') || ( window.parent && window.parent.wp && window.parent.wp.customize ) ) {
|
||||
return; // Skript hier beenden, wenn wir im Customizer sind.
|
||||
// header-scroll.js – kompakter Header beim Scrollen + Suche Toggle
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
// ── Customizer Guard ──────────────────────────────────────────────────
|
||||
if (
|
||||
window.location.href.includes('/wp-admin/customize.php') ||
|
||||
(window.parent && window.parent.wp && window.parent.wp.customize)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Scroll-Effekt + kompakter Header ─────────────────────────────────
|
||||
const header = document.querySelector('.site-header');
|
||||
window.addEventListener('scroll', function() {
|
||||
if (window.scrollY > 50) {
|
||||
header.classList.add('scrolled');
|
||||
} else {
|
||||
header.classList.remove('scrolled');
|
||||
}
|
||||
});
|
||||
const brandingRow = header ? header.querySelector('.header-row-branding') : null;
|
||||
|
||||
if (header) {
|
||||
let lastScrollY = Math.max(window.scrollY, 0);
|
||||
let directionAnchorY = lastScrollY;
|
||||
let isCompact = header.classList.contains('header-compact');
|
||||
let lastStateChangeAt = 0;
|
||||
let ticking = false;
|
||||
|
||||
const compactEnterThreshold = 110;
|
||||
const compactExitThreshold = 24;
|
||||
const directionThreshold = 10;
|
||||
const expandDelta = 120;
|
||||
const stateChangeCooldown = 260;
|
||||
|
||||
const setCompactState = function (nextCompact, now) {
|
||||
if (isCompact === nextCompact) {
|
||||
return;
|
||||
}
|
||||
|
||||
isCompact = nextCompact;
|
||||
lastStateChangeAt = now;
|
||||
directionAnchorY = Math.max(window.scrollY, 0);
|
||||
|
||||
header.classList.toggle('header-compact', nextCompact);
|
||||
|
||||
if (brandingRow) {
|
||||
brandingRow.classList.toggle('branding-hidden', nextCompact);
|
||||
}
|
||||
};
|
||||
|
||||
const updateHeaderState = function () {
|
||||
ticking = false;
|
||||
|
||||
const now = window.performance && typeof window.performance.now === 'function'
|
||||
? window.performance.now()
|
||||
: Date.now();
|
||||
const currentScrollY = Math.max(window.scrollY, 0);
|
||||
const delta = currentScrollY - lastScrollY;
|
||||
const canChangeState = now - lastStateChangeAt >= stateChangeCooldown;
|
||||
|
||||
header.classList.toggle('scrolled', currentScrollY > 50);
|
||||
|
||||
if (currentScrollY <= compactExitThreshold) {
|
||||
setCompactState(false, now);
|
||||
} else if (canChangeState && delta > directionThreshold) {
|
||||
directionAnchorY = currentScrollY;
|
||||
|
||||
if (currentScrollY > compactEnterThreshold) {
|
||||
setCompactState(true, now);
|
||||
}
|
||||
} else if (canChangeState && delta < -directionThreshold) {
|
||||
if (directionAnchorY - currentScrollY >= expandDelta) {
|
||||
setCompactState(false, now);
|
||||
}
|
||||
}
|
||||
|
||||
lastScrollY = currentScrollY;
|
||||
};
|
||||
|
||||
const onScroll = function () {
|
||||
if (ticking) {
|
||||
return;
|
||||
}
|
||||
|
||||
ticking = true;
|
||||
window.requestAnimationFrame(updateHeaderState);
|
||||
};
|
||||
|
||||
updateHeaderState();
|
||||
window.addEventListener('scroll', onScroll, { passive: true });
|
||||
}
|
||||
|
||||
// ── Suche Toggle ──────────────────────────────────────────────────────
|
||||
const searchToggle = document.querySelector('.header-search-toggle');
|
||||
const searchDropdown = document.querySelector('.header-search-dropdown');
|
||||
|
||||
if (searchToggle && searchDropdown) {
|
||||
searchToggle.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
const isOpen = searchDropdown.classList.toggle('open');
|
||||
searchToggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
||||
searchDropdown.setAttribute('aria-hidden', isOpen ? 'false' : 'true');
|
||||
|
||||
if (isOpen) {
|
||||
// Fokus ins Suchfeld setzen
|
||||
const field = searchDropdown.querySelector('.search-field');
|
||||
if (field) setTimeout(function () { field.focus(); }, 50);
|
||||
}
|
||||
});
|
||||
|
||||
// Schließen bei Außenklick
|
||||
document.addEventListener('click', function (e) {
|
||||
if (!searchDropdown.contains(e.target) && !searchToggle.contains(e.target)) {
|
||||
searchDropdown.classList.remove('open');
|
||||
searchToggle.setAttribute('aria-expanded', 'false');
|
||||
searchDropdown.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
});
|
||||
|
||||
// Schließen mit Escape
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape' && searchDropdown.classList.contains('open')) {
|
||||
searchDropdown.classList.remove('open');
|
||||
searchToggle.setAttribute('aria-expanded', 'false');
|
||||
searchDropdown.setAttribute('aria-hidden', 'true');
|
||||
searchToggle.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,25 +1,30 @@
|
||||
jQuery(document).ready(function($) {
|
||||
const slider = $('#minecraft-avatar-slider');
|
||||
const slides = slider.find('.avatar-slide');
|
||||
|
||||
// Nur starten, wenn es mehr als einen Slide gibt
|
||||
if (slides.length > 1) {
|
||||
let currentIndex = 0;
|
||||
|
||||
function showSlide(index) {
|
||||
slides.removeClass('avatar-slide-active');
|
||||
slides.eq(index).addClass('avatar-slide-active');
|
||||
}
|
||||
if ( slides.length === 0 ) return;
|
||||
|
||||
let currentIndex = 0;
|
||||
|
||||
function showSlide(index) {
|
||||
slides.removeClass('avatar-slide-active');
|
||||
slides.eq(index).addClass('avatar-slide-active');
|
||||
}
|
||||
|
||||
// FIX: Ersten Slide sofort anzeigen, nicht erst nach dem ersten Interval-Tick
|
||||
showSlide(0);
|
||||
|
||||
// Nur Interval starten wenn es mehr als einen Slide gibt
|
||||
if ( slides.length > 1 ) {
|
||||
function nextSlide() {
|
||||
currentIndex = (currentIndex + 1) % slides.length;
|
||||
showSlide(currentIndex);
|
||||
}
|
||||
|
||||
// Geschwindigkeit aus den WordPress-Einstellungen holen
|
||||
const speed = avatarSliderSettings.speed || 4000;
|
||||
const speed = ( typeof avatarSliderSettings !== 'undefined' && avatarSliderSettings.speed )
|
||||
? avatarSliderSettings.speed
|
||||
: 4000;
|
||||
|
||||
// Den Slider alle X Sekunden wechseln
|
||||
setInterval(nextSlide, speed);
|
||||
}
|
||||
});
|
||||
63
Minecraft-Modern-Theme/js/minecraft-avatar-skinview.js
Normal file
63
Minecraft-Modern-Theme/js/minecraft-avatar-skinview.js
Normal file
@@ -0,0 +1,63 @@
|
||||
// Lädt skinview3d von CDN
|
||||
(function(){
|
||||
if(document.getElementById('skinview3d-cdn')) return;
|
||||
var s = document.createElement('script');
|
||||
s.id = 'skinview3d-cdn';
|
||||
s.src = 'https://unpkg.com/skinview3d@4.1.1/bundles/skinview3d.min.js';
|
||||
s.onload = function() {
|
||||
window.skinview3dReady = true;
|
||||
};
|
||||
document.head.appendChild(s);
|
||||
})();
|
||||
|
||||
window.showMinecraftSkinModal = function(uuid) {
|
||||
if(document.getElementById('minecraft-skin-modal')) return;
|
||||
var modal = document.createElement('div');
|
||||
modal.id = 'minecraft-skin-modal';
|
||||
modal.innerHTML = `
|
||||
<div class="sv3d-modal-bg"></div>
|
||||
<div class="sv3d-modal-content">
|
||||
<button class="sv3d-modal-close" aria-label="Schließen">×</button>
|
||||
<div id="sv3d-canvas-wrap" style="width:320px;height:320px;"></div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(modal);
|
||||
document.querySelector('.sv3d-modal-close').onclick = function(){ modal.remove(); };
|
||||
document.querySelector('.sv3d-modal-bg').onclick = function(){ modal.remove(); };
|
||||
|
||||
function renderSkin() {
|
||||
var skinUrl = `https://crafatar.com/skins/${uuid}`;
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = 320; canvas.height = 320;
|
||||
document.getElementById('sv3d-canvas-wrap').appendChild(canvas);
|
||||
var viewer = new skinview3d.SkinViewer({
|
||||
canvas: canvas,
|
||||
width: 320,
|
||||
height: 320,
|
||||
skin: skinUrl
|
||||
});
|
||||
viewer.controls.enableZoom = false;
|
||||
viewer.animation = new skinview3d.WalkingAnimation();
|
||||
viewer.animation.speed = 1.2;
|
||||
viewer.animation.play();
|
||||
}
|
||||
if(window.skinview3dReady) renderSkin();
|
||||
else {
|
||||
var check = setInterval(function(){
|
||||
if(window.skinview3dReady) { clearInterval(check); renderSkin(); }
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
// Avatar-Widget-Click-Handler
|
||||
window.addEventListener('DOMContentLoaded', function(){
|
||||
var widget = document.getElementById('minecraft-avatar-widget');
|
||||
if(widget) {
|
||||
widget.style.cursor = 'pointer';
|
||||
widget.title = 'Klicke für 3D Skin-Ansicht';
|
||||
widget.onclick = function(){
|
||||
var uuid = widget.getAttribute('data-uuid');
|
||||
if(uuid) window.showMinecraftSkinModal(uuid);
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -1,40 +1,174 @@
|
||||
( function() {
|
||||
const siteNavigation = document.getElementById( 'site-navigation' );
|
||||
const menuToggle = siteNavigation.querySelector( '.menu-toggle' );
|
||||
( function () {
|
||||
'use strict';
|
||||
|
||||
var isSidebarLayout = document.querySelector( '.site-header--sidebar' ) !== null;
|
||||
|
||||
if ( isSidebarLayout ) {
|
||||
|
||||
// --- Panel öffnen / schließen ---
|
||||
var panel = document.getElementById( 'header-sidebar' );
|
||||
var overlay = document.getElementById( 'sidebar-overlay' );
|
||||
var openBtn = document.querySelector( '.sidebar-menu-toggle' );
|
||||
var closeBtn = document.querySelector( '.sidebar-menu-close' );
|
||||
|
||||
function openPanel() {
|
||||
if ( ! panel ) return;
|
||||
panel.classList.add( 'is-open' );
|
||||
panel.setAttribute( 'aria-hidden', 'false' );
|
||||
if ( openBtn ) openBtn.setAttribute( 'aria-expanded', 'true' );
|
||||
if ( overlay ) overlay.classList.add( 'is-visible' );
|
||||
document.body.classList.add( 'sidebar-nav-open' );
|
||||
}
|
||||
|
||||
function closePanel() {
|
||||
if ( ! panel ) return;
|
||||
panel.classList.remove( 'is-open' );
|
||||
panel.setAttribute( 'aria-hidden', 'true' );
|
||||
if ( openBtn ) openBtn.setAttribute( 'aria-expanded', 'false' );
|
||||
if ( overlay ) overlay.classList.remove( 'is-visible' );
|
||||
document.body.classList.remove( 'sidebar-nav-open' );
|
||||
}
|
||||
|
||||
if ( openBtn ) openBtn.addEventListener( 'click', openPanel );
|
||||
if ( closeBtn ) closeBtn.addEventListener( 'click', closePanel );
|
||||
if ( overlay ) overlay.addEventListener( 'click', closePanel );
|
||||
document.addEventListener( 'keydown', function ( e ) {
|
||||
if ( e.key === 'Escape' ) closePanel();
|
||||
} );
|
||||
|
||||
// --- Submenu Flyout ---
|
||||
var sidebarNav = document.getElementById( 'site-navigation' );
|
||||
if ( sidebarNav ) {
|
||||
sidebarNav.querySelectorAll( '.menu-item-has-children' ).forEach( function ( item ) {
|
||||
var subMenu = item.querySelector( ':scope > .sub-menu' );
|
||||
if ( ! subMenu ) return;
|
||||
|
||||
var isOpen = false;
|
||||
var moveHdlr = null;
|
||||
|
||||
function showFlyout() {
|
||||
if ( isOpen ) return;
|
||||
isOpen = true;
|
||||
subMenu.style.top = item.getBoundingClientRect().top + 'px';
|
||||
item.classList.add( 'flyout-open' );
|
||||
|
||||
// Erkennungszone berechnen:
|
||||
// - vertikal: Höhe des li-Elements
|
||||
// - horizontal: von linkem Rand der Sidebar (0) bis
|
||||
// rechtem Rand des Flyout-Panels
|
||||
// → voller horizontaler Streifen für diesen Menüpunkt
|
||||
moveHdlr = function ( e ) {
|
||||
var ir = item.getBoundingClientRect();
|
||||
var sr = subMenu.getBoundingClientRect();
|
||||
|
||||
var zoneLeft = 0; // Bildschirmrand links
|
||||
var zoneRight = Math.max( ir.right, sr.right ); // bis Ende Flyout
|
||||
var zoneTop = ir.top; // oberer Rand des li
|
||||
var zoneBottom = ir.bottom; // unterer Rand des li
|
||||
|
||||
var inZone = e.clientX >= zoneLeft &&
|
||||
e.clientX <= zoneRight &&
|
||||
e.clientY >= zoneTop &&
|
||||
e.clientY <= zoneBottom;
|
||||
|
||||
if ( ! inZone ) hideFlyout();
|
||||
};
|
||||
|
||||
document.addEventListener( 'mousemove', moveHdlr );
|
||||
}
|
||||
|
||||
function hideFlyout() {
|
||||
if ( ! isOpen ) return;
|
||||
isOpen = false;
|
||||
item.classList.remove( 'flyout-open' );
|
||||
if ( moveHdlr ) {
|
||||
document.removeEventListener( 'mousemove', moveHdlr );
|
||||
moveHdlr = null;
|
||||
}
|
||||
}
|
||||
|
||||
item.addEventListener( 'mouseenter', showFlyout );
|
||||
|
||||
// Klick-Toggle für Touch / Tastatur
|
||||
var btn = document.createElement( 'button' );
|
||||
btn.className = 'submenu-toggle';
|
||||
btn.setAttribute( 'aria-expanded', 'false' );
|
||||
btn.innerHTML = '<i class="fas fa-chevron-down"></i>';
|
||||
var link = item.querySelector( ':scope > a' );
|
||||
if ( link ) link.insertAdjacentElement( 'afterend', btn );
|
||||
|
||||
btn.addEventListener( 'click', function ( e ) {
|
||||
e.stopPropagation();
|
||||
var open = item.classList.toggle( 'active' );
|
||||
btn.setAttribute( 'aria-expanded', open ? 'true' : 'false' );
|
||||
if ( open ) {
|
||||
subMenu.style.top = item.getBoundingClientRect().top + 'px';
|
||||
item.classList.add( 'flyout-open' );
|
||||
isOpen = true;
|
||||
} else {
|
||||
hideFlyout();
|
||||
}
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
// Early exit wenn kein Toggle da ist
|
||||
if ( ! menuToggle ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle Klassen hinzufügen (Menü öffnen/schließen)
|
||||
menuToggle.addEventListener( 'click', function() {
|
||||
siteNavigation.classList.toggle( 'toggled' );
|
||||
|
||||
// Aria States aktualisieren
|
||||
if ( menuToggle.getAttribute( 'aria-expanded' ) === 'true' ) {
|
||||
menuToggle.setAttribute( 'aria-expanded', 'false' );
|
||||
menuToggle.innerHTML = '<i class="fas fa-bars"></i>';
|
||||
} else {
|
||||
menuToggle.setAttribute( 'aria-expanded', 'true' );
|
||||
menuToggle.innerHTML = '<i class="fas fa-times"></i>';
|
||||
}
|
||||
} );
|
||||
// =========================================================================
|
||||
// CLASSIC / CENTERED / MEGA
|
||||
// =========================================================================
|
||||
var siteNavigation = document.getElementById( 'site-navigation' );
|
||||
if ( ! siteNavigation ) return;
|
||||
|
||||
// Mobile Submenu Toggle (Klick auf Parent-Item öffnet Untermenü)
|
||||
const subMenuParents = siteNavigation.querySelectorAll( '.menu-item-has-children' );
|
||||
var menuToggle = siteNavigation.querySelector( '.menu-toggle' );
|
||||
var subMenuParents = siteNavigation.querySelectorAll( '.menu-item-has-children' );
|
||||
|
||||
subMenuParents.forEach( function( subMenuParent ) {
|
||||
subMenuParent.addEventListener( 'click', function( e ) {
|
||||
// Nur auf Mobil aktivieren (Media Query Check)
|
||||
if ( window.innerWidth <= 992 ) {
|
||||
// Optional: Verhindern, dass der Link geklickt wird, wenn man nur das Menü öffnen will
|
||||
// e.preventDefault();
|
||||
|
||||
// Klasse 'active' umschalten für das CSS Display
|
||||
this.classList.toggle( 'active' );
|
||||
if ( menuToggle ) {
|
||||
menuToggle.addEventListener( 'click', function () {
|
||||
var expanded = siteNavigation.classList.toggle( 'toggled' );
|
||||
this.setAttribute( 'aria-expanded', String( expanded ) );
|
||||
this.innerHTML = expanded ? '<i class="fas fa-times"></i>' : '<i class="fas fa-bars"></i>';
|
||||
} );
|
||||
document.addEventListener( 'click', function ( e ) {
|
||||
if ( siteNavigation.classList.contains( 'toggled' ) && ! siteNavigation.contains( e.target ) ) {
|
||||
siteNavigation.classList.remove( 'toggled' );
|
||||
menuToggle.setAttribute( 'aria-expanded', 'false' );
|
||||
menuToggle.innerHTML = '<i class="fas fa-bars"></i>';
|
||||
}
|
||||
} );
|
||||
window.addEventListener( 'resize', function () {
|
||||
if ( window.innerWidth > 992 ) {
|
||||
siteNavigation.classList.remove( 'toggled' );
|
||||
menuToggle.setAttribute( 'aria-expanded', 'false' );
|
||||
menuToggle.innerHTML = '<i class="fas fa-bars"></i>';
|
||||
subMenuParents.forEach( function ( i ) { i.classList.remove( 'active' ); } );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
subMenuParents.forEach( function ( item ) {
|
||||
var btn = document.createElement( 'button' );
|
||||
btn.className = 'submenu-toggle';
|
||||
btn.setAttribute( 'aria-expanded', 'false' );
|
||||
btn.innerHTML = '<i class="fas fa-chevron-down"></i>';
|
||||
var link = item.querySelector( ':scope > a' );
|
||||
if ( link ) link.insertAdjacentElement( 'afterend', btn );
|
||||
btn.addEventListener( 'click', function ( e ) {
|
||||
e.stopPropagation();
|
||||
var open = item.classList.toggle( 'active' );
|
||||
btn.setAttribute( 'aria-expanded', open ? 'true' : 'false' );
|
||||
} );
|
||||
} );
|
||||
|
||||
document.addEventListener( 'click', function ( e ) {
|
||||
if ( ! e.target.closest( '.menu-item-has-children' ) ) {
|
||||
subMenuParents.forEach( function ( item ) {
|
||||
item.classList.remove( 'active' );
|
||||
var b = item.querySelector( '.submenu-toggle' );
|
||||
if ( b ) b.setAttribute( 'aria-expanded', 'false' );
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
||||
} )();
|
||||
@@ -1,24 +1,25 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Hole den Slider-Container
|
||||
const heroSlider = document.querySelector('.hero-slider');
|
||||
|
||||
// Stelle sicher, dass der Slider auf der Seite existiert
|
||||
if (!heroSlider) {
|
||||
const heroSlider = document.querySelector('.hero-slider');
|
||||
if (!heroSlider) return;
|
||||
|
||||
// BUG-FIX: sliderSettings wird via wp_localize_script gesetzt. Fehlt es
|
||||
// (z.B. wegen Caching oder falschem Enqueue), würde ein ReferenceError
|
||||
// den gesamten Slider-Init abschießen.
|
||||
if (typeof sliderSettings === 'undefined') {
|
||||
console.warn('Minecraft Modern Theme: sliderSettings nicht gefunden. Slider wird nicht initialisiert.');
|
||||
heroSlider.classList.add('swiper-initialized'); // Opacity-Fix trotzdem aufheben
|
||||
return;
|
||||
}
|
||||
|
||||
// Konfiguration für den Slider vorbereiten
|
||||
const swiperConfig = {
|
||||
// Der Effekt ist jetzt fest auf "Überblenden" eingestellt
|
||||
effect: 'fade',
|
||||
fadeEffect: {
|
||||
crossFade: true
|
||||
},
|
||||
|
||||
// Loop-Einstellung ist jetzt DYNAMISCH
|
||||
loop: sliderSettings.loop === '1',
|
||||
|
||||
// Autoplay
|
||||
autoplay: {
|
||||
delay: 5000,
|
||||
disableOnInteraction: false,
|
||||
@@ -26,27 +27,24 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
pauseOnMouseEnter: true,
|
||||
|
||||
// Prüfe, ob die Pfeile NICHT ausgeblendet werden sollen
|
||||
navigation: sliderSettings.hideArrows !== '1' ? {
|
||||
nextEl: '.swiper-button-next',
|
||||
prevEl: '.swiper-button-prev',
|
||||
} : false,
|
||||
|
||||
// Prüfe, ob die Paginierung NICHT ausgeblendet werden soll
|
||||
pagination: sliderSettings.hidePagination !== '1' ? {
|
||||
el: '.swiper-pagination',
|
||||
clickable: true,
|
||||
} : false,
|
||||
|
||||
|
||||
on: {
|
||||
init: function () {
|
||||
setTimeout(() => {
|
||||
setTimeout(function() {
|
||||
heroSlider.classList.add('swiper-initialized');
|
||||
}, 50);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Initialisiere den Slider mit der konfigurierten Optionen
|
||||
new Swiper('.hero-slider', swiperConfig);
|
||||
});
|
||||
@@ -1,32 +1,53 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const html = document.documentElement;
|
||||
const toggle = document.querySelector('.theme-toggle');
|
||||
const iconMoon = toggle.querySelector('.icon-moon');
|
||||
const iconSun = toggle.querySelector('.icon-sun');
|
||||
const toggle = document.querySelector('.theme-toggle');
|
||||
if ( ! toggle ) return;
|
||||
|
||||
const defaultMode = typeof sliderSettings !== 'undefined' ? sliderSettings.defaultMode : 'dark';
|
||||
const saved = localStorage.getItem('themeMode') || defaultMode;
|
||||
const html = document.documentElement;
|
||||
const iconMoon = toggle.querySelector('.icon-moon');
|
||||
const iconSun = toggle.querySelector('.icon-sun');
|
||||
|
||||
if (saved === 'light') {
|
||||
html.classList.add('light-mode');
|
||||
iconMoon.style.display = 'none';
|
||||
iconSun.style.display = 'block';
|
||||
} else {
|
||||
iconMoon.style.display = 'block';
|
||||
iconSun.style.display = 'none';
|
||||
}
|
||||
const defaultMode = typeof sliderSettings !== 'undefined' && sliderSettings.defaultMode
|
||||
? sliderSettings.defaultMode
|
||||
: 'dark';
|
||||
|
||||
toggle.addEventListener('click', function () {
|
||||
html.classList.toggle('light-mode');
|
||||
// Gespeicherten Wert laden oder OS-Schema/Theme-Default als Fallback
|
||||
let saved = localStorage.getItem('themeMode');
|
||||
if ( ! saved ) {
|
||||
saved = ( window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches )
|
||||
? 'light'
|
||||
: defaultMode;
|
||||
}
|
||||
|
||||
if (html.classList.contains('light-mode')) {
|
||||
iconMoon.style.display = 'none';
|
||||
iconSun.style.display = 'block';
|
||||
localStorage.setItem('themeMode', 'light');
|
||||
} else {
|
||||
iconMoon.style.display = 'block';
|
||||
iconSun.style.display = 'none';
|
||||
localStorage.setItem('themeMode', 'dark');
|
||||
}
|
||||
});
|
||||
function applyMode( mode ) {
|
||||
if ( mode === 'light' ) {
|
||||
html.classList.add('light-mode');
|
||||
if ( iconMoon ) iconMoon.style.display = 'none';
|
||||
if ( iconSun ) iconSun.style.display = 'block';
|
||||
} else {
|
||||
html.classList.remove('light-mode');
|
||||
if ( iconMoon ) iconMoon.style.display = 'block';
|
||||
if ( iconSun ) iconSun.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
applyMode( saved );
|
||||
|
||||
// BUG-FIX: Vorher wurde html.classList.toggle() aufgerufen und danach
|
||||
// applyMode() – das hat die Klasse doppelt manipuliert. Jetzt lesen wir
|
||||
// den aktuellen Zustand aus und rufen nur applyMode() auf.
|
||||
toggle.addEventListener('click', function () {
|
||||
const isCurrentlyLight = html.classList.contains('light-mode');
|
||||
const newMode = isCurrentlyLight ? 'dark' : 'light';
|
||||
applyMode( newMode );
|
||||
localStorage.setItem('themeMode', newMode);
|
||||
});
|
||||
|
||||
// Live-Reaktion auf OS-Umschalten (nur wenn keine manuelle Auswahl)
|
||||
if ( window.matchMedia ) {
|
||||
window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', function( e ) {
|
||||
if ( ! localStorage.getItem('themeMode') ) {
|
||||
applyMode( e.matches ? 'light' : 'dark' );
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
26
Minecraft-Modern-Theme/list-posts.php
Normal file
26
Minecraft-Modern-Theme/list-posts.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
$posts = get_posts(array(
|
||||
'post_type' => 'mm_livestream',
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'any',
|
||||
));
|
||||
|
||||
echo "Gefundene Livestream Posts: " . count($posts) . "\n\n";
|
||||
|
||||
foreach ($posts as $p) {
|
||||
echo "ID: {$p->ID}\n";
|
||||
echo "Titel: {$p->post_title}\n";
|
||||
echo "Status: {$p->post_status}\n";
|
||||
|
||||
$profile = get_post_meta($p->ID, '_mm_livestream_url', true);
|
||||
$player = get_post_meta($p->ID, '_mm_livestream_player_url', true);
|
||||
$owner = get_post_meta($p->ID, '_mm_livestream_owner', true);
|
||||
|
||||
echo "Owner: {$owner}\n";
|
||||
echo "Profile: {$profile}\n";
|
||||
echo "Player: {$player}\n";
|
||||
echo "---\n\n";
|
||||
}
|
||||
240
Minecraft-Modern-Theme/page-bewerbung.php
Normal file
240
Minecraft-Modern-Theme/page-bewerbung.php
Normal file
@@ -0,0 +1,240 @@
|
||||
<?php get_header(); ?>
|
||||
|
||||
<div class="container site-main">
|
||||
<div class="content-area">
|
||||
<div class="bewerbung-container">
|
||||
|
||||
<header class="page-header">
|
||||
<h1 class="page-title">
|
||||
<i class="fas fa-clipboard-list"></i>
|
||||
<?php echo esc_html( get_theme_mod('mm_bewerbung_title', __('Bewirb dich bei uns!', 'minecraft-modern-theme')) ); ?>
|
||||
</h1>
|
||||
<p class="page-description">
|
||||
<?php echo esc_html( get_theme_mod('mm_bewerbung_desc', __('Du möchtest Teil unseres Teams werden? Füll das Formular aus und wir melden uns bei dir.', 'minecraft-modern-theme')) ); ?>
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<?php if ( ! get_theme_mod('mm_bewerbung_enabled', false) ) : ?>
|
||||
<div class="bewerbung-disabled">
|
||||
<i class="fas fa-lock"></i>
|
||||
<p><?php _e('Bewerbungen sind momentan nicht möglich.', 'minecraft-modern-theme'); ?></p>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
|
||||
<div id="bewerbung-success" class="bewerbung-success" style="display:none;">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<p id="bewerbung-success-msg"></p>
|
||||
</div>
|
||||
|
||||
<form id="bewerbung-form" class="bewerbung-form" novalidate>
|
||||
<?php wp_nonce_field('mm_bewerbung_nonce', 'mm_bew_nonce_field'); ?>
|
||||
|
||||
<div class="bew-grid">
|
||||
|
||||
<!-- Minecraft Username -->
|
||||
<div class="bew-field">
|
||||
<label for="bew_mc_name" class="bew-label">
|
||||
<i class="fas fa-gamepad"></i>
|
||||
<?php _e('Minecraft Username', 'minecraft-modern-theme'); ?>
|
||||
<span class="bew-required">*</span>
|
||||
</label>
|
||||
<div class="bew-mc-wrap">
|
||||
<input type="text" id="bew_mc_name" name="mc_name"
|
||||
class="bew-input" required maxlength="16"
|
||||
placeholder="z.B. Steve_123"
|
||||
autocomplete="off">
|
||||
<div class="bew-mc-avatar" id="bew-mc-avatar">
|
||||
<img src="" alt="" id="bew-mc-avatar-img" style="display:none;">
|
||||
<i class="fas fa-user" id="bew-mc-avatar-placeholder"></i>
|
||||
</div>
|
||||
</div>
|
||||
<p class="bew-hint"><?php _e('Dein exakter Minecraft-Username (Groß-/Kleinschreibung beachten)', 'minecraft-modern-theme'); ?></p>
|
||||
</div>
|
||||
|
||||
<!-- Discord Username -->
|
||||
<div class="bew-field">
|
||||
<label for="bew_discord" class="bew-label">
|
||||
<i class="fab fa-discord"></i>
|
||||
<?php _e('Discord Username', 'minecraft-modern-theme'); ?>
|
||||
<span class="bew-required">*</span>
|
||||
</label>
|
||||
<input type="text" id="bew_discord" name="discord"
|
||||
class="bew-input" required maxlength="50"
|
||||
placeholder="z.B. Steve#1234 oder @steve">
|
||||
<p class="bew-hint"><?php _e('Dein Discord-Name damit wir dich erreichen können', 'minecraft-modern-theme'); ?></p>
|
||||
</div>
|
||||
|
||||
<!-- Alter -->
|
||||
<div class="bew-field bew-field--small">
|
||||
<label for="bew_alter" class="bew-label">
|
||||
<i class="fas fa-birthday-cake"></i>
|
||||
<?php _e('Alter', 'minecraft-modern-theme'); ?>
|
||||
<span class="bew-required">*</span>
|
||||
</label>
|
||||
<input type="number" id="bew_alter" name="alter"
|
||||
class="bew-input" required min="1" max="99"
|
||||
placeholder="z.B. 16">
|
||||
<?php
|
||||
$min = absint(get_theme_mod('mm_bewerbung_min_alter', 14));
|
||||
if ($min > 0) :
|
||||
?>
|
||||
<p class="bew-hint"><?php printf( __('Mindestalter: %d Jahre', 'minecraft-modern-theme'), $min ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</div><!-- .bew-grid -->
|
||||
|
||||
<!-- Warum mitspielen -->
|
||||
<div class="bew-field">
|
||||
<label for="bew_warum" class="bew-label">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
<?php _e('Warum möchtest du mitspielen?', 'minecraft-modern-theme'); ?>
|
||||
<span class="bew-required">*</span>
|
||||
</label>
|
||||
<textarea id="bew_warum" name="warum" class="bew-textarea" required
|
||||
rows="4" maxlength="1000"
|
||||
placeholder="<?php esc_attr_e('Erzähl uns warum du auf unseren Server möchtest und was du dir davon erhoffst...', 'minecraft-modern-theme'); ?>"></textarea>
|
||||
<div class="bew-char-count"><span id="warum-count">0</span>/1000</div>
|
||||
</div>
|
||||
|
||||
<!-- Erfahrung / Vorstellung -->
|
||||
<div class="bew-field">
|
||||
<label for="bew_erfahrung" class="bew-label">
|
||||
<i class="fas fa-star"></i>
|
||||
<?php _e('Erfahrung & Vorstellung', 'minecraft-modern-theme'); ?>
|
||||
<span class="bew-required">*</span>
|
||||
</label>
|
||||
<textarea id="bew_erfahrung" name="erfahrung" class="bew-textarea" required
|
||||
rows="5" maxlength="2000"
|
||||
placeholder="<?php esc_attr_e('Stell dich kurz vor: Wie lange spielst du Minecraft? Welche Erfahrungen bringst du mit? Was macht dich besonders?', 'minecraft-modern-theme'); ?>"></textarea>
|
||||
<div class="bew-char-count"><span id="erfahrung-count">0</span>/2000</div>
|
||||
</div>
|
||||
|
||||
<!-- Fehler-Meldung -->
|
||||
<div id="bewerbung-error" class="bewerbung-error" style="display:none;">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span id="bewerbung-error-msg"></span>
|
||||
</div>
|
||||
|
||||
<!-- Submit -->
|
||||
<div class="bew-submit-wrap">
|
||||
<button type="submit" id="bewerbung-submit" class="bew-submit-btn">
|
||||
<i class="fas fa-paper-plane"></i>
|
||||
<?php _e('Bewerbung absenden', 'minecraft-modern-theme'); ?>
|
||||
</button>
|
||||
<p class="bew-submit-hint">
|
||||
<i class="fas fa-shield-alt"></i>
|
||||
<?php _e('Mit * markierte Felder sind Pflichtfelder. Deine Daten werden nur intern gespeichert.', 'minecraft-modern-theme'); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div><!-- .bewerbung-container -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var form = document.getElementById('bewerbung-form');
|
||||
var submitBtn = document.getElementById('bewerbung-submit');
|
||||
var errorBox = document.getElementById('bewerbung-error');
|
||||
var errorMsg = document.getElementById('bewerbung-error-msg');
|
||||
var successBox = document.getElementById('bewerbung-success');
|
||||
var successMsg = document.getElementById('bewerbung-success-msg');
|
||||
|
||||
if (!form) return;
|
||||
|
||||
// ── Minecraft Avatar live laden ──
|
||||
var mcInput = document.getElementById('bew_mc_name');
|
||||
var avatarImg = document.getElementById('bew-mc-avatar-img');
|
||||
var avatarIcon = document.getElementById('bew-mc-avatar-placeholder');
|
||||
var avatarTimer;
|
||||
|
||||
if (mcInput) {
|
||||
mcInput.addEventListener('input', function() {
|
||||
clearTimeout(avatarTimer);
|
||||
var val = this.value.trim();
|
||||
if (val.length >= 3) {
|
||||
avatarTimer = setTimeout(function() {
|
||||
var url = 'https://mc-heads.net/avatar/' + encodeURIComponent(val) + '/40';
|
||||
avatarImg.src = url;
|
||||
avatarImg.style.display = 'block';
|
||||
avatarIcon.style.display = 'none';
|
||||
avatarImg.onerror = function() {
|
||||
avatarImg.style.display = 'none';
|
||||
avatarIcon.style.display = 'block';
|
||||
};
|
||||
}, 600);
|
||||
} else {
|
||||
avatarImg.style.display = 'none';
|
||||
avatarIcon.style.display = 'block';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ── Zeichenzähler ──
|
||||
function addCounter(textareaId, countId) {
|
||||
var ta = document.getElementById(textareaId);
|
||||
var ct = document.getElementById(countId);
|
||||
if (!ta || !ct) return;
|
||||
ta.addEventListener('input', function() {
|
||||
ct.textContent = this.value.length;
|
||||
ct.style.color = this.value.length > this.maxLength * 0.9 ? '#ff6b6b' : '';
|
||||
});
|
||||
}
|
||||
addCounter('bew_warum', 'warum-count');
|
||||
addCounter('bew_erfahrung', 'erfahrung-count');
|
||||
|
||||
// ── Formular absenden ──
|
||||
form.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
errorBox.style.display = 'none';
|
||||
|
||||
var nonce = document.getElementById('mm_bew_nonce_field');
|
||||
if (!nonce) return;
|
||||
|
||||
var data = new FormData();
|
||||
data.append('action', 'mm_submit_bewerbung');
|
||||
data.append('nonce', nonce.value);
|
||||
data.append('mc_name', document.getElementById('bew_mc_name').value.trim());
|
||||
data.append('discord', document.getElementById('bew_discord').value.trim());
|
||||
data.append('alter', document.getElementById('bew_alter').value.trim());
|
||||
data.append('warum', document.getElementById('bew_warum').value.trim());
|
||||
data.append('erfahrung', document.getElementById('bew_erfahrung').value.trim());
|
||||
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> <?php echo esc_js(__("Wird gesendet...","minecraft-modern-theme")); ?>';
|
||||
|
||||
fetch('<?php echo esc_url(admin_url("admin-ajax.php")); ?>', {
|
||||
method: 'POST',
|
||||
body: data
|
||||
})
|
||||
.then(function(r){ return r.json(); })
|
||||
.then(function(res) {
|
||||
if (res.success) {
|
||||
form.style.display = 'none';
|
||||
successMsg.textContent = res.data.msg;
|
||||
successBox.style.display = 'flex';
|
||||
window.scrollTo({ top: successBox.offsetTop - 80, behavior: 'smooth' });
|
||||
} else {
|
||||
errorMsg.textContent = res.data.msg;
|
||||
errorBox.style.display = 'flex';
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.innerHTML = '<i class="fas fa-paper-plane"></i> <?php echo esc_js(__("Bewerbung absenden","minecraft-modern-theme")); ?>';
|
||||
window.scrollTo({ top: errorBox.offsetTop - 80, behavior: 'smooth' });
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
errorMsg.textContent = '<?php echo esc_js(__("Verbindungsfehler. Bitte erneut versuchen.","minecraft-modern-theme")); ?>';
|
||||
errorBox.style.display = 'flex';
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.innerHTML = '<i class="fas fa-paper-plane"></i> <?php echo esc_js(__("Bewerbung absenden","minecraft-modern-theme")); ?>';
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
@@ -9,76 +9,145 @@ get_header(); ?>
|
||||
<div id="primary" class="content-area">
|
||||
<main id="main" class="site-main">
|
||||
<div class="custom-auth-container">
|
||||
<?php if (is_user_logged_in()) : ?>
|
||||
<!-- Wenn der Benutzer angemeldet ist, zeige eine Nachricht und einen Logout-Link -->
|
||||
|
||||
<?php if ( is_user_logged_in() ) : ?>
|
||||
|
||||
<!-- Eingeloggt -->
|
||||
<div class="logged-in-message">
|
||||
<h2>Willkommen zurück, <?php echo esc_html(wp_get_current_user()->display_name); ?>!</h2>
|
||||
<p>Du bist bereits angemeldet.</p>
|
||||
<h2><?php printf( __('Willkommen zurück, %s!', 'minecraft-modern-theme'), esc_html( wp_get_current_user()->display_name ) ); ?></h2>
|
||||
<p><?php _e('Du bist bereits angemeldet.', 'minecraft-modern-theme'); ?></p>
|
||||
<p>
|
||||
<a href="<?php echo esc_url(wp_logout_url(home_url())); ?>" class="button">Abmelden</a>
|
||||
<a href="<?php echo esc_url(admin_url()); ?>" class="button">Zum Dashboard</a>
|
||||
<a href="<?php echo esc_url( wp_logout_url( home_url() ) ); ?>" class="button">
|
||||
<i class="fas fa-sign-out-alt"></i> <?php _e('Abmelden', 'minecraft-modern-theme'); ?>
|
||||
</a>
|
||||
<a href="<?php echo esc_url( admin_url() ); ?>" class="button">
|
||||
<i class="fas fa-tachometer-alt"></i> <?php _e('Zum Dashboard', 'minecraft-modern-theme'); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<!-- Wenn der Benutzer nicht angemeldet ist, zeige das Registrierungsformular -->
|
||||
<h1 class="auth-title">Willkommen auf <?php bloginfo('name'); ?></h1>
|
||||
<p class="auth-subtitle">Erstelle deinen Account und werde Teil unserer Community!</p>
|
||||
|
||||
|
||||
<?php elseif ( get_option('users_can_register') ) : ?>
|
||||
|
||||
<!-- Registrierung erlaubt -->
|
||||
<h1 class="auth-title"><?php printf( __('Willkommen auf %s', 'minecraft-modern-theme'), get_bloginfo('name') ); ?></h1>
|
||||
<p class="auth-subtitle"><?php _e('Erstelle deinen Account und werde Teil unserer Community!', 'minecraft-modern-theme'); ?></p>
|
||||
|
||||
<?php
|
||||
// Zeige das Registrierungsformular an
|
||||
$args = array(
|
||||
'echo' => true,
|
||||
'redirect' => home_url('/login/?checkemail=registered'), // Weiterleitung nach der Registrierung
|
||||
// Fehlermeldungen aus der Query-String (z.B. nach gescheiterter Registrierung)
|
||||
if ( isset($_GET['registration']) && $_GET['registration'] === 'disabled' ) : ?>
|
||||
<div class="auth-notice auth-notice-error">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
<?php _e('Die Registrierung ist zurzeit deaktiviert.', 'minecraft-modern-theme'); ?>
|
||||
</div>
|
||||
<?php endif;
|
||||
|
||||
if ( isset($_GET['checkemail']) && $_GET['checkemail'] === 'registered' ) : ?>
|
||||
<div class="auth-notice auth-notice-success">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<?php _e('Registrierung erfolgreich! Prüfe deine E-Mails für das Passwort.', 'minecraft-modern-theme'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
wp_register_form( array(
|
||||
'redirect' => home_url('/login/?checkemail=registered'),
|
||||
'form_id' => 'custom_registerform',
|
||||
'label_username' => __( 'Benutzername' ),
|
||||
'label_email' => __( 'E-Mail-Adresse' ),
|
||||
'label_password' => __( 'Passwort' ),
|
||||
'label_remember' => __( 'Angemeldet bleiben' ),
|
||||
'label_log_in' => __( 'Registrieren' ),
|
||||
'label_username' => __('Benutzername', 'minecraft-modern-theme'),
|
||||
'label_email' => __('E-Mail-Adresse', 'minecraft-modern-theme'),
|
||||
'label_password' => __('Passwort', 'minecraft-modern-theme'),
|
||||
'label_log_in' => __('Registrieren', 'minecraft-modern-theme'),
|
||||
'id_username' => 'user_login',
|
||||
'id_email' => 'user_email',
|
||||
'id_password' => 'user_pass',
|
||||
'id_remember' => 'rememberme',
|
||||
'id_submit' => 'wp-submit',
|
||||
'remember' => true,
|
||||
'value_username' => NULL,
|
||||
'value_remember' => false
|
||||
);
|
||||
wp_register_form($args);
|
||||
'value_username' => isset($_GET['user_login']) ? sanitize_user( $_GET['user_login'] ) : '',
|
||||
) );
|
||||
?>
|
||||
|
||||
|
||||
<div class="login-form-link">
|
||||
<p>Schon hast du einen Account? <a href="<?php echo esc_url(wp_login_url()); ?>">Hier anmelden</a>.</p>
|
||||
<p><?php _e('Schon einen Account?', 'minecraft-modern-theme'); ?>
|
||||
<a href="<?php echo esc_url( wp_login_url() ); ?>">
|
||||
<?php _e('Hier anmelden', 'minecraft-modern-theme'); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<!-- FIX: Registrierung deaktiviert – saubere Fehlermeldung statt kaputter Formulare -->
|
||||
<div class="auth-registration-closed">
|
||||
<div class="auth-icon"><i class="fas fa-lock fa-3x"></i></div>
|
||||
<h2><?php _e('Registrierung geschlossen', 'minecraft-modern-theme'); ?></h2>
|
||||
<p><?php _e('Neue Registrierungen sind derzeit nicht möglich. Bitte schau später wieder vorbei oder kontaktiere einen Administrator.', 'minecraft-modern-theme'); ?></p>
|
||||
<a href="<?php echo esc_url( wp_login_url() ); ?>" class="button">
|
||||
<i class="fas fa-sign-in-alt"></i> <?php _e('Zum Login', 'minecraft-modern-theme'); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Hintergrundbild aus dem Customizer holen und als Inline-CSS ausgeben
|
||||
$auth_bg_image = get_theme_mod('login_background_image');
|
||||
if ($auth_bg_image):
|
||||
?>
|
||||
$auth_bg_image = get_theme_mod('login_background_image');
|
||||
if ( $auth_bg_image ) : ?>
|
||||
<style>
|
||||
body.login, body.login-action-register {
|
||||
body {
|
||||
background-image: url('<?php echo esc_url($auth_bg_image); ?>') !important;
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
}
|
||||
body.login::before, body.login-action-register::before {
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
inset: 0;
|
||||
background: rgba(20, 21, 26, 0.8);
|
||||
z-index: -1;
|
||||
}
|
||||
</style>
|
||||
<?php endif; ?>
|
||||
|
||||
<style>
|
||||
/* Benachrichtigungen */
|
||||
.auth-notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 14px 18px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.auth-notice-success {
|
||||
background: rgba(0, 212, 100, 0.12);
|
||||
border-left: 4px solid #00d464;
|
||||
color: #00d464;
|
||||
}
|
||||
.auth-notice-error {
|
||||
background: rgba(255, 60, 60, 0.1);
|
||||
border-left: 4px solid #ff3c3c;
|
||||
color: #ff3c3c;
|
||||
}
|
||||
|
||||
/* Registrierung geschlossen */
|
||||
.auth-registration-closed {
|
||||
text-align: center;
|
||||
padding: 60px 40px;
|
||||
background: var(--card-bg);
|
||||
border-radius: 10px;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.auth-icon {
|
||||
color: var(--primary-accent, #00d4ff);
|
||||
margin-bottom: 20px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.auth-registration-closed h2 { margin-bottom: 12px; }
|
||||
.auth-registration-closed p { color: var(--text-muted, #a0a0a0); margin-bottom: 24px; }
|
||||
</style>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
107
Minecraft-Modern-Theme/search.php
Normal file
107
Minecraft-Modern-Theme/search.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php get_header(); ?>
|
||||
|
||||
<main id="primary" class="site-main">
|
||||
<div class="container">
|
||||
<div class="content-area">
|
||||
|
||||
<header class="search-header">
|
||||
<div class="archive-type-badge">
|
||||
<i class="fas fa-search"></i> <?php _e('Suchergebnisse', 'minecraft-modern-theme'); ?>
|
||||
</div>
|
||||
<h1 class="archive-title">
|
||||
<?php
|
||||
printf(
|
||||
__('Ergebnisse für: <span class="search-query">%s</span>', 'minecraft-modern-theme'),
|
||||
'<em>' . esc_html( get_search_query() ) . '</em>'
|
||||
);
|
||||
?>
|
||||
</h1>
|
||||
<?php global $wp_query; ?>
|
||||
<p class="search-result-count">
|
||||
<?php printf(
|
||||
_n('%d Ergebnis gefunden', '%d Ergebnisse gefunden', $wp_query->found_posts, 'minecraft-modern-theme'),
|
||||
$wp_query->found_posts
|
||||
); ?>
|
||||
</p>
|
||||
|
||||
<!-- Suchformular zum Verfeinern -->
|
||||
<div class="search-refine">
|
||||
<?php get_search_form(); ?>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<?php if ( have_posts() ) : ?>
|
||||
|
||||
<div class="archive-posts-grid">
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class('post archive-post-card'); ?>>
|
||||
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<div class="archive-card-thumb">
|
||||
<a href="<?php the_permalink(); ?>">
|
||||
<?php the_post_thumbnail('medium_large', array('loading' => 'lazy')); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="archive-card-body">
|
||||
|
||||
<div class="archive-card-type">
|
||||
<?php
|
||||
$pt = get_post_type_object( get_post_type() );
|
||||
echo '<span class="post-type-badge"><i class="fas fa-file-alt"></i> ' . esc_html($pt->labels->singular_name) . '</span>';
|
||||
?>
|
||||
</div>
|
||||
|
||||
<h2 class="archive-card-title">
|
||||
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||||
</h2>
|
||||
|
||||
<div class="archive-card-meta">
|
||||
<span><i class="fas fa-calendar-alt"></i> <?php echo esc_html( get_the_date() ); ?></span>
|
||||
<span><i class="fas fa-user"></i> <?php the_author(); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="archive-card-excerpt">
|
||||
<?php the_excerpt(); ?>
|
||||
</div>
|
||||
|
||||
<a href="<?php the_permalink(); ?>" class="archive-card-read-more">
|
||||
<?php _e('Zum Beitrag', 'minecraft-modern-theme'); ?> <i class="fas fa-arrow-right"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="archive-pagination">
|
||||
<?php
|
||||
the_posts_pagination( array(
|
||||
'mid_size' => 2,
|
||||
'prev_text' => '<i class="fas fa-chevron-left"></i> ' . __('Zurück', 'minecraft-modern-theme'),
|
||||
'next_text' => __('Weiter', 'minecraft-modern-theme') . ' <i class="fas fa-chevron-right"></i>',
|
||||
) );
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<div class="no-posts-found">
|
||||
<i class="fas fa-search fa-3x" style="opacity:0.3; margin-bottom:20px;"></i>
|
||||
<h2><?php _e('Keine Ergebnisse gefunden', 'minecraft-modern-theme'); ?></h2>
|
||||
<p><?php printf( __('Deine Suche nach <strong>%s</strong> hat keine Treffer ergeben.', 'minecraft-modern-theme'), esc_html( get_search_query() ) ); ?></p>
|
||||
<p><?php _e('Versuche es mit anderen Suchbegriffen oder schau dir unsere letzten Beiträge an.', 'minecraft-modern-theme'); ?></p>
|
||||
<?php get_search_form(); ?>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
23
Minecraft-Modern-Theme/searchform.php
Normal file
23
Minecraft-Modern-Theme/searchform.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
// Eindeutige ID für jede Instanz des Suchformulars
|
||||
$search_id = 'search-field-' . uniqid();
|
||||
?>
|
||||
<form role="search" method="get" class="search-form" action="<?php echo esc_url( home_url('/') ); ?>">
|
||||
<div class="search-form-inner">
|
||||
<label for="<?php echo esc_attr( $search_id ); ?>" class="screen-reader-text">
|
||||
<?php _e('Suche nach:', 'minecraft-modern-theme'); ?>
|
||||
</label>
|
||||
<input
|
||||
type="search"
|
||||
id="<?php echo esc_attr( $search_id ); ?>"
|
||||
class="search-field"
|
||||
placeholder="<?php esc_attr_e('Suche...', 'minecraft-modern-theme'); ?>"
|
||||
value="<?php echo esc_attr( get_search_query() ); ?>"
|
||||
name="s"
|
||||
autocomplete="off"
|
||||
>
|
||||
<button type="submit" class="search-submit" aria-label="<?php esc_attr_e('Suchen', 'minecraft-modern-theme'); ?>">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,19 +1,179 @@
|
||||
<?php get_header(); ?>
|
||||
|
||||
<?php
|
||||
// Sidebar-Einstellungen aus dem Customizer
|
||||
$sidebar_enabled = get_theme_mod( 'single_sidebar_enabled', true );
|
||||
$sidebar_position = get_theme_mod( 'single_sidebar_position', 'right' );
|
||||
$has_sidebar = $sidebar_enabled && is_active_sidebar( 'single-post-sidebar' );
|
||||
|
||||
$layout_class = $has_sidebar
|
||||
? 'single-layout with-sidebar sidebar-' . esc_attr( $sidebar_position )
|
||||
: 'single-layout';
|
||||
?>
|
||||
|
||||
<main id="primary" class="site-main">
|
||||
<div class="container">
|
||||
<div class="content-area">
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class('post'); ?>>
|
||||
<div class="post-content">
|
||||
<h1 class="post-title"><?php the_title(); ?></h1>
|
||||
<div class="post-entry">
|
||||
<?php the_content(); ?>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<div class="<?php echo esc_attr( $layout_class ); ?>">
|
||||
|
||||
<?php if ( $has_sidebar && $sidebar_position === 'left' ) : ?>
|
||||
<aside class="single-sidebar">
|
||||
<?php minecraft_modern_render_single_sidebar(); ?>
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="single-main-content">
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class('post single-post'); ?>>
|
||||
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<div class="post-hero-image">
|
||||
<?php the_post_thumbnail( 'large' ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="post-content">
|
||||
|
||||
<?php if ( get_theme_mod( 'single_show_breadcrumb', true ) ) : ?>
|
||||
<nav class="breadcrumb" aria-label="Breadcrumb">
|
||||
<a href="<?php echo esc_url( home_url('/') ); ?>"><?php _e('Startseite', 'minecraft-modern-theme'); ?></a>
|
||||
<span class="breadcrumb-sep"><i class="fas fa-chevron-right"></i></span>
|
||||
<?php
|
||||
$cats = get_the_category();
|
||||
if ( $cats ) :
|
||||
$cat = $cats[0];
|
||||
?>
|
||||
<a href="<?php echo esc_url( get_category_link( $cat->term_id ) ); ?>"><?php echo esc_html( $cat->name ); ?></a>
|
||||
<span class="breadcrumb-sep"><i class="fas fa-chevron-right"></i></span>
|
||||
<?php endif; ?>
|
||||
<span class="breadcrumb-current"><?php the_title(); ?></span>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
|
||||
<h1 class="post-title"><?php the_title(); ?></h1>
|
||||
|
||||
<div class="post-meta">
|
||||
<span class="post-meta-item post-author">
|
||||
<?php echo get_avatar( get_the_author_meta('ID'), 24, '', '', array('class' => 'author-avatar') ); ?>
|
||||
<a href="<?php echo esc_url( get_author_posts_url( get_the_author_meta('ID') ) ); ?>"><?php the_author(); ?></a>
|
||||
</span>
|
||||
<span class="post-meta-item post-date">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
<time datetime="<?php echo esc_attr( get_the_date('c') ); ?>"><?php echo esc_html( get_the_date() ); ?></time>
|
||||
</span>
|
||||
<?php if ( get_the_modified_date() !== get_the_date() ) : ?>
|
||||
<span class="post-meta-item post-updated">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
<?php printf( __('Aktualisiert: %s', 'minecraft-modern-theme'), '<time datetime="' . esc_attr( get_the_modified_date('c') ) . '">' . esc_html( get_the_modified_date() ) . '</time>' ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
$content = get_post_field( 'post_content', get_the_ID() );
|
||||
$word_count = str_word_count( strip_tags( $content ) );
|
||||
$read_time = max( 1, ceil( $word_count / 200 ) );
|
||||
?>
|
||||
<span class="post-meta-item post-read-time">
|
||||
<i class="fas fa-clock"></i>
|
||||
<?php printf( _n('%d Min. Lesezeit', '%d Min. Lesezeit', $read_time, 'minecraft-modern-theme'), $read_time ); ?>
|
||||
</span>
|
||||
<?php if ( comments_open() ) : ?>
|
||||
<span class="post-meta-item post-comments">
|
||||
<i class="fas fa-comment"></i>
|
||||
<a href="#comments"><?php comments_number( __('0 Kommentare', 'minecraft-modern-theme'), __('1 Kommentar', 'minecraft-modern-theme'), __('% Kommentare', 'minecraft-modern-theme') ); ?></a>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php $cats = get_the_category(); if ( $cats ) : ?>
|
||||
<div class="post-categories-top">
|
||||
<?php foreach ( $cats as $cat ) : ?>
|
||||
<a href="<?php echo esc_url( get_category_link( $cat->term_id ) ); ?>" class="post-category-badge"><?php echo esc_html( $cat->name ); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="post-entry">
|
||||
<?php the_content(); ?>
|
||||
</div>
|
||||
|
||||
<footer class="post-footer">
|
||||
<?php $tags = get_the_tags(); if ( $tags ) : ?>
|
||||
<div class="post-tags">
|
||||
<i class="fas fa-tags"></i>
|
||||
<?php foreach ( $tags as $tag ) : ?>
|
||||
<a href="<?php echo esc_url( get_tag_link( $tag->term_id ) ); ?>" class="post-tag">#<?php echo esc_html( $tag->name ); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<nav class="post-navigation" aria-label="<?php esc_attr_e('Beitrag Navigation', 'minecraft-modern-theme'); ?>">
|
||||
<?php $prev_post = get_previous_post(); $next_post = get_next_post(); ?>
|
||||
<?php if ( $prev_post ) : ?>
|
||||
<a href="<?php echo esc_url( get_permalink( $prev_post->ID ) ); ?>" class="post-nav-link post-nav-prev">
|
||||
<span class="post-nav-label"><i class="fas fa-arrow-left"></i> <?php _e('Vorheriger Beitrag', 'minecraft-modern-theme'); ?></span>
|
||||
<span class="post-nav-title"><?php echo esc_html( get_the_title( $prev_post->ID ) ); ?></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if ( $next_post ) : ?>
|
||||
<a href="<?php echo esc_url( get_permalink( $next_post->ID ) ); ?>" class="post-nav-link post-nav-next">
|
||||
<span class="post-nav-label"><?php _e('Nächster Beitrag', 'minecraft-modern-theme'); ?> <i class="fas fa-arrow-right"></i></span>
|
||||
<span class="post-nav-title"><?php echo esc_html( get_the_title( $next_post->ID ) ); ?></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</nav>
|
||||
</footer>
|
||||
|
||||
</div><!-- .post-content -->
|
||||
</article>
|
||||
|
||||
<!-- Related Posts -->
|
||||
<?php if ( get_theme_mod( 'single_show_related_posts', true ) ) : ?>
|
||||
<?php
|
||||
$current_cats = wp_get_post_categories( get_the_ID() );
|
||||
if ( $current_cats ) :
|
||||
$related = new WP_Query( array(
|
||||
'category__in' => $current_cats,
|
||||
'post__not_in' => array( get_the_ID() ),
|
||||
'posts_per_page' => 3,
|
||||
'orderby' => 'rand',
|
||||
) );
|
||||
if ( $related->have_posts() ) : ?>
|
||||
<section class="related-posts">
|
||||
<h3 class="related-posts-title">
|
||||
<i class="fas fa-layer-group"></i> <?php _e('Ähnliche Beiträge', 'minecraft-modern-theme'); ?>
|
||||
</h3>
|
||||
<div class="related-posts-grid">
|
||||
<?php while ( $related->have_posts() ) : $related->the_post(); ?>
|
||||
<article class="related-post-card">
|
||||
<?php if ( has_post_thumbnail() ) : ?>
|
||||
<a href="<?php the_permalink(); ?>" class="related-post-thumb">
|
||||
<?php the_post_thumbnail('medium', array('loading' => 'lazy')); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<div class="related-post-info">
|
||||
<h4 class="related-post-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h4>
|
||||
<span class="related-post-date"><i class="fas fa-calendar-alt"></i> <?php echo esc_html( get_the_date() ); ?></span>
|
||||
</div>
|
||||
</article>
|
||||
<?php endwhile; wp_reset_postdata(); ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif;
|
||||
endif; ?>
|
||||
<?php endif; // single_show_related_posts ?>
|
||||
|
||||
<?php comments_template(); ?>
|
||||
|
||||
<?php endwhile; ?>
|
||||
</div><!-- .single-main-content -->
|
||||
|
||||
<?php if ( $has_sidebar && $sidebar_position === 'right' ) : ?>
|
||||
<aside class="single-sidebar">
|
||||
<?php minecraft_modern_render_single_sidebar(); ?>
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
|
||||
</div><!-- .single-layout -->
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
98
Minecraft-Modern-Theme/test-api-key.php
Normal file
98
Minecraft-Modern-Theme/test-api-key.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* Test-Skript für YouTube API Key
|
||||
* Führe aus: php test-api-key.php
|
||||
*/
|
||||
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
echo "=== YouTube API Key Test ===\n\n";
|
||||
|
||||
// Hole API Key aus Customizer
|
||||
$api_key = get_theme_mod('youtube_api_key', '');
|
||||
$api_key_from_config = defined('YOUTUBE_API_KEY') ? YOUTUBE_API_KEY : '';
|
||||
|
||||
echo "API Key aus Customizer: " . ($api_key ? substr($api_key, 0, 10) . '...' : 'NICHT GESETZT') . "\n";
|
||||
echo "API Key aus wp-config: " . ($api_key_from_config ? substr($api_key_from_config, 0, 10) . '...' : 'NICHT GESETZT') . "\n\n";
|
||||
|
||||
$active_key = $api_key ? $api_key : $api_key_from_config;
|
||||
|
||||
if (empty($active_key)) {
|
||||
echo "⚠️ Kein API Key gefunden!\n\n";
|
||||
echo "So fügst du einen API Key hinzu:\n";
|
||||
echo "1. Gehe zu: Design → Customizer → Video & Livestream\n";
|
||||
echo "2. Trage dort deinen YouTube API Key ein\n";
|
||||
echo "3. Klicke auf 'Veröffentlichen'\n\n";
|
||||
echo "Oder füge in wp-config.php hinzu:\n";
|
||||
echo "define('YOUTUBE_API_KEY', 'DEIN_KEY_HIER');\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
echo "✓ API Key gefunden: " . substr($active_key, 0, 15) . "...\n\n";
|
||||
|
||||
// Test: Video-Status abfragen
|
||||
$test_video_id = 'ithwtp7aJlM'; // NashvilleBirdCam Stream
|
||||
|
||||
echo "Teste API Key mit Video ID: $test_video_id\n\n";
|
||||
|
||||
$url = sprintf(
|
||||
'https://www.googleapis.com/youtube/v3/videos?id=%s&part=snippet,liveStreamingDetails&key=%s',
|
||||
rawurlencode($test_video_id),
|
||||
rawurlencode($active_key)
|
||||
);
|
||||
|
||||
echo "API Request: " . substr($url, 0, 100) . "...\n\n";
|
||||
|
||||
$response = wp_remote_get($url, array('timeout' => 10));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
echo "❌ Fehler beim API Request: " . $response->get_error_message() . "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$status_code = wp_remote_retrieve_response_code($response);
|
||||
echo "HTTP Status: $status_code\n\n";
|
||||
|
||||
if ($status_code !== 200) {
|
||||
echo "❌ API Fehler (Status $status_code)\n";
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if (isset($data['error']['message'])) {
|
||||
echo "Fehlermeldung: " . $data['error']['message'] . "\n";
|
||||
|
||||
if (strpos($data['error']['message'], 'API key not valid') !== false) {
|
||||
echo "\n⚠️ Der API Key ist ungültig!\n";
|
||||
echo "Bitte überprüfe den Key im Customizer oder erstelle einen neuen.\n";
|
||||
}
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if (empty($data['items'])) {
|
||||
echo "❌ Video nicht gefunden oder nicht verfügbar\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
echo "✅ API Key funktioniert!\n\n";
|
||||
|
||||
$video = $data['items'][0];
|
||||
$title = $video['snippet']['title'] ?? 'Unbekannt';
|
||||
$state = $video['snippet']['liveBroadcastContent'] ?? 'none';
|
||||
|
||||
echo "Video Titel: $title\n";
|
||||
echo "Live Status: $state\n";
|
||||
|
||||
if ($state === 'live') {
|
||||
echo "🔴 Das Video ist LIVE!\n";
|
||||
} elseif ($state === 'upcoming') {
|
||||
echo "⏰ Das Video ist geplant (noch nicht live)\n";
|
||||
} else {
|
||||
echo "⚫ Das Video ist NICHT live (aufgezeichnet oder offline)\n";
|
||||
}
|
||||
|
||||
echo "\n=== Test erfolgreich ===\n";
|
||||
80
Minecraft-Modern-Theme/test-api-live.php
Normal file
80
Minecraft-Modern-Theme/test-api-live.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* Test das neue API-basierte Livestream-System
|
||||
*/
|
||||
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
echo "=== Test API-basiertes Livestream-System ===\n\n";
|
||||
|
||||
// 1. Check Customizer Settings
|
||||
$api_key = get_theme_mod('youtube_api_key');
|
||||
$handle = get_theme_mod('youtube_livestream_handle', '@DreamTripspk');
|
||||
|
||||
echo "1. Customizer Settings:\n";
|
||||
echo " API Key: " . ($api_key ? "SET (" . strlen($api_key) . " chars)" : "NOT SET") . "\n";
|
||||
echo " Handle: " . ($handle ? $handle : "NOT SET") . "\n\n";
|
||||
|
||||
if (empty($api_key)) {
|
||||
echo "⚠️ WARNUNG: Kein API Key gesetzt. Ohne API Key funktioniert das neue System nicht!\n";
|
||||
echo " Bitte im Customizer unter 'Video & Livestream' einen YouTube API Key eintragen.\n\n";
|
||||
}
|
||||
|
||||
if (empty($handle)) {
|
||||
echo "⚠️ WARNUNG: Kein Handle gesetzt.\n";
|
||||
echo " Bitte im Customizer unter 'Video & Livestream' einen YouTube @Handle eintragen.\n\n";
|
||||
}
|
||||
|
||||
// 2. Test Channel ID Resolution
|
||||
if (!empty($handle)) {
|
||||
echo "2. Channel ID Resolution:\n";
|
||||
$channel_id = mm_get_channel_id_by_handle($handle);
|
||||
if ($channel_id) {
|
||||
echo " ✓ Channel ID: $channel_id\n\n";
|
||||
|
||||
// 3. Test Live Video Detection
|
||||
echo "3. Live Video Detection:\n";
|
||||
$live_id = mm_get_youtube_live_id_from_handle($handle);
|
||||
if ($live_id) {
|
||||
echo " ✓ LIVE! Video ID: $live_id\n";
|
||||
echo " ✓ URL: https://www.youtube.com/watch?v=$live_id\n\n";
|
||||
} else {
|
||||
echo " ✗ Nicht live oder keine Videos gefunden\n\n";
|
||||
}
|
||||
} else {
|
||||
echo " ✗ Channel ID konnte nicht ermittelt werden\n";
|
||||
echo " Prüfe ob der Handle korrekt ist und API Key gültig ist\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Test mm_video_get_livestream_groups()
|
||||
echo "4. Test mm_video_get_livestream_groups():\n";
|
||||
$groups = mm_video_get_livestream_groups();
|
||||
echo " Debug: Returned value type: " . gettype($groups) . "\n";
|
||||
echo " Debug: Is array: " . (is_array($groups) ? 'yes' : 'no') . "\n";
|
||||
echo " Debug: Count: " . count($groups) . "\n";
|
||||
if (!empty($groups)) {
|
||||
echo " ✓ " . count($groups) . " Gruppe(n) gefunden\n";
|
||||
foreach ($groups as $i => $group) {
|
||||
echo " Gruppe $i:\n";
|
||||
echo " - Title: " . $group['title'] . "\n";
|
||||
echo " - Platform: " . $group['platform'] . "\n";
|
||||
echo " - YT ID: " . $group['yt_id'] . "\n";
|
||||
echo " - Handle: " . $group['handle'] . "\n";
|
||||
}
|
||||
} else {
|
||||
echo " ✗ Keine Gruppen (kein Live-Stream aktiv)\n";
|
||||
echo " Debug: Testing internal call...\n";
|
||||
$test_handle = get_theme_mod('youtube_livestream_handle', '');
|
||||
echo " Debug: Handle from theme_mod: '" . $test_handle . "'\n";
|
||||
$test_live_id = mm_get_youtube_live_id_from_handle($test_handle);
|
||||
echo " Debug: Live ID from internal call: '" . ($test_live_id ? $test_live_id : 'false') . "'\n";
|
||||
}
|
||||
|
||||
echo "\n=== Test Complete ===\n";
|
||||
echo "\nNächste Schritte:\n";
|
||||
echo "1. Gehe zu Design → Customizer → Video & Livestream\n";
|
||||
echo "2. Trage deinen YouTube API Key ein\n";
|
||||
echo "3. Trage deinen @Handle ein (z.B. @DreamTripspk)\n";
|
||||
echo "4. Speichern und Seite neu laden\n";
|
||||
29
Minecraft-Modern-Theme/test-direct-url.php
Normal file
29
Minecraft-Modern-Theme/test-direct-url.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
echo "=== Testing Direct Stream URL ===\n\n";
|
||||
|
||||
$profile_url = 'https://www.youtube.com/@NashvilleBirdCam';
|
||||
$player_url = 'https://www.youtube.com/watch?v=ithwtp7aJlM';
|
||||
$youtube_channel_id = 'UClOWy1mPxNB1D3cpmmxqGEg';
|
||||
|
||||
echo "Profile URL: $profile_url\n";
|
||||
echo "Player URL: $player_url\n";
|
||||
echo "Channel ID: $youtube_channel_id\n\n";
|
||||
|
||||
$data = mm_video_get_livestream_data($profile_url, $player_url, $youtube_channel_id);
|
||||
|
||||
echo "=== Result ===\n";
|
||||
print_r($data);
|
||||
|
||||
echo "\n=== Key Fields ===\n";
|
||||
echo "Platform: " . ($data['platform'] ?? 'NOT SET') . "\n";
|
||||
echo "Video ID: " . ($data['video_id'] ?? 'NOT SET') . "\n";
|
||||
echo "Embed URL: " . ($data['embed_url'] ?? 'NOT SET') . "\n";
|
||||
|
||||
if (!empty($data['video_id']) && !empty($data['embed_url'])) {
|
||||
echo "\n✓ SUCCESS - Both video_id and embed_url are set!\n";
|
||||
} else {
|
||||
echo "\n✗ FAILURE - Missing video_id or embed_url\n";
|
||||
}
|
||||
72
Minecraft-Modern-Theme/test-extraction.php
Normal file
72
Minecraft-Modern-Theme/test-extraction.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
echo "=== Testing YouTube Video ID Extraction ===\n\n";
|
||||
|
||||
$url = 'https://www.youtube.com/@NashvilleBirdCam/streams';
|
||||
echo "Fetching: $url\n\n";
|
||||
|
||||
$response = wp_remote_get($url, 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',
|
||||
),
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
echo "ERROR: " . $response->get_error_message() . "\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
echo "Response size: " . strlen($body) . " bytes\n\n";
|
||||
|
||||
// Test all patterns
|
||||
$patterns = array(
|
||||
'watchEndpoint' => '/"watchEndpoint":\{"videoId":"([A-Za-z0-9_-]{11})"/i',
|
||||
'videoId with isLiveNow' => '/"videoId":"([A-Za-z0-9_-]{11})"[^}]*"isLiveNow":true/i',
|
||||
'URL with u0026' => '/\/watch\?v=([A-Za-z0-9_-]{11})\\u0026/i',
|
||||
'URL standard' => '/\/watch\?v=([A-Za-z0-9_-]{11})/i',
|
||||
'LIVE_NOW label' => '/LIVE_NOW.*?"videoId":"([A-Za-z0-9_-]{11})"/is',
|
||||
);
|
||||
|
||||
echo "Testing patterns:\n";
|
||||
foreach ($patterns as $name => $pattern) {
|
||||
if (preg_match($pattern, $body, $m)) {
|
||||
echo "✓ $name: MATCH - video_id = " . $m[1] . "\n";
|
||||
} else {
|
||||
echo "✗ $name: NO MATCH\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n=== Calling mm_video_extract_youtube_live_video_id ===\n";
|
||||
$video_id = mm_video_extract_youtube_live_video_id($body);
|
||||
if ($video_id) {
|
||||
echo "✓ Extracted video_id: $video_id\n";
|
||||
} else {
|
||||
echo "✗ NO video_id extracted!\n";
|
||||
}
|
||||
|
||||
// Show some context
|
||||
echo "\n=== Searching for 'watchEndpoint' in response ===\n";
|
||||
if (preg_match('/"watchEndpoint":\{"videoId":"[^"]+"/i', $body, $context)) {
|
||||
echo "Found: " . $context[0] . "\n";
|
||||
} else {
|
||||
echo "Not found\n";
|
||||
}
|
||||
|
||||
echo "\n=== Searching for 'PAmS12qbdzA' (known live video ID) ===\n";
|
||||
if (strpos($body, 'PAmS12qbdzA') !== false) {
|
||||
echo "✓ Found PAmS12qbdzA in response\n";
|
||||
|
||||
// Get context around it
|
||||
$pos = strpos($body, 'PAmS12qbdzA');
|
||||
$start = max(0, $pos - 100);
|
||||
$context = substr($body, $start, 250);
|
||||
echo "Context: " . htmlspecialchars($context) . "\n";
|
||||
} else {
|
||||
echo "✗ PAmS12qbdzA NOT found in response\n";
|
||||
}
|
||||
52
Minecraft-Modern-Theme/test-filter.php
Normal file
52
Minecraft-Modern-Theme/test-filter.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
echo "=== Debug: Livestream Filtering ===\n\n";
|
||||
|
||||
$args = array(
|
||||
'post_type' => 'mm_livestream',
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'publish',
|
||||
);
|
||||
|
||||
$query = new WP_Query($args);
|
||||
|
||||
if ($query->have_posts()) {
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$post_id = get_the_ID();
|
||||
|
||||
$profile_url = get_post_meta($post_id, '_mm_livestream_url', true);
|
||||
$player_url = get_post_meta($post_id, '_mm_livestream_player_url', true);
|
||||
$youtube_channel_id = get_post_meta($post_id, '_mm_livestream_youtube_channel_id', true);
|
||||
$owner = get_post_meta($post_id, '_mm_livestream_owner', true);
|
||||
|
||||
echo "Post #$post_id: " . get_the_title() . "\n";
|
||||
echo " Owner: $owner\n";
|
||||
echo " Profile: $profile_url\n";
|
||||
echo " Player: $player_url\n";
|
||||
echo " Channel ID: $youtube_channel_id\n";
|
||||
|
||||
$stream = mm_video_get_livestream_data($profile_url, $player_url, $youtube_channel_id);
|
||||
|
||||
echo " Platform: " . $stream['platform'] . "\n";
|
||||
echo " Video ID: " . ($stream['video_id'] ?? 'EMPTY') . "\n";
|
||||
echo " Embed URL: " . ($stream['embed_url'] ?? 'EMPTY') . "\n";
|
||||
|
||||
if ($stream['platform'] === 'youtube') {
|
||||
$video_id = $stream['video_id'] ?? '';
|
||||
if ($video_id) {
|
||||
$is_live = mm_video_check_youtube_live_status($video_id);
|
||||
echo " Live Status Check: " . ($is_live ? 'LIVE ✓' : 'NOT LIVE ✗') . "\n";
|
||||
} else {
|
||||
echo " Live Status Check: SKIPPED (no video_id)\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
}
|
||||
wp_reset_postdata();
|
||||
} else {
|
||||
echo "No livestream posts found!\n";
|
||||
}
|
||||
47
Minecraft-Modern-Theme/test-live.php
Normal file
47
Minecraft-Modern-Theme/test-live.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
$urls = array(
|
||||
'https://www.youtube.com/@NashvilleBirdCam/live',
|
||||
'https://www.youtube.com/channel/UClOWy1mPxNB1D3cpmmxqGEg/live',
|
||||
);
|
||||
|
||||
foreach ($urls as $url) {
|
||||
echo "\n=== Testing: $url ===\n";
|
||||
|
||||
$response = wp_remote_get($url, 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',
|
||||
),
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
echo "ERROR: " . $response->get_error_message() . "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
echo "Response size: " . strlen($body) . " bytes\n";
|
||||
|
||||
if (strpos($body, 'PAmS12qbdzA') !== false) {
|
||||
echo "✓ Found PAmS12qbdzA\n";
|
||||
|
||||
$pos = strpos($body, 'PAmS12qbdzA');
|
||||
$start = max(0, $pos - 150);
|
||||
$context = substr($body, $start, 350);
|
||||
echo "Context:\n" . htmlspecialchars($context) . "\n";
|
||||
} else {
|
||||
echo "✗ PAmS12qbdzA NOT found\n";
|
||||
}
|
||||
|
||||
$video_id = mm_video_extract_youtube_live_video_id($body);
|
||||
if ($video_id) {
|
||||
echo "✓ Extracted video_id: $video_id\n";
|
||||
} else {
|
||||
echo "✗ NO video_id extracted\n";
|
||||
}
|
||||
}
|
||||
69
Minecraft-Modern-Theme/test-render.php
Normal file
69
Minecraft-Modern-Theme/test-render.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
echo "=== Testing Livestream Rendering ===\n\n";
|
||||
|
||||
// Query für Videos mit Livestream
|
||||
$args = array(
|
||||
'post_type' => 'video',
|
||||
'posts_per_page' => 2,
|
||||
'meta_query' => array(
|
||||
array(
|
||||
'key' => 'video_is_livestream',
|
||||
'value' => '1',
|
||||
'compare' => '='
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$query = new WP_Query($args);
|
||||
|
||||
if ($query->have_posts()) {
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
|
||||
$post_id = get_the_ID();
|
||||
$profile_url = get_post_meta($post_id, 'video_livestream_profile_url', true);
|
||||
$player_url = get_post_meta($post_id, 'video_livestream_player_url', true);
|
||||
$youtube_channel_id = get_post_meta($post_id, 'video_youtube_channel_id', true);
|
||||
|
||||
echo "Post ID: $post_id\n";
|
||||
echo "Title: " . get_the_title() . "\n";
|
||||
echo "Profile URL: $profile_url\n";
|
||||
echo "Player URL: $player_url\n";
|
||||
echo "YouTube Channel ID: $youtube_channel_id\n";
|
||||
|
||||
$data = mm_video_get_livestream_data($profile_url, $player_url, $youtube_channel_id);
|
||||
|
||||
echo "\nLivestream Data:\n";
|
||||
echo " Platform: " . ($data['platform'] ?? 'N/A') . "\n";
|
||||
echo " Video ID: " . ($data['video_id'] ?? 'EMPTY') . "\n";
|
||||
echo " Embed URL: " . ($data['embed_url'] ?? 'EMPTY') . "\n";
|
||||
echo " Profile URL: " . ($data['profile_url'] ?? 'N/A') . "\n";
|
||||
|
||||
echo "\n" . str_repeat("-", 80) . "\n\n";
|
||||
}
|
||||
wp_reset_postdata();
|
||||
} else {
|
||||
echo "No livestream videos found.\n";
|
||||
}
|
||||
|
||||
// Test the groups
|
||||
echo "\n=== Testing Group Generation ===\n\n";
|
||||
$groups = mm_video_get_livestream_groups();
|
||||
echo "Found " . count($groups) . " groups\n\n";
|
||||
|
||||
foreach ($groups as $idx => $group) {
|
||||
echo "Group $idx: " . $group['owner'] . "\n";
|
||||
echo " Items: " . count($group['items']) . "\n";
|
||||
|
||||
foreach ($group['items'] as $item_idx => $item) {
|
||||
echo " Item $item_idx:\n";
|
||||
echo " Title: " . $item['title'] . "\n";
|
||||
echo " Platform: " . $item['stream']['platform'] . "\n";
|
||||
echo " Video ID: " . ($item['stream']['video_id'] ?? 'EMPTY') . "\n";
|
||||
echo " Embed URL: " . (empty($item['stream']['embed_url']) ? 'EMPTY' : 'SET') . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
79
Minecraft-Modern-Theme/test-video-id.php
Normal file
79
Minecraft-Modern-Theme/test-video-id.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* Test Video ID Detection for specific YouTube video
|
||||
*/
|
||||
|
||||
// WordPress laden
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
$video_id = 'kWRhLLbLFE0';
|
||||
|
||||
echo "=== Testing Video ID: $video_id ===\n\n";
|
||||
|
||||
// 1. Check if video is live
|
||||
echo "1. Checking Live Status:\n";
|
||||
$live_status = mm_video_check_youtube_live_status($video_id);
|
||||
echo " Result: " . ($live_status ? "LIVE" : "NOT LIVE") . "\n\n";
|
||||
|
||||
// 2. Try to fetch video info from YouTube
|
||||
echo "2. Fetching YouTube HTML:\n";
|
||||
$url = "https://www.youtube.com/watch?v=" . $video_id;
|
||||
$response = wp_remote_get($url);
|
||||
if (!is_wp_error($response)) {
|
||||
$html = wp_remote_retrieve_body($response);
|
||||
|
||||
// Check for live indicators
|
||||
if (stripos($html, '"isLiveContent":true') !== false) {
|
||||
echo " ✓ isLiveContent found\n";
|
||||
}
|
||||
if (stripos($html, '"isLive":true') !== false) {
|
||||
echo " ✓ isLive found\n";
|
||||
}
|
||||
if (stripos($html, '"isLiveNow":true') !== false) {
|
||||
echo " ✓ isLiveNow found\n";
|
||||
}
|
||||
if (stripos($html, 'LIVE_NOW') !== false) {
|
||||
echo " ✓ LIVE_NOW badge found\n";
|
||||
}
|
||||
|
||||
// Check for DVR
|
||||
if (stripos($html, '"isLiveDvrEnabled":true') !== false) {
|
||||
echo " ✓ DVR enabled\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
} else {
|
||||
echo " ERROR: " . $response->get_error_message() . "\n\n";
|
||||
}
|
||||
|
||||
// 3. Check DreamTripspk channel for live videos
|
||||
echo "3. Checking DreamTripspk Channel:\n";
|
||||
$channel_id = 'UCetYFjkhf7S7LwiuJxeC28g';
|
||||
$channel_url = 'https://www.youtube.com/channel/' . $channel_id . '/live';
|
||||
|
||||
$extracted_id = mm_video_extract_youtube_live_video_id($channel_url);
|
||||
if ($extracted_id) {
|
||||
echo " ✓ Found video ID: $extracted_id\n";
|
||||
if ($extracted_id === $video_id) {
|
||||
echo " ✓ MATCH! This is the current live video\n";
|
||||
} else {
|
||||
echo " ✗ DIFFERENT video is live: $extracted_id\n";
|
||||
}
|
||||
} else {
|
||||
echo " ✗ No live video found on channel\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// 4. Check cache
|
||||
echo "4. Cache Status:\n";
|
||||
$cache_key_video = 'mm_yt_live_v2_' . md5($channel_url);
|
||||
$cached_video_id = get_transient($cache_key_video);
|
||||
echo " Video ID Cache: " . ($cached_video_id ? $cached_video_id : "EMPTY") . "\n";
|
||||
|
||||
$cache_key_status = 'mm_yt_status_' . $video_id;
|
||||
$cached_status = get_transient($cache_key_status);
|
||||
echo " Live Status Cache: " . ($cached_status !== false ? ($cached_status ? "LIVE" : "NOT LIVE") : "EMPTY") . "\n";
|
||||
|
||||
echo "\n=== Test Complete ===\n";
|
||||
28
Minecraft-Modern-Theme/test-youtube.php
Normal file
28
Minecraft-Modern-Theme/test-youtube.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
echo "=== Testing YouTube Livestream Data ===\n\n";
|
||||
|
||||
$profile_url = 'https://www.youtube.com/@NashvilleBirdCam';
|
||||
$youtube_channel_id = 'UClOWy1mPxNB1D3cpmmxqGEg';
|
||||
|
||||
echo "Profile URL: $profile_url\n";
|
||||
echo "Channel ID: $youtube_channel_id\n\n";
|
||||
|
||||
$data = mm_video_get_livestream_data($profile_url, '', $youtube_channel_id);
|
||||
|
||||
echo "=== Livestream Data ===\n";
|
||||
print_r($data);
|
||||
|
||||
if (!empty($data['video_id'])) {
|
||||
echo "\n✓ video_id found: " . $data['video_id'] . "\n";
|
||||
} else {
|
||||
echo "\n✗ video_id is EMPTY!\n";
|
||||
}
|
||||
|
||||
if (!empty($data['embed_url'])) {
|
||||
echo "✓ embed_url found: " . $data['embed_url'] . "\n";
|
||||
} else {
|
||||
echo "✗ embed_url is EMPTY!\n";
|
||||
}
|
||||
61
Minecraft-Modern-Theme/update-dreamtripspk.php
Normal file
61
Minecraft-Modern-Theme/update-dreamtripspk.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* Update DreamTripspk post with direct video URL
|
||||
*/
|
||||
|
||||
define('WP_USE_THEMES', false);
|
||||
require('../../../wp-load.php');
|
||||
|
||||
$video_url = 'https://www.youtube.com/watch?v=kWRhLLbLFE0';
|
||||
$post_id = 17512; // DreamTripspk Post ID
|
||||
|
||||
echo "=== Updating DreamTripspk Post ===\n\n";
|
||||
|
||||
// Update the meta field
|
||||
$result = update_post_meta($post_id, '_mm_livestream_player_url', $video_url);
|
||||
|
||||
if ($result) {
|
||||
echo "✓ Updated _mm_livestream_player_url to: $video_url\n";
|
||||
} else {
|
||||
// Check if value already exists
|
||||
$current = get_post_meta($post_id, '_mm_livestream_player_url', true);
|
||||
if ($current === $video_url) {
|
||||
echo "✓ Value already set to: $video_url\n";
|
||||
} else {
|
||||
echo "✗ Update failed. Current value: $current\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Clear caches
|
||||
$channel_id = get_post_meta($post_id, '_mm_livestream_youtube_channel_id', true);
|
||||
if ($channel_id) {
|
||||
$channel_url = 'https://www.youtube.com/channel/' . $channel_id . '/live';
|
||||
$cache_key = 'mm_yt_live_v2_' . md5($channel_url);
|
||||
delete_transient($cache_key);
|
||||
echo "✓ Cleared cache for channel\n";
|
||||
}
|
||||
|
||||
// Clear video status cache
|
||||
delete_transient('mm_yt_status_kWRhLLbLFE0');
|
||||
echo "✓ Cleared video status cache\n";
|
||||
|
||||
// Test the livestream data
|
||||
echo "\n=== Testing Livestream Item ===\n";
|
||||
$item = mm_video_get_livestream_item($post_id);
|
||||
if ($item) {
|
||||
echo "Title: " . $item['title'] . "\n";
|
||||
echo "Owner: " . $item['owner'] . "\n";
|
||||
echo "Platform: " . $item['stream']['platform'] . "\n";
|
||||
echo "Video ID: " . $item['stream']['video_id'] . "\n";
|
||||
echo "Embed URL: " . ($item['stream']['embed_url'] ? 'SET' : 'EMPTY') . "\n";
|
||||
|
||||
// Test live status
|
||||
if (!empty($item['stream']['video_id'])) {
|
||||
$is_live = mm_video_check_youtube_live_status($item['stream']['video_id']);
|
||||
echo "Live Status: " . ($is_live ? "LIVE" : "NOT LIVE") . "\n";
|
||||
}
|
||||
} else {
|
||||
echo "ERROR: Could not get livestream item data\n";
|
||||
}
|
||||
|
||||
echo "\n✓ Update Complete! Reload the page.\n";
|
||||
Reference in New Issue
Block a user