Upload via GUI (182 Dateien)
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
/* Roboto – lokal gehostet (DSGVO). Generiert, nicht manuell bearbeiten. */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('roboto-latin-ext-0fb06be4.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('roboto-latin-cb43c055.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('roboto-latin-ext-0fb06be4.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('roboto-latin-cb43c055.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('roboto-latin-ext-0fb06be4.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('roboto-latin-cb43c055.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,49 @@
|
|||||||
|
/* Rubik – lokal gehostet (DSGVO). Generiert, nicht manuell bearbeiten. */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('rubik-latin-ext-b7b482e1.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('rubik-latin-f673d854.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('rubik-latin-ext-b7b482e1.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('rubik-latin-f673d854.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('rubik-latin-ext-b7b482e1.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Rubik';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('rubik-latin-f673d854.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,9 @@
|
|||||||
|
/* Satisfy – lokal gehostet (DSGVO). Generiert, nicht manuell bearbeiten. */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satisfy';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('satisfy-latin-b4c9305d.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,49 @@
|
|||||||
|
/* Source Sans Pro – lokal gehostet (DSGVO). Generiert, nicht manuell bearbeiten. */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('source-sans-pro-latin-ext-c12498bb.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('source-sans-pro-latin-ea667083.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('source-sans-pro-latin-ext-c008dc5c.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('source-sans-pro-latin-49902363.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('source-sans-pro-latin-ext-17c620e3.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('source-sans-pro-latin-c7df1611.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,33 @@
|
|||||||
|
/* Ubuntu – lokal gehostet (DSGVO). Generiert, nicht manuell bearbeiten. */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Ubuntu';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('ubuntu-latin-ext-b2700a09.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Ubuntu';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('ubuntu-latin-62d0e61f.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Ubuntu';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('ubuntu-latin-ext-4f2e4a8f.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Ubuntu';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('ubuntu-latin-7b2f7147.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,49 @@
|
|||||||
|
/* Work Sans – lokal gehostet (DSGVO). Generiert, nicht manuell bearbeiten. */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Work Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('work-sans-latin-ext-94b95f7b.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Work Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('work-sans-latin-f7b83de3.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Work Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('work-sans-latin-ext-94b95f7b.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Work Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('work-sans-latin-f7b83de3.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Work Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('work-sans-latin-ext-94b95f7b.woff2') format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Work Sans';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('work-sans-latin-f7b83de3.woff2') format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,327 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Ankuendigungs-Leiste inkl. Admin-Seite und Hoehenausgleich
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// ANNOUNCEMENT BAR
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
function mm_announcement_get_font_list() {
|
||||||
|
return array(
|
||||||
|
'inherit' => array( 'label' => 'Theme-Standard', 'css' => 'inherit', 'google' => false, 'google_name' => '' ),
|
||||||
|
'Arial' => array( 'label' => 'Arial', 'css' => 'Arial, Helvetica, sans-serif', 'google' => false, 'google_name' => '' ),
|
||||||
|
'Roboto' => array( 'label' => 'Roboto', 'css' => "'Roboto', sans-serif", 'google' => true, 'google_name' => 'Roboto' ),
|
||||||
|
'Montserrat' => array( 'label' => 'Montserrat', 'css' => "'Montserrat', sans-serif", 'google' => true, 'google_name' => 'Montserrat' ),
|
||||||
|
'Open Sans' => array( 'label' => 'Open Sans', 'css' => "'Open Sans', sans-serif", 'google' => true, 'google_name' => 'Open+Sans' ),
|
||||||
|
'Lato' => array( 'label' => 'Lato', 'css' => "'Lato', sans-serif", 'google' => true, 'google_name' => 'Lato' ),
|
||||||
|
'Poppins' => array( 'label' => 'Poppins', 'css' => "'Poppins', sans-serif", 'google' => true, 'google_name' => 'Poppins' ),
|
||||||
|
'Source Sans Pro' => array( 'label' => 'Source Sans Pro', 'css' => "'Source Sans Pro', sans-serif", 'google' => true, 'google_name' => 'Source+Sans+Pro' ),
|
||||||
|
'Noto Sans' => array( 'label' => 'Noto Sans', 'css' => "'Noto Sans', sans-serif", 'google' => true, 'google_name' => 'Noto+Sans' ),
|
||||||
|
'Raleway' => array( 'label' => 'Raleway', 'css' => "'Raleway', sans-serif", 'google' => true, 'google_name' => 'Raleway' ),
|
||||||
|
'Merriweather' => array( 'label' => 'Merriweather', 'css' => "'Merriweather', serif", 'google' => true, 'google_name' => 'Merriweather' ),
|
||||||
|
'Playfair Display' => array( 'label' => 'Playfair Display', 'css' => "'Playfair Display', serif", 'google' => true, 'google_name' => 'Playfair+Display' ),
|
||||||
|
'Oswald' => array( 'label' => 'Oswald', 'css' => "'Oswald', sans-serif", 'google' => true, 'google_name' => 'Oswald' ),
|
||||||
|
'Rubik' => array( 'label' => 'Rubik', 'css' => "'Rubik', sans-serif", 'google' => true, 'google_name' => 'Rubik' ),
|
||||||
|
'Inter' => array( 'label' => 'Inter', 'css' => "'Inter', sans-serif", 'google' => true, 'google_name' => 'Inter' ),
|
||||||
|
'Nunito' => array( 'label' => 'Nunito', 'css' => "'Nunito', sans-serif", 'google' => true, 'google_name' => 'Nunito' ),
|
||||||
|
'Ubuntu' => array( 'label' => 'Ubuntu', 'css' => "'Ubuntu', sans-serif", 'google' => true, 'google_name' => 'Ubuntu' ),
|
||||||
|
'PT Sans' => array( 'label' => 'PT Sans', 'css' => "'PT Sans', sans-serif", 'google' => true, 'google_name' => 'PT+Sans' ),
|
||||||
|
'Archivo' => array( 'label' => 'Archivo', 'css' => "'Archivo', sans-serif", 'google' => true, 'google_name' => 'Archivo' ),
|
||||||
|
'Fira Sans' => array( 'label' => 'Fira Sans', 'css' => "'Fira Sans', sans-serif", 'google' => true, 'google_name' => 'Fira+Sans' ),
|
||||||
|
'Work Sans' => array( 'label' => 'Work Sans', 'css' => "'Work Sans', sans-serif", 'google' => true, 'google_name' => 'Work+Sans' ),
|
||||||
|
'Quicksand' => array( 'label' => 'Quicksand', 'css' => "'Quicksand', sans-serif", 'google' => true, 'google_name' => 'Quicksand' ),
|
||||||
|
'Karla' => array( 'label' => 'Karla', 'css' => "'Karla', sans-serif", 'google' => true, 'google_name' => 'Karla' ),
|
||||||
|
'Dancing Script' => array( 'label' => 'Dancing Script', 'css' => "'Dancing Script', cursive", 'google' => true, 'google_name' => 'Dancing+Script' ),
|
||||||
|
'Pacifico' => array( 'label' => 'Pacifico', 'css' => "'Pacifico', cursive", 'google' => true, 'google_name' => 'Pacifico' ),
|
||||||
|
'Great Vibes' => array( 'label' => 'Great Vibes', 'css' => "'Great Vibes', cursive", 'google' => true, 'google_name' => 'Great+Vibes' ),
|
||||||
|
'Satisfy' => array( 'label' => 'Satisfy', 'css' => "'Satisfy', cursive", 'google' => true, 'google_name' => 'Satisfy' ),
|
||||||
|
'Allura' => array( 'label' => 'Allura', 'css' => "'Allura', cursive", 'google' => true, 'google_name' => 'Allura' ),
|
||||||
|
'Alex Brush' => array( 'label' => 'Alex Brush', 'css' => "'Alex Brush', cursive", 'google' => true, 'google_name' => 'Alex+Brush' ),
|
||||||
|
'Cookie' => array( 'label' => 'Cookie', 'css' => "'Cookie', cursive", 'google' => true, 'google_name' => 'Cookie' ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function mm_announcement_admin_init() {
|
||||||
|
add_menu_page( 'Ankündigung', 'Ankündigung', 'manage_options', 'mm-announcement', 'mm_announcement_admin_page', 'dashicons-megaphone', 61 );
|
||||||
|
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_enabled' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_text' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_bg' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_color' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_font_size' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_font_family' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_position' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_countdown_enabled' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_countdown_label' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_countdown_date' );
|
||||||
|
register_setting( 'mm_announcement_group', 'mm_announcement_countdown_expired_msg' );
|
||||||
|
}
|
||||||
|
add_action( 'admin_menu', 'mm_announcement_admin_init' );
|
||||||
|
|
||||||
|
|
||||||
|
function mm_announcement_admin_page() {
|
||||||
|
if ( ! current_user_can( 'manage_options' ) ) return;
|
||||||
|
|
||||||
|
$fonts = mm_announcement_get_font_list();
|
||||||
|
$selected_font = get_option( 'mm_announcement_font_family', 'inherit' );
|
||||||
|
$selected_size = (int) get_option( 'mm_announcement_font_size', 16 );
|
||||||
|
$bg = esc_attr( get_option( 'mm_announcement_bg', '#1e1e1e' ) );
|
||||||
|
$color = esc_attr( get_option( 'mm_announcement_color', '#ffffff' ) );
|
||||||
|
$text_sample = wp_strip_all_tags( get_option( 'mm_announcement_text' ) ) ?: 'Das ist eine Vorschau: Wie sieht die Schrift aus?';
|
||||||
|
?>
|
||||||
|
<div class="wrap mm-announcement-admin">
|
||||||
|
<h1>Header-Ankündigung</h1>
|
||||||
|
<p class="description">Diese Leiste wird auf allen Seiten angezeigt. Die Vorschau unten zeigt sofort, wie die Ankündigung aussieht — Änderungen wirken <strong>direkt in der Vorschau</strong>, erst nach <em>Änderungen speichern</em> werden sie im Frontend übernommen.</p>
|
||||||
|
|
||||||
|
<form method="post" action="options.php" id="mm-announcement-form">
|
||||||
|
<?php settings_fields( 'mm_announcement_group' ); ?>
|
||||||
|
|
||||||
|
<h2>Allgemein</h2>
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th>Aktivieren</th>
|
||||||
|
<td>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="mm_announcement_enabled" value="1" <?php checked( 1, get_option( 'mm_announcement_enabled' ) ); ?>>
|
||||||
|
Ankündigung anzeigen
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Inhalt</h2>
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th style="vertical-align:top;">Text</th>
|
||||||
|
<td>
|
||||||
|
<?php wp_editor( get_option( 'mm_announcement_text' ), 'mm_announcement_text', array( 'textarea_rows' => 6, 'media_buttons' => false, 'tinymce' => true, 'quicktags' => true ) ); ?>
|
||||||
|
|
||||||
|
<h3>Verfügbare Icons</h3>
|
||||||
|
<p class="description">Klicke auf ein Icon, um es in den Editor einzufügen.</p>
|
||||||
|
<div id="mm-announcement-icon-list" style="display:flex;flex-wrap:wrap;gap:10px;margin-bottom:20px;">
|
||||||
|
<?php
|
||||||
|
$icons = array( '⚡', '‼️', '❗', '✅', '❌', '⭐', '🔥', '💡', '📢', '🎮', '🏆', '🔔', '🎉', '💬', '🛡️' );
|
||||||
|
foreach ( $icons as $icon ) {
|
||||||
|
echo '<button type="button" class="mm-icon-button" style="font-size:20px;padding:6px 10px;border:1px solid #ccc;border-radius:4px;background:#f7f7f7;cursor:pointer;" title="Klicke zum Einfügen">' . $icon . '</button>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($){
|
||||||
|
$('#mm-announcement-icon-list .mm-icon-button').on('click', function(){
|
||||||
|
var icon = $(this).text();
|
||||||
|
if (typeof tinymce !== 'undefined') {
|
||||||
|
var ed = tinymce.get('mm_announcement_text');
|
||||||
|
if (ed) { ed.execCommand('mceInsertContent', false, icon); return; }
|
||||||
|
}
|
||||||
|
var ta = $('#mm_announcement_text'), s = ta[0].selectionStart, e = ta[0].selectionEnd, v = ta.val();
|
||||||
|
ta.val(v.substring(0,s) + icon + v.substring(e));
|
||||||
|
ta[0].selectionStart = ta[0].selectionEnd = s + icon.length;
|
||||||
|
ta.focus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class="description">HTML erlaubt (z. B. <a>-Links).</p>
|
||||||
|
|
||||||
|
<div id="mm-announcement-preview" style="background:<?php echo $bg; ?>;color:<?php echo $color; ?>;padding:12px;border-radius:6px;box-shadow:0 1px 4px rgba(0,0,0,.06);margin-top:14px;">
|
||||||
|
<div id="mm-announcement-preview-text" style="font-size:<?php echo $selected_size; ?>px;font-family:<?php echo isset( $fonts[ $selected_font ] ) ? esc_attr( $fonts[ $selected_font ]['css'] ) : 'inherit'; ?>;text-align:center;">
|
||||||
|
<?php echo esc_html( $text_sample ); ?>
|
||||||
|
</div>
|
||||||
|
<p style="margin-top:10px;color:#888;font-size:13px;text-align:center;">Live Vorschau</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Position</h2>
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th>Anzeigeort</th>
|
||||||
|
<td>
|
||||||
|
<select name="mm_announcement_position" id="mm-announcement-position">
|
||||||
|
<option value="top" <?php selected( get_option( 'mm_announcement_position' ), 'top' ); ?>>Ganz oben (über dem Header)</option>
|
||||||
|
<option value="below-header" <?php selected( get_option( 'mm_announcement_position' ), 'below-header' ); ?>>Unter dem Header (Standard)</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Design</h2>
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th>Hintergrundfarbe</th>
|
||||||
|
<td><input type="color" name="mm_announcement_bg" id="mm-announcement-bg" value="<?php echo $bg; ?>"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Textfarbe</th>
|
||||||
|
<td><input type="color" name="mm_announcement_color" id="mm-announcement-color" value="<?php echo $color; ?>"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Schriftgröße (px)</th>
|
||||||
|
<td><input type="number" min="10" max="48" name="mm_announcement_font_size" id="mm-announcement-size" value="<?php echo $selected_size; ?>"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Schriftfamilie</th>
|
||||||
|
<td>
|
||||||
|
<select name="mm_announcement_font_family" id="mm-announcement-font">
|
||||||
|
<?php foreach ( $fonts as $key => $f ) : ?>
|
||||||
|
<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $selected_font, $key ); ?>><?php echo esc_html( $f['label'] ); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2>Countdown Timer</h2>
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th>Countdown aktivieren</th>
|
||||||
|
<td><label><input type="checkbox" name="mm_announcement_countdown_enabled" value="1" <?php checked( 1, get_option( 'mm_announcement_countdown_enabled' ) ); ?>> Timer im Banner anzeigen</label></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Label (Text vor Timer)</th>
|
||||||
|
<td><input type="text" name="mm_announcement_countdown_label" value="<?php echo esc_attr( get_option( 'mm_announcement_countdown_label', 'Event in:' ) ); ?>" style="width:100%;"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Zieldatum & Uhrzeit</th>
|
||||||
|
<td><input type="datetime-local" name="mm_announcement_countdown_date" value="<?php echo esc_attr( get_option( 'mm_announcement_countdown_date' ) ); ?>"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Nachricht nach Ablauf</th>
|
||||||
|
<td><input type="text" name="mm_announcement_countdown_expired_msg" value="<?php echo esc_attr( get_option( 'mm_announcement_countdown_expired_msg', 'Event läuft gerade!' ) ); ?>" style="width:100%;"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php submit_button( 'Änderungen speichern' ); ?>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function mm_render_announcement_bar() {
|
||||||
|
if ( ! get_option( 'mm_announcement_enabled' ) ) return;
|
||||||
|
|
||||||
|
$countdown_enabled = get_option( 'mm_announcement_countdown_enabled', false );
|
||||||
|
$countdown_label = esc_attr( get_option( 'mm_announcement_countdown_label', 'Event in:' ) );
|
||||||
|
$countdown_date = esc_attr( get_option( 'mm_announcement_countdown_date', '' ) );
|
||||||
|
$countdown_expired = esc_html( get_option( 'mm_announcement_countdown_expired_msg', 'Event läuft gerade!' ) );
|
||||||
|
|
||||||
|
$position = esc_attr( get_option( 'mm_announcement_position', 'below-header' ) );
|
||||||
|
$bg = esc_attr( get_option( 'mm_announcement_bg', '#1e1e1e' ) );
|
||||||
|
$color = esc_attr( get_option( 'mm_announcement_color', '#ffffff' ) );
|
||||||
|
$size = (int) get_option( 'mm_announcement_font_size', 16 );
|
||||||
|
$font_key = get_option( 'mm_announcement_font_family', 'inherit' );
|
||||||
|
$fonts = mm_announcement_get_font_list();
|
||||||
|
$font_css = isset( $fonts[ $font_key ] ) ? wp_strip_all_tags( $fonts[ $font_key ]['css'] ) : 'inherit';
|
||||||
|
$text_kses = wp_kses_post( get_option( 'mm_announcement_text', '' ) );
|
||||||
|
|
||||||
|
$countdown_html = '';
|
||||||
|
if ( $countdown_enabled && ! empty( $countdown_date ) ) {
|
||||||
|
$countdown_html = '<div class="mm-countdown-wrapper" style="display:inline-flex;align-items:center;margin-left:15px;padding-left:15px;border-left:1px solid rgba(255,255,255,0.3);font-weight:bold;">
|
||||||
|
<span class="mm-countdown-label">' . $countdown_label . ' </span>
|
||||||
|
<span class="mm-countdown-timer" data-date="' . $countdown_date . '" data-expired="' . $countdown_expired . '">Laden...</span>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div id="mm-announcement"
|
||||||
|
data-position="<?php echo esc_attr( $position ); ?>"
|
||||||
|
style="background:<?php echo esc_attr( $bg ); ?>;color:<?php echo esc_attr( $color ); ?>;font-size:<?php echo esc_attr( $size ); ?>px;font-family:<?php echo esc_attr( $font_css ); ?>;">
|
||||||
|
<div class="mm-announcement-inner">
|
||||||
|
<div class="mm-announcement-text" style="display:inline-flex;align-items:center;width:100%;justify-content:center;">
|
||||||
|
<?php echo $text_kses; ?>
|
||||||
|
<?php echo $countdown_html; ?>
|
||||||
|
</div>
|
||||||
|
<button class="mm-announcement-close" aria-label="<?php esc_attr_e( 'Schließen', 'minecraft-modern-theme' ); ?>">×</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
add_action( 'wp_body_open', 'mm_render_announcement_bar' );
|
||||||
|
|
||||||
|
|
||||||
|
function mm_announcement_enqueue_assets() {
|
||||||
|
// BUG-FIX: CSS/JS nicht laden wenn die Ankündigungs-Bar deaktiviert ist.
|
||||||
|
if ( ! get_option( 'mm_announcement_enabled' ) ) return;
|
||||||
|
|
||||||
|
// BUG-FIX: Hier wurde bisher /css/announcement.css eingebunden – diese Datei
|
||||||
|
// existiert nicht (404 bei jedem Aufruf mit aktiver Bar). Die Styles der
|
||||||
|
// Ankündigungs-Leiste stehen bereits in style.css (#mm-announcement ff.),
|
||||||
|
// der Enqueue war also toter Code und wurde entfernt.
|
||||||
|
wp_enqueue_script( 'mm-announcement-script', get_template_directory_uri() . '/js/announcement.js', array(), filemtime( get_template_directory() . '/js/announcement.js' ), true );
|
||||||
|
|
||||||
|
// Gewählte Schrift lokal einbinden (kein Google-Aufruf mehr).
|
||||||
|
// Der Array-Key entspricht dem Schriftnamen, z. B. "Open Sans" -> /fonts/open-sans/.
|
||||||
|
$fonts = mm_announcement_get_font_list();
|
||||||
|
$font_key = get_option( 'mm_announcement_font_family', 'inherit' );
|
||||||
|
if ( isset( $fonts[ $font_key ] ) && ! empty( $fonts[ $font_key ]['google'] ) ) {
|
||||||
|
mm_enqueue_local_font( $font_key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'wp_enqueue_scripts', 'mm_announcement_enqueue_assets' );
|
||||||
|
|
||||||
|
|
||||||
|
function mm_announcement_admin_assets( $hook ) {
|
||||||
|
if ( $hook !== 'toplevel_page_mm-announcement' ) return;
|
||||||
|
|
||||||
|
wp_add_inline_style( 'wp-admin', '
|
||||||
|
.mm-announcement-admin .form-table th { width: 180px; vertical-align: top; }
|
||||||
|
.mm-announcement-admin .description { margin-top: 6px; color: #666; max-width: 720px; }
|
||||||
|
.mm-announcement-admin h2 { margin-top: 24px; }
|
||||||
|
#mm-announcement-preview { transition: all 140ms ease; }
|
||||||
|
#mm-announcement-preview-text { transition: font-family 160ms ease, font-size 120ms ease; white-space: normal; word-break: break-word; }
|
||||||
|
' );
|
||||||
|
|
||||||
|
wp_enqueue_script( 'mm-announcement-admin-script', get_template_directory_uri() . '/js/mm-announcement-admin.js', array( 'jquery' ), filemtime( get_template_directory() . '/js/mm-announcement-admin.js' ), true );
|
||||||
|
wp_localize_script( 'mm-announcement-admin-script', 'MM_Announcement_Fonts', mm_announcement_get_font_list() );
|
||||||
|
wp_localize_script( 'mm-announcement-admin-script', 'MM_Announcement_Current', array(
|
||||||
|
'font' => get_option( 'mm_announcement_font_family', 'inherit' ),
|
||||||
|
'size' => (int) get_option( 'mm_announcement_font_size', 16 ),
|
||||||
|
'bg' => get_option( 'mm_announcement_bg', '#1e1e1e' ),
|
||||||
|
'color' => get_option( 'mm_announcement_color', '#ffffff' ),
|
||||||
|
'text' => wp_kses_post( get_option( 'mm_announcement_text' ) ),
|
||||||
|
// Basis-URL der lokalen Schriften für die Live-Vorschau (kein Google-Aufruf)
|
||||||
|
'fontsBase' => get_template_directory_uri() . '/fonts/',
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'admin_enqueue_scripts', 'mm_announcement_admin_assets' );
|
||||||
|
// === Announcement-Bar Höhe als CSS-Variable + Body-Klasse ===
|
||||||
|
function minecraft_modern_announcement_offset_script() {
|
||||||
|
if ( ! get_option( 'mm_announcement_enabled' ) ) return;
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var bar = document.getElementById('mm-announcement');
|
||||||
|
if (!bar) return;
|
||||||
|
function updateOffset() {
|
||||||
|
var h = bar.offsetHeight;
|
||||||
|
document.documentElement.style.setProperty('--announcement-height', h + 'px');
|
||||||
|
document.body.classList.add('has-announcement');
|
||||||
|
}
|
||||||
|
updateOffset();
|
||||||
|
new ResizeObserver(updateOffset).observe(bar);
|
||||||
|
// Wenn Bar geschlossen wird
|
||||||
|
var closeBtn = bar.querySelector('.mm-announcement-close');
|
||||||
|
if (closeBtn) {
|
||||||
|
closeBtn.addEventListener('click', function() {
|
||||||
|
document.documentElement.style.setProperty('--announcement-height', '0px');
|
||||||
|
document.body.classList.remove('has-announcement');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
add_action( 'wp_footer', 'minecraft_modern_announcement_offset_script' );
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,394 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Bewerbungsformular: CPT, Formularverarbeitung und Verwaltung
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// === BEWERBUNGSFORMULAR ======================================================
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// --- 1. Customizer: Ein/Ausschalten ---
|
||||||
|
function mm_bewerbung_customizer( $wp_customize ) {
|
||||||
|
$wp_customize->add_section( 'mm_bewerbung_section', array(
|
||||||
|
'title' => __( 'Bewerbungsformular', 'minecraft-modern-theme' ),
|
||||||
|
'priority' => 80,
|
||||||
|
) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_bewerbung_enabled', array(
|
||||||
|
'default' => false,
|
||||||
|
'sanitize_callback' => 'wp_validate_boolean',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'mm_bewerbung_enabled', array(
|
||||||
|
'label' => __( 'Bewerbungsformular aktivieren', 'minecraft-modern-theme' ),
|
||||||
|
'description' => __( 'Schaltet die Bewerbungsseite und das Formular ein.', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'mm_bewerbung_section',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_bewerbung_title', array(
|
||||||
|
'default' => __( 'Bewirb dich bei uns!', 'minecraft-modern-theme' ),
|
||||||
|
'sanitize_callback' => 'sanitize_text_field',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'mm_bewerbung_title', array(
|
||||||
|
'label' => __( 'Titel der Bewerbungsseite', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'mm_bewerbung_section',
|
||||||
|
'type' => 'text',
|
||||||
|
) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_bewerbung_desc', array(
|
||||||
|
'default' => __( 'Du möchtest Teil unseres Teams werden? Füll das Formular aus und wir melden uns bei dir.', 'minecraft-modern-theme' ),
|
||||||
|
'sanitize_callback' => 'sanitize_textarea_field',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'mm_bewerbung_desc', array(
|
||||||
|
'label' => __( 'Beschreibungstext', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'mm_bewerbung_section',
|
||||||
|
'type' => 'textarea',
|
||||||
|
) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_bewerbung_success_msg', array(
|
||||||
|
'default' => __( 'Deine Bewerbung wurde erfolgreich eingereicht! Wir melden uns so bald wie möglich bei dir.', 'minecraft-modern-theme' ),
|
||||||
|
'sanitize_callback' => 'sanitize_textarea_field',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'mm_bewerbung_success_msg', array(
|
||||||
|
'label' => __( 'Erfolgsmeldung nach dem Absenden', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'mm_bewerbung_section',
|
||||||
|
'type' => 'textarea',
|
||||||
|
) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_bewerbung_min_alter', array(
|
||||||
|
'default' => 14,
|
||||||
|
'sanitize_callback' => 'absint',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'mm_bewerbung_min_alter', array(
|
||||||
|
'label' => __( 'Mindestalter', 'minecraft-modern-theme' ),
|
||||||
|
'description' => __( 'Bewerbungen unter diesem Alter werden abgelehnt. 0 = kein Limit.', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'mm_bewerbung_section',
|
||||||
|
'type' => 'number',
|
||||||
|
'input_attrs' => array( 'min' => 0, 'max' => 99 ),
|
||||||
|
) );
|
||||||
|
|
||||||
|
// ── Positionen ──
|
||||||
|
$wp_customize->add_setting( 'mm_bewerbung_positionen', array(
|
||||||
|
'default' => "Moderator
|
||||||
|
Supporter
|
||||||
|
Builder
|
||||||
|
Developer",
|
||||||
|
'sanitize_callback' => 'sanitize_textarea_field',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'mm_bewerbung_positionen', array(
|
||||||
|
'label' => __( 'Bewerbungs-Positionen', 'minecraft-modern-theme' ),
|
||||||
|
'description' => __( 'Eine Position pro Zeile. Der Bewerber wählt genau eine davon aus.', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'mm_bewerbung_section',
|
||||||
|
'type' => 'textarea',
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'customize_register', 'mm_bewerbung_customizer' );
|
||||||
|
|
||||||
|
// Hilfsfunktion: Positions-Liste als Array zurückgeben
|
||||||
|
function mm_bewerbung_get_positionen() {
|
||||||
|
$raw = get_theme_mod( 'mm_bewerbung_positionen', "Moderator
|
||||||
|
Supporter
|
||||||
|
Builder
|
||||||
|
Developer" );
|
||||||
|
$list = array_filter( array_map( 'trim', explode( "
|
||||||
|
", $raw ) ) );
|
||||||
|
return array_values( $list );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- 2. Custom Post Type: Bewerbung ---
|
||||||
|
function mm_register_bewerbung_cpt() {
|
||||||
|
if ( ! get_theme_mod( 'mm_bewerbung_enabled', false ) ) return;
|
||||||
|
|
||||||
|
register_post_type( 'mm_bewerbung', array(
|
||||||
|
'labels' => array(
|
||||||
|
'name' => __( 'Bewerbungen', 'minecraft-modern-theme' ),
|
||||||
|
'singular_name' => __( 'Bewerbung', 'minecraft-modern-theme' ),
|
||||||
|
'all_items' => __( 'Alle Bewerbungen', 'minecraft-modern-theme' ),
|
||||||
|
'menu_name' => __( 'Bewerbungen', 'minecraft-modern-theme' ),
|
||||||
|
),
|
||||||
|
'public' => false,
|
||||||
|
'show_ui' => true,
|
||||||
|
'show_in_menu' => true,
|
||||||
|
'menu_icon' => 'dashicons-clipboard',
|
||||||
|
'menu_position' => 8,
|
||||||
|
'supports' => array( 'title' ),
|
||||||
|
'capabilities' => array(
|
||||||
|
'create_posts' => 'do_not_allow', // Nur über Frontend erstellbar
|
||||||
|
),
|
||||||
|
'map_meta_cap' => true,
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'init', 'mm_register_bewerbung_cpt' );
|
||||||
|
|
||||||
|
|
||||||
|
// --- 3. Admin: Meta-Box für Bewerbungs-Details ---
|
||||||
|
function mm_bewerbung_meta_box() {
|
||||||
|
add_meta_box(
|
||||||
|
'mm_bewerbung_details',
|
||||||
|
__( 'Bewerbungs-Details', 'minecraft-modern-theme' ),
|
||||||
|
'mm_bewerbung_meta_box_html',
|
||||||
|
'mm_bewerbung', 'normal', 'high'
|
||||||
|
);
|
||||||
|
add_meta_box(
|
||||||
|
'mm_bewerbung_status_box',
|
||||||
|
__( 'Status', 'minecraft-modern-theme' ),
|
||||||
|
'mm_bewerbung_status_box_html',
|
||||||
|
'mm_bewerbung', 'side', 'high'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_action( 'add_meta_boxes', 'mm_bewerbung_meta_box' );
|
||||||
|
|
||||||
|
function mm_bewerbung_meta_box_html( $post ) {
|
||||||
|
$fields = array(
|
||||||
|
'_mm_bew_mc_name' => __( 'Minecraft Username', 'minecraft-modern-theme' ),
|
||||||
|
'_mm_bew_discord' => __( 'Discord Username', 'minecraft-modern-theme' ),
|
||||||
|
'_mm_bew_alter' => __( 'Alter', 'minecraft-modern-theme' ),
|
||||||
|
'_mm_bew_position' => __( 'Bewirbt sich als', 'minecraft-modern-theme' ),
|
||||||
|
'_mm_bew_warum' => __( 'Warum möchtest du mitspielen?', 'minecraft-modern-theme' ),
|
||||||
|
'_mm_bew_erfahrung' => __( 'Erfahrung / Vorstellung', 'minecraft-modern-theme' ),
|
||||||
|
'_mm_bew_datum' => __( 'Eingereicht am', 'minecraft-modern-theme' ),
|
||||||
|
'_mm_bew_ip' => __( 'IP-Adresse', 'minecraft-modern-theme' ),
|
||||||
|
);
|
||||||
|
echo '<table class="form-table" style="margin:0;">';
|
||||||
|
foreach ( $fields as $key => $label ) {
|
||||||
|
$val = get_post_meta( $post->ID, $key, true );
|
||||||
|
if ( ! $val ) continue;
|
||||||
|
$is_long = in_array( $key, array( '_mm_bew_warum', '_mm_bew_erfahrung' ) );
|
||||||
|
echo '<tr>';
|
||||||
|
echo '<th style="width:180px;padding:10px 0;vertical-align:top;"><strong>' . esc_html($label) . '</strong></th>';
|
||||||
|
echo '<td style="padding:10px 0;">';
|
||||||
|
if ( $is_long ) {
|
||||||
|
echo '<div style="background:#f9f9f9;border:1px solid #ddd;border-radius:4px;padding:10px 14px;line-height:1.6;max-width:700px;white-space:pre-wrap;">' . esc_html($val) . '</div>';
|
||||||
|
} else {
|
||||||
|
echo '<span style="font-size:14px;">' . esc_html($val) . '</span>';
|
||||||
|
}
|
||||||
|
echo '</td></tr>';
|
||||||
|
}
|
||||||
|
echo '</table>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function mm_bewerbung_status_box_html( $post ) {
|
||||||
|
$status = get_post_meta( $post->ID, '_mm_bew_status', true ) ?: 'neu';
|
||||||
|
wp_nonce_field( 'mm_bew_status_save', 'mm_bew_status_nonce' );
|
||||||
|
$options = array(
|
||||||
|
'neu' => array( 'label' => __('Neu','minecraft-modern-theme'), 'color' => '#0073aa' ),
|
||||||
|
'in_pruef' => array( 'label' => __('In Prüfung','minecraft-modern-theme'), 'color' => '#f0ad4e' ),
|
||||||
|
'angenommen' => array( 'label' => __('Angenommen','minecraft-modern-theme'), 'color' => '#46b450' ),
|
||||||
|
'abgelehnt' => array( 'label' => __('Abgelehnt','minecraft-modern-theme'), 'color' => '#dc3232' ),
|
||||||
|
);
|
||||||
|
echo '<select name="mm_bew_status" style="width:100%;margin-bottom:10px;">';
|
||||||
|
foreach ( $options as $val => $opt ) {
|
||||||
|
$sel = selected( $status, $val, false );
|
||||||
|
echo '<option value="' . esc_attr($val) . '" ' . $sel . '>' . esc_html($opt['label']) . '</option>';
|
||||||
|
}
|
||||||
|
echo '</select>';
|
||||||
|
$cur = isset($options[$status]) ? $options[$status] : $options['neu'];
|
||||||
|
echo '<div style="background:' . esc_attr($cur['color']) . ';color:#fff;text-align:center;padding:6px;border-radius:4px;font-weight:600;">' . esc_html($cur['label']) . '</div>';
|
||||||
|
|
||||||
|
// Admin-Notiz
|
||||||
|
$notiz = get_post_meta( $post->ID, '_mm_bew_notiz', true );
|
||||||
|
echo '<hr style="margin:12px 0;">';
|
||||||
|
echo '<label style="font-weight:600;display:block;margin-bottom:6px;">' . __('Interne Notiz:', 'minecraft-modern-theme') . '</label>';
|
||||||
|
echo '<textarea name="mm_bew_notiz" rows="4" style="width:100%;font-size:12px;">' . esc_textarea($notiz) . '</textarea>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function mm_bewerbung_save_status( $post_id ) {
|
||||||
|
if ( ! isset($_POST['mm_bew_status_nonce']) || ! wp_verify_nonce($_POST['mm_bew_status_nonce'], 'mm_bew_status_save') ) return;
|
||||||
|
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
|
||||||
|
if ( ! current_user_can('edit_post', $post_id) ) return;
|
||||||
|
if ( isset($_POST['mm_bew_status']) ) {
|
||||||
|
update_post_meta( $post_id, '_mm_bew_status', sanitize_text_field($_POST['mm_bew_status']) );
|
||||||
|
}
|
||||||
|
if ( isset($_POST['mm_bew_notiz']) ) {
|
||||||
|
update_post_meta( $post_id, '_mm_bew_notiz', sanitize_textarea_field($_POST['mm_bew_notiz']) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'save_post', 'mm_bewerbung_save_status' );
|
||||||
|
|
||||||
|
|
||||||
|
// --- 4. Admin-Spalten in der Bewerbungsliste ---
|
||||||
|
function mm_bewerbung_columns( $cols ) {
|
||||||
|
return array(
|
||||||
|
'cb' => $cols['cb'],
|
||||||
|
'title' => __( 'Name', 'minecraft-modern-theme' ),
|
||||||
|
'mc_name' => __( 'Minecraft', 'minecraft-modern-theme' ),
|
||||||
|
'discord' => __( 'Discord', 'minecraft-modern-theme' ),
|
||||||
|
'alter' => __( 'Alter', 'minecraft-modern-theme' ),
|
||||||
|
'position' => __( 'Position', 'minecraft-modern-theme' ),
|
||||||
|
'status' => __( 'Status', 'minecraft-modern-theme' ),
|
||||||
|
'datum' => __( 'Eingereicht', 'minecraft-modern-theme' ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_filter( 'manage_mm_bewerbung_posts_columns', 'mm_bewerbung_columns' );
|
||||||
|
|
||||||
|
function mm_bewerbung_column_content( $col, $post_id ) {
|
||||||
|
$status_colors = array(
|
||||||
|
'neu' => '#0073aa',
|
||||||
|
'in_pruef' => '#f0ad4e',
|
||||||
|
'angenommen' => '#46b450',
|
||||||
|
'abgelehnt' => '#dc3232',
|
||||||
|
);
|
||||||
|
$status_labels = array(
|
||||||
|
'neu' => __('Neu','minecraft-modern-theme'),
|
||||||
|
'in_pruef' => __('In Prüfung','minecraft-modern-theme'),
|
||||||
|
'angenommen' => __('Angenommen','minecraft-modern-theme'),
|
||||||
|
'abgelehnt' => __('Abgelehnt','minecraft-modern-theme'),
|
||||||
|
);
|
||||||
|
switch ($col) {
|
||||||
|
case 'mc_name':
|
||||||
|
$mc = get_post_meta($post_id, '_mm_bew_mc_name', true);
|
||||||
|
if ($mc) {
|
||||||
|
echo '<div style="display:flex;align-items:center;gap:8px;">';
|
||||||
|
echo '<img src="https://mc-heads.net/avatar/' . esc_attr($mc) . '/24" style="border-radius:3px;" width="24" height="24" alt="">';
|
||||||
|
echo esc_html($mc) . '</div>';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'discord':
|
||||||
|
echo esc_html( get_post_meta($post_id, '_mm_bew_discord', true) );
|
||||||
|
break;
|
||||||
|
case 'alter':
|
||||||
|
echo esc_html( get_post_meta($post_id, '_mm_bew_alter', true) );
|
||||||
|
break;
|
||||||
|
case 'position':
|
||||||
|
$pos = get_post_meta($post_id, '_mm_bew_position', true);
|
||||||
|
if ( $pos ) {
|
||||||
|
echo '<span style="background:#1e3a5f;color:#58a6ff;padding:2px 10px;border-radius:12px;font-size:12px;font-weight:600;">'
|
||||||
|
. esc_html($pos) . '</span>';
|
||||||
|
} else {
|
||||||
|
echo '<span style="color:#999;">—</span>';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'status':
|
||||||
|
$s = get_post_meta($post_id, '_mm_bew_status', true) ?: 'neu';
|
||||||
|
$color = isset($status_colors[$s]) ? $status_colors[$s] : '#0073aa';
|
||||||
|
$label = isset($status_labels[$s]) ? $status_labels[$s] : $s;
|
||||||
|
echo '<span style="background:' . esc_attr($color) . ';color:#fff;padding:2px 10px;border-radius:12px;font-size:12px;font-weight:600;">' . esc_html($label) . '</span>';
|
||||||
|
break;
|
||||||
|
case 'datum':
|
||||||
|
echo esc_html( get_post_meta($post_id, '_mm_bew_datum', true) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'manage_mm_bewerbung_posts_custom_column', 'mm_bewerbung_column_content', 10, 2 );
|
||||||
|
|
||||||
|
|
||||||
|
// --- 5. AJAX: Formular absenden ---
|
||||||
|
add_action( 'wp_ajax_mm_submit_bewerbung', 'mm_submit_bewerbung' );
|
||||||
|
add_action( 'wp_ajax_nopriv_mm_submit_bewerbung', 'mm_submit_bewerbung' );
|
||||||
|
|
||||||
|
function mm_submit_bewerbung() {
|
||||||
|
// Nonce prüfen
|
||||||
|
if ( ! isset($_POST['nonce']) || ! wp_verify_nonce($_POST['nonce'], 'mm_bewerbung_nonce') ) {
|
||||||
|
wp_send_json_error( array('msg' => __('Sicherheitsfehler. Bitte Seite neu laden.', 'minecraft-modern-theme')) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Felder validieren
|
||||||
|
$mc_name = sanitize_text_field( $_POST['mc_name'] ?? '' );
|
||||||
|
$discord = sanitize_text_field( $_POST['discord'] ?? '' );
|
||||||
|
$alter_raw = absint( $_POST['alter'] ?? 0 );
|
||||||
|
$warum = sanitize_textarea_field( $_POST['warum'] ?? '' );
|
||||||
|
$erfahrung = sanitize_textarea_field( $_POST['erfahrung'] ?? '' );
|
||||||
|
|
||||||
|
$position = sanitize_text_field( $_POST['position'] ?? '' );
|
||||||
|
$positionen = mm_bewerbung_get_positionen();
|
||||||
|
|
||||||
|
$errors = array();
|
||||||
|
if ( empty($mc_name) ) $errors[] = __('Minecraft Username ist erforderlich.', 'minecraft-modern-theme');
|
||||||
|
if ( empty($discord) ) $errors[] = __('Discord Username ist erforderlich.', 'minecraft-modern-theme');
|
||||||
|
if ( $alter_raw < 1 ) $errors[] = __('Bitte gib dein Alter an.', 'minecraft-modern-theme');
|
||||||
|
if ( ! empty($positionen) && ! in_array($position, $positionen, true) ) {
|
||||||
|
$errors[] = __('Bitte wähle eine gültige Position aus.', 'minecraft-modern-theme');
|
||||||
|
}
|
||||||
|
if ( empty($warum) ) $errors[] = __('Bitte erkläre warum du mitspielen möchtest.', 'minecraft-modern-theme');
|
||||||
|
if ( empty($erfahrung) ) $errors[] = __('Bitte stell dich kurz vor.', 'minecraft-modern-theme');
|
||||||
|
|
||||||
|
// Mindestalter prüfen
|
||||||
|
$min_alter = absint( get_theme_mod('mm_bewerbung_min_alter', 14) );
|
||||||
|
if ( $min_alter > 0 && $alter_raw < $min_alter ) {
|
||||||
|
$errors[] = sprintf( __('Du musst mindestens %d Jahre alt sein.', 'minecraft-modern-theme'), $min_alter );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doppelbewerbung prüfen (gleicher MC-Name in den letzten 30 Tagen)
|
||||||
|
$existing = get_posts( array(
|
||||||
|
'post_type' => 'mm_bewerbung',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'meta_query' => array(
|
||||||
|
array( 'key' => '_mm_bew_mc_name', 'value' => $mc_name, 'compare' => '=' ),
|
||||||
|
),
|
||||||
|
'date_query' => array(
|
||||||
|
array( 'after' => '30 days ago' ),
|
||||||
|
),
|
||||||
|
'numberposts' => 1,
|
||||||
|
) );
|
||||||
|
if ( $existing ) {
|
||||||
|
$errors[] = __('Mit diesem Minecraft-Namen wurde in den letzten 30 Tagen bereits eine Bewerbung eingereicht.', 'minecraft-modern-theme');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty($errors) ) {
|
||||||
|
wp_send_json_error( array('msg' => implode(' ', $errors)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bewerbung als Post speichern
|
||||||
|
$post_id = wp_insert_post( array(
|
||||||
|
'post_type' => 'mm_bewerbung',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'post_title' => $mc_name . ' – ' . date_i18n('d.m.Y H:i'),
|
||||||
|
) );
|
||||||
|
|
||||||
|
if ( is_wp_error($post_id) ) {
|
||||||
|
wp_send_json_error( array('msg' => __('Fehler beim Speichern. Bitte versuche es erneut.', 'minecraft-modern-theme')) );
|
||||||
|
}
|
||||||
|
|
||||||
|
update_post_meta( $post_id, '_mm_bew_mc_name', $mc_name );
|
||||||
|
update_post_meta( $post_id, '_mm_bew_discord', $discord );
|
||||||
|
update_post_meta( $post_id, '_mm_bew_alter', $alter_raw );
|
||||||
|
update_post_meta( $post_id, '_mm_bew_position', $position );
|
||||||
|
update_post_meta( $post_id, '_mm_bew_warum', $warum );
|
||||||
|
update_post_meta( $post_id, '_mm_bew_erfahrung', $erfahrung );
|
||||||
|
update_post_meta( $post_id, '_mm_bew_status', 'neu' );
|
||||||
|
update_post_meta( $post_id, '_mm_bew_datum', date_i18n('d.m.Y H:i:s') );
|
||||||
|
update_post_meta( $post_id, '_mm_bew_ip', sanitize_text_field( $_SERVER['REMOTE_ADDR'] ?? '' ) );
|
||||||
|
|
||||||
|
$success_msg = get_theme_mod( 'mm_bewerbung_success_msg', __('Deine Bewerbung wurde erfolgreich eingereicht! Wir melden uns so bald wie möglich bei dir.', 'minecraft-modern-theme') );
|
||||||
|
wp_send_json_success( array('msg' => $success_msg) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- 6. Template-Loader ---
|
||||||
|
function mm_bewerbung_template_loader( $template ) {
|
||||||
|
if ( ! get_theme_mod('mm_bewerbung_enabled', false) ) return $template;
|
||||||
|
if ( is_page('bewerbung') ) {
|
||||||
|
// BUG-FIX: locate_template() statt get_template_directory(),
|
||||||
|
// damit ein page-bewerbung.php im Child-Theme greift.
|
||||||
|
$t = locate_template( 'page-bewerbung.php' );
|
||||||
|
if ( $t ) return $t;
|
||||||
|
}
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
add_filter( 'template_include', 'mm_bewerbung_template_loader' );
|
||||||
|
|
||||||
|
|
||||||
|
// --- 7. Seite automatisch anlegen ---
|
||||||
|
function mm_bewerbung_create_page() {
|
||||||
|
if ( ! get_theme_mod('mm_bewerbung_enabled', false) ) return;
|
||||||
|
if ( ! get_page_by_path('bewerbung') ) {
|
||||||
|
wp_insert_post( array(
|
||||||
|
'post_title' => __('Bewerbung', 'minecraft-modern-theme'),
|
||||||
|
'post_name' => 'bewerbung',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'post_type' => 'page',
|
||||||
|
'post_author' => 1,
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'customize_save_after', 'mm_bewerbung_create_page' );
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Cookie-Banner (DSGVO) mit vier Darstellungsvarianten
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// === COOKIE-BANNER (DSGVO) – 4 Varianten, alle gleichzeitig gerendert =======
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// Vorschau-Control
|
||||||
|
if ( class_exists('WP_Customize_Control') && ! class_exists('MM_Cookie_Preview_Control') ) :
|
||||||
|
class MM_Cookie_Preview_Control extends WP_Customize_Control {
|
||||||
|
public $type = 'mm_cookie_preview';
|
||||||
|
public function render_content() { ?>
|
||||||
|
<div style="margin-top:4px;">
|
||||||
|
<span class="customize-control-title" style="display:block;margin-bottom:8px;"><?php _e('Live-Vorschau','minecraft-modern-theme'); ?></span>
|
||||||
|
<div style="padding:12px 14px;background:rgba(0,212,255,0.07);border-left:3px solid #00d4ff;border-radius:0 6px 6px 0;">
|
||||||
|
<p style="margin:0 0 5px;font-size:12px;color:#00d4ff;font-weight:600;">← <?php _e('Vorschau rechts','minecraft-modern-theme'); ?></p>
|
||||||
|
<p style="margin:0;font-size:11px;color:#aaa;line-height:1.5;"><?php _e('Der Banner wird direkt in der Seitenvorschau angezeigt und aktualisiert sich live beim Wechseln der Variante.','minecraft-modern-theme'); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php }
|
||||||
|
}
|
||||||
|
endif;
|
||||||
|
|
||||||
|
|
||||||
|
// --- 1. Customizer ---
|
||||||
|
function mm_cookie_banner_customizer( $wp_customize ) {
|
||||||
|
$wp_customize->add_section( 'mm_cookie_banner_section', array(
|
||||||
|
'title' => __( 'Cookie-Banner (DSGVO)', 'minecraft-modern-theme' ),
|
||||||
|
'priority' => 75,
|
||||||
|
) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_cookie_enabled', array( 'default' => true, 'sanitize_callback' => 'wp_validate_boolean', 'transport' => 'postMessage' ) );
|
||||||
|
$wp_customize->add_control( 'mm_cookie_enabled', array( 'label' => __( 'Cookie-Banner aktivieren', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'checkbox' ) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_cookie_style', array( 'default' => 'bar', 'sanitize_callback' => 'sanitize_text_field', 'transport' => 'postMessage' ) );
|
||||||
|
$wp_customize->add_control( 'mm_cookie_style', array(
|
||||||
|
'label' => __( 'Design-Variante', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'mm_cookie_banner_section',
|
||||||
|
'type' => 'select',
|
||||||
|
'choices' => array(
|
||||||
|
'bar' => __( 'Variante 1 – Schmale Bar (volle Breite)', 'minecraft-modern-theme' ),
|
||||||
|
'split' => __( 'Variante 2 – Zweispaltig (3A)', 'minecraft-modern-theme' ),
|
||||||
|
'slide' => __( 'Variante 3 – Slide-In von rechts (3B)', 'minecraft-modern-theme' ),
|
||||||
|
'stepper' => __( 'Variante 4 – Kompakt-Center mit Stepper (3C)', 'minecraft-modern-theme' ),
|
||||||
|
),
|
||||||
|
) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_cookie_text', array( 'default' => __( 'Wir nutzen Cookies und ähnliche Technologien. Einige sind essenziell, andere helfen uns diese Website zu verbessern. Du kannst deine Auswahl jederzeit anpassen.', 'minecraft-modern-theme' ), 'sanitize_callback' => 'wp_kses_post', 'transport' => 'postMessage' ) );
|
||||||
|
$wp_customize->add_control( 'mm_cookie_text', array( 'label' => __( 'Banner-Text', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'textarea' ) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_cookie_privacy_url', array( 'default' => '', 'sanitize_callback' => 'esc_url_raw' ) );
|
||||||
|
$wp_customize->add_control( 'mm_cookie_privacy_url', array( 'label' => __( 'URL Datenschutzerklärung', 'minecraft-modern-theme' ), 'description' => __( 'Leer lassen um den Link auszublenden.', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'url' ) );
|
||||||
|
|
||||||
|
foreach ( array(
|
||||||
|
'necessary' => array( 'label' => __( 'Beschreibung: Notwendige', 'minecraft-modern-theme' ), 'default' => __( 'Grundlegende Funktionen der Website. Können nicht deaktiviert werden.', 'minecraft-modern-theme' ) ),
|
||||||
|
'statistics' => array( 'label' => __( 'Beschreibung: Statistik', 'minecraft-modern-theme' ), 'default' => __( 'Helfen uns zu verstehen wie Besucher mit der Website interagieren (z.B. Google Analytics).', 'minecraft-modern-theme' ) ),
|
||||||
|
'marketing' => array( 'label' => __( 'Beschreibung: Marketing', 'minecraft-modern-theme' ), 'default' => __( 'Werden genutzt um Werbung relevanter zu gestalten (z.B. YouTube, Facebook).', 'minecraft-modern-theme' ) ),
|
||||||
|
) as $key => $opts ) {
|
||||||
|
$wp_customize->add_setting( 'mm_cookie_desc_' . $key, array( 'default' => $opts['default'], 'sanitize_callback' => 'sanitize_textarea_field' ) );
|
||||||
|
$wp_customize->add_control( 'mm_cookie_desc_' . $key, array( 'label' => $opts['label'], 'section' => 'mm_cookie_banner_section', 'type' => 'textarea' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_cookie_ga_id', array( 'default' => '', 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||||
|
$wp_customize->add_control( 'mm_cookie_ga_id', array( 'label' => __( 'Google Analytics ID (optional)', 'minecraft-modern-theme' ), 'description' => __( 'z.B. G-XXXXXXXXXX', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'text' ) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_cookie_lifetime', array( 'default' => 365, 'sanitize_callback' => 'absint' ) );
|
||||||
|
$wp_customize->add_control( 'mm_cookie_lifetime', array( 'label' => __( 'Cookie-Laufzeit (Tage)', 'minecraft-modern-theme' ), 'section' => 'mm_cookie_banner_section', 'type' => 'number', 'input_attrs' => array( 'min' => 1, 'max' => 730 ) ) );
|
||||||
|
|
||||||
|
if ( class_exists( 'MM_Cookie_Preview_Control' ) ) {
|
||||||
|
$wp_customize->add_setting( 'mm_cookie_preview_dummy', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||||
|
$wp_customize->add_control( new MM_Cookie_Preview_Control( $wp_customize, 'mm_cookie_preview_dummy', array( 'section' => 'mm_cookie_banner_section', 'priority' => 200 ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'customize_register', 'mm_cookie_banner_customizer' );
|
||||||
|
|
||||||
|
|
||||||
|
// --- 2. Banner HTML – ALLE 4 LAYOUTS gleichzeitig ausgeben ---
|
||||||
|
// Im Customizer wechselt JS nur die Klasse auf #mm-cookie-banner.
|
||||||
|
// CSS zeigt immer nur das passende .mmc-layout-* div.
|
||||||
|
function mm_cookie_banner_render() {
|
||||||
|
$is_preview = is_customize_preview();
|
||||||
|
if ( ! $is_preview && ! get_theme_mod( 'mm_cookie_enabled', true ) ) return;
|
||||||
|
|
||||||
|
$style = get_theme_mod( 'mm_cookie_style', 'bar' );
|
||||||
|
$text = get_theme_mod( 'mm_cookie_text', __( 'Wir nutzen Cookies und ähnliche Technologien. Einige sind essenziell, andere helfen uns diese Website zu verbessern.', 'minecraft-modern-theme' ) );
|
||||||
|
$priv_url = get_theme_mod( 'mm_cookie_privacy_url', '' );
|
||||||
|
$lifetime = absint( get_theme_mod( 'mm_cookie_lifetime', 365 ) );
|
||||||
|
$ga_id = get_theme_mod( 'mm_cookie_ga_id', '' );
|
||||||
|
$desc_n = get_theme_mod( 'mm_cookie_desc_necessary', __( 'Grundlegende Funktionen der Website. Können nicht deaktiviert werden.', 'minecraft-modern-theme' ) );
|
||||||
|
$desc_s = get_theme_mod( 'mm_cookie_desc_statistics', __( 'Helfen uns zu verstehen wie Besucher mit der Website interagieren (z.B. Google Analytics).', 'minecraft-modern-theme' ) );
|
||||||
|
$desc_m = get_theme_mod( 'mm_cookie_desc_marketing', __( 'Werden genutzt um Werbung relevanter zu gestalten (z.B. YouTube, Facebook).', 'minecraft-modern-theme' ) );
|
||||||
|
|
||||||
|
$priv_link = $priv_url ? '<a href="' . esc_url($priv_url) . '" target="_blank" rel="noopener noreferrer" class="mmc-priv-link">' . __( 'Datenschutzerklärung', 'minecraft-modern-theme' ) . '</a>' : '';
|
||||||
|
$preview_class = $is_preview ? ' mmc-visible mmc-preview-mode' : '';
|
||||||
|
$inline_style = $is_preview ? '' : 'display:none;';
|
||||||
|
|
||||||
|
// Kategorien-Block (identisch in allen Varianten mit Kategorien)
|
||||||
|
$cats = '<div class="mmc-cats">
|
||||||
|
<div class="mmc-cat"><div class="mmc-cat-row"><span class="mmc-cat-name"><i class="fas fa-shield-alt"></i> ' . __('Notwendige','minecraft-modern-theme') . '</span><span class="mmc-always">' . __('Immer aktiv','minecraft-modern-theme') . '</span></div><p class="mmc-cat-desc">' . esc_html($desc_n) . '</p></div>
|
||||||
|
<div class="mmc-cat"><div class="mmc-cat-row"><label class="mmc-cat-name" for="mmc-stat"><i class="fas fa-chart-bar"></i> ' . __('Statistik','minecraft-modern-theme') . '</label><label class="mmc-toggle"><input type="checkbox" id="mmc-stat" checked><span class="mmc-knob"></span></label></div><p class="mmc-cat-desc">' . esc_html($desc_s) . '</p></div>
|
||||||
|
<div class="mmc-cat"><div class="mmc-cat-row"><label class="mmc-cat-name" for="mmc-mark"><i class="fas fa-bullhorn"></i> ' . __('Marketing','minecraft-modern-theme') . '</label><label class="mmc-toggle"><input type="checkbox" id="mmc-mark"><span class="mmc-knob"></span></label></div><p class="mmc-cat-desc">' . esc_html($desc_m) . '</p></div>
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
$btn_accept = '<button id="mmc-accept" class="mmc-btn mmc-btn-accept"><i class="fas fa-check"></i> ' . __('Alle akzeptieren','minecraft-modern-theme') . '</button>';
|
||||||
|
$btn_select = '<button id="mmc-select" class="mmc-btn mmc-btn-select"><i class="fas fa-sliders-h"></i> ' . __('Auswahl speichern','minecraft-modern-theme') . '</button>';
|
||||||
|
$btn_neces = '<button id="mmc-neces" class="mmc-btn mmc-btn-neces">' . __('Nur notwendige','minecraft-modern-theme') . '</button>';
|
||||||
|
|
||||||
|
$text_esc = wp_kses_post($text);
|
||||||
|
?>
|
||||||
|
<div id="mm-cookie-banner"
|
||||||
|
class="mmc-style-<?php echo esc_attr($style); ?><?php echo $preview_class; ?>"
|
||||||
|
role="dialog" aria-modal="true"
|
||||||
|
style="<?php echo $inline_style; ?>">
|
||||||
|
|
||||||
|
<!-- Overlay (nur für stepper sichtbar, per CSS gesteuert) -->
|
||||||
|
<div class="mmc-overlay"></div>
|
||||||
|
|
||||||
|
<!-- ══ LAYOUT 1: Schmale Bar ══ -->
|
||||||
|
<div class="mmc-layout-bar">
|
||||||
|
<div class="mmc-bar-wrap">
|
||||||
|
<i class="fas fa-cookie-bite mmc-bar-icon"></i>
|
||||||
|
<p class="mmc-text"><?php echo $text_esc; ?> <?php echo $priv_link; ?></p>
|
||||||
|
<div class="mmc-bar-btns"><?php echo $btn_neces; ?><?php echo $btn_accept; ?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ══ LAYOUT 2 (3A): Zweispaltig ══ -->
|
||||||
|
<div class="mmc-layout-split">
|
||||||
|
<div class="mmc-split-left">
|
||||||
|
<i class="fas fa-cookie-bite mmc-split-icon"></i>
|
||||||
|
<h3 class="mmc-split-title"><?php _e('Datenschutz-Einstellungen','minecraft-modern-theme'); ?></h3>
|
||||||
|
<p class="mmc-split-sub"><?php echo $text_esc; ?></p>
|
||||||
|
<?php if ($priv_link) echo '<p class="mmc-split-priv">' . $priv_link . '</p>'; ?>
|
||||||
|
</div>
|
||||||
|
<div class="mmc-split-right">
|
||||||
|
<?php echo $cats; ?>
|
||||||
|
<div class="mmc-split-btns"><?php echo $btn_neces; ?><?php echo $btn_select; ?><?php echo $btn_accept; ?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ══ LAYOUT 3 (3B): Slide-In von rechts ══ -->
|
||||||
|
<div class="mmc-layout-slide">
|
||||||
|
<div class="mmc-slide-header">
|
||||||
|
<div class="mmc-slide-icon"><i class="fas fa-cookie-bite"></i></div>
|
||||||
|
<h3 class="mmc-slide-title"><?php _e('Datenschutz-Einstellungen','minecraft-modern-theme'); ?></h3>
|
||||||
|
</div>
|
||||||
|
<p class="mmc-slide-text"><?php echo $text_esc; ?> <?php echo $priv_link; ?></p>
|
||||||
|
<?php echo $cats; ?>
|
||||||
|
<div class="mmc-slide-btns"><?php echo $btn_accept; ?><?php echo $btn_select; ?><?php echo $btn_neces; ?></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ══ LAYOUT 4 (3C): Stepper ══ -->
|
||||||
|
<div class="mmc-layout-stepper">
|
||||||
|
<div class="mmc-steps">
|
||||||
|
<div class="mmc-step mmc-step-done"><span class="mmc-step-num">✓</span><?php _e('Info','minecraft-modern-theme'); ?></div>
|
||||||
|
<div class="mmc-step mmc-step-active"><span class="mmc-step-num">2</span><?php _e('Auswahl','minecraft-modern-theme'); ?></div>
|
||||||
|
<div class="mmc-step"><span class="mmc-step-num">3</span><?php _e('Fertig','minecraft-modern-theme'); ?></div>
|
||||||
|
</div>
|
||||||
|
<div class="mmc-stepper-body">
|
||||||
|
<p class="mmc-stepper-text"><?php echo $text_esc; ?> <?php echo $priv_link; ?></p>
|
||||||
|
<?php echo $cats; ?>
|
||||||
|
<div class="mmc-stepper-btns"><?php echo $btn_neces; ?><?php echo $btn_select; ?><?php echo $btn_accept; ?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div><!-- #mm-cookie-banner -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function(){
|
||||||
|
var IS_PREVIEW=<?php echo $is_preview?'true':'false';?>;
|
||||||
|
var COOKIE='mm_cookie_consent',DAYS=<?php echo intval($lifetime);?>,GA_ID=<?php echo json_encode($ga_id);?>,STYLE=<?php echo json_encode($style);?>;
|
||||||
|
var BLOCKED=['youtube.com','youtube-nocookie.com','youtu.be','vimeo.com','maps.google.com','google.com/maps','facebook.com','fb.com','twitter.com','platform.twitter.com','tiktok.com','instagram.com','open.spotify.com','twitch.tv'];
|
||||||
|
|
||||||
|
function getCookie(n){var m=document.cookie.match(new RegExp('(?:^|; )'+n.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')+'=([^;]*)'));try{return m?JSON.parse(decodeURIComponent(m[1])):null;}catch(e){return null;}}
|
||||||
|
function setCookie(n,v,d){var e=new Date();e.setDate(e.getDate()+d);document.cookie=n+'='+encodeURIComponent(JSON.stringify(v))+'; expires='+e.toUTCString()+'; path=/; SameSite=Lax';}
|
||||||
|
|
||||||
|
var banner=document.getElementById('mm-cookie-banner');
|
||||||
|
if(!banner)return;
|
||||||
|
|
||||||
|
function getCurrentStyle(){return banner.className.match(/mmc-style-(\w+)/)?banner.className.match(/mmc-style-(\w+)/)[1]:STYLE;}
|
||||||
|
|
||||||
|
function show(){
|
||||||
|
banner.style.display='';
|
||||||
|
var s=getCurrentStyle();
|
||||||
|
if(s==='stepper')document.body.style.overflow='hidden';
|
||||||
|
setTimeout(function(){banner.classList.add('mmc-visible');},30);
|
||||||
|
}
|
||||||
|
function hide(){
|
||||||
|
if(IS_PREVIEW)return;
|
||||||
|
banner.classList.add('mmc-hiding');
|
||||||
|
setTimeout(function(){banner.style.display='none';banner.classList.remove('mmc-hiding','mmc-visible');document.body.style.overflow='';},400);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadGA(id){if(window._mmGaOk)return;window._mmGaOk=true;var s=document.createElement('script');s.async=true;s.src='https://www.googletagmanager.com/gtag/js?id='+id;document.head.appendChild(s);window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config',id,{anonymize_ip:true});}
|
||||||
|
function isBlocked(src){return src&&BLOCKED.some(function(d){return src.indexOf(d)!==-1;});}
|
||||||
|
function blockIframes(){if(IS_PREVIEW)return;document.querySelectorAll('iframe').forEach(function(f){var src=f.getAttribute('src')||f.getAttribute('data-src')||'';if(!isBlocked(src)||f.dataset.mmBlocked)return;f.dataset.mmOrigSrc=src;f.dataset.mmBlocked='1';f.setAttribute('src','about:blank');f.style.display='none';var ph=document.createElement('div');ph.className='mmc-placeholder';ph.innerHTML='<i class="fas fa-cookie-bite"></i><p><?php echo esc_js(__("Inhalt wegen Cookie-Einstellungen blockiert.","minecraft-modern-theme"));?></p><button class="mmc-ph-btn"><?php echo esc_js(__("Einstellungen ändern","minecraft-modern-theme"));?></button>';f.parentNode.insertBefore(ph,f);ph.querySelector('.mmc-ph-btn').addEventListener('click',show);});}
|
||||||
|
function unblockIframes(){document.querySelectorAll('iframe[data-mm-blocked]').forEach(function(f){var prev=f.previousElementSibling;if(prev&&prev.classList.contains('mmc-placeholder'))prev.remove();f.setAttribute('src',f.dataset.mmOrigSrc||'');f.style.display='';delete f.dataset.mmBlocked;});}
|
||||||
|
function applyConsent(c){document.dispatchEvent(new CustomEvent('mm_cookie_consent_set',{detail:c}));if(c.statistics&&GA_ID)loadGA(GA_ID);if(c.marketing){unblockIframes();}else{blockIframes();}}
|
||||||
|
function saveAndClose(stat,mark){var c={necessary:true,statistics:!!stat,marketing:!!mark};setCookie(COOKIE,c,DAYS);applyConsent(c);hide();}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded',function(){
|
||||||
|
var existing=getCookie(COOKIE);
|
||||||
|
// Checkboxen aus allen Layouts referenzieren (nur die ersten sind aktiv)
|
||||||
|
function getStatCb(){return document.querySelector('#mm-cookie-banner .mmc-layout-'+getCurrentStyle()+' #mmc-stat, #mmc-stat');}
|
||||||
|
function getMarkCb(){return document.querySelector('#mm-cookie-banner .mmc-layout-'+getCurrentStyle()+' #mmc-mark, #mmc-mark');}
|
||||||
|
|
||||||
|
if(!IS_PREVIEW&&existing){applyConsent(existing);var s=getStatCb(),m=getMarkCb();if(s)s.checked=!!existing.statistics;if(m)m.checked=!!existing.marketing;}
|
||||||
|
else if(!IS_PREVIEW){blockIframes();setTimeout(show,800);}
|
||||||
|
|
||||||
|
banner.addEventListener('click',function(e){
|
||||||
|
var t=e.target;
|
||||||
|
if(t.id==='mmc-accept'||t.closest('#mmc-accept')){var s=getStatCb(),m=getMarkCb();if(s)s.checked=true;if(m)m.checked=true;saveAndClose(true,true);}
|
||||||
|
else if(t.id==='mmc-select'||t.closest('#mmc-select')){var s=getStatCb(),m=getMarkCb();saveAndClose(s&&s.checked,m&&m.checked);}
|
||||||
|
else if(t.id==='mmc-neces'||t.closest('#mmc-neces')){saveAndClose(false,false);}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
window.mmOpenCookieBanner=show;
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
add_action( 'wp_footer', 'mm_cookie_banner_render' );
|
||||||
|
|
||||||
|
|
||||||
|
// --- 3. Hilfsfunktionen ---
|
||||||
|
function mm_cookie_consent(){if(!isset($_COOKIE['mm_cookie_consent']))return array();$v=json_decode(stripslashes($_COOKIE['mm_cookie_consent']),true);return is_array($v)?$v:array();}
|
||||||
|
function mm_cookie_accepted($category='necessary'){$c=mm_cookie_consent();return!empty($c[$category]);}
|
||||||
|
function mm_cookie_settings_shortcode($atts){$a=shortcode_atts(array('text'=>__('Cookie-Einstellungen','minecraft-modern-theme')),$atts);return '<a href="javascript:void(0)" onclick="if(window.mmOpenCookieBanner)window.mmOpenCookieBanner();" class="mmc-settings-link">'.esc_html($a['text']).'</a>';}
|
||||||
|
add_shortcode('cookie_settings','mm_cookie_settings_shortcode');
|
||||||
|
|
||||||
|
|
||||||
|
// --- 4. Live-Vorschau: nur Klasse + Text wechseln, HTML ist bereits vollständig ---
|
||||||
|
function mm_cookie_banner_preview_js(){
|
||||||
|
if(!is_customize_preview())return; ?>
|
||||||
|
<script>
|
||||||
|
(function(){
|
||||||
|
var ALL=['bar','split','slide','stepper'];
|
||||||
|
wp.customize.bind('preview-ready',function(){
|
||||||
|
|
||||||
|
// Variante wechseln: nur CSS-Klasse tauschen, HTML bleibt
|
||||||
|
wp.customize('mm_cookie_style',function(setting){setting.bind(function(v){
|
||||||
|
var b=document.getElementById('mm-cookie-banner');if(!b)return;
|
||||||
|
ALL.forEach(function(x){b.classList.remove('mmc-style-'+x);});
|
||||||
|
b.classList.add('mmc-style-'+v);
|
||||||
|
// Scroll-Lock für Stepper
|
||||||
|
document.body.style.overflow=(v==='stepper'?'hidden':'');
|
||||||
|
});});
|
||||||
|
|
||||||
|
// Text in allen 4 Layouts gleichzeitig aktualisieren
|
||||||
|
wp.customize('mm_cookie_text',function(setting){setting.bind(function(v){
|
||||||
|
['.mmc-text','.mmc-split-sub','.mmc-slide-text','.mmc-stepper-text'].forEach(function(sel){
|
||||||
|
document.querySelectorAll('#mm-cookie-banner '+sel).forEach(function(el){
|
||||||
|
var lnk=el.querySelector('a.mmc-priv-link');
|
||||||
|
el.textContent=v+' ';
|
||||||
|
if(lnk)el.appendChild(lnk);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});});
|
||||||
|
|
||||||
|
// Banner ein/aus
|
||||||
|
wp.customize('mm_cookie_enabled',function(setting){setting.bind(function(v){
|
||||||
|
var b=document.getElementById('mm-cookie-banner');if(!b)return;
|
||||||
|
if(v){b.style.display='';b.classList.remove('mmc-hiding');setTimeout(function(){b.classList.add('mmc-visible');},30);}
|
||||||
|
else{b.classList.add('mmc-hiding');setTimeout(function(){b.style.display='none';b.classList.remove('mmc-hiding','mmc-visible');},400);}
|
||||||
|
});});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
add_action('customize_preview_init',function(){add_action('wp_footer','mm_cookie_banner_preview_js',99);});
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* FAQ: Custom Post Type, automatische Seite und Template-Loader
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === FAQ Custom Post Type & Taxonomy ===
|
||||||
|
function create_faq_post_type() {
|
||||||
|
if ( get_theme_mod( 'faq_enabled', true ) ) {
|
||||||
|
register_post_type( 'faq', array(
|
||||||
|
'labels' => array(
|
||||||
|
'name' => __( 'FAQs', 'minecraft-modern-theme' ),
|
||||||
|
'singular_name' => __( 'FAQ', 'minecraft-modern-theme' ),
|
||||||
|
'add_new' => __( 'Neue FAQ hinzufügen', 'minecraft-modern-theme' ),
|
||||||
|
'add_new_item' => __( 'Neue FAQ hinzufügen', 'minecraft-modern-theme' ),
|
||||||
|
'edit_item' => __( 'FAQ bearbeiten', 'minecraft-modern-theme' ),
|
||||||
|
'new_item' => __( 'Neue FAQ', 'minecraft-modern-theme' ),
|
||||||
|
'view_item' => __( 'FAQ ansehen', 'minecraft-modern-theme' ),
|
||||||
|
'search_items' => __( 'FAQs durchsuchen', 'minecraft-modern-theme' ),
|
||||||
|
'not_found' => __( 'Keine FAQs gefunden', 'minecraft-modern-theme' ),
|
||||||
|
'not_found_in_trash' => __( 'Keine FAQs im Papierkorb gefunden', 'minecraft-modern-theme' ),
|
||||||
|
'all_items' => __( 'Alle FAQs', 'minecraft-modern-theme' ),
|
||||||
|
),
|
||||||
|
'public' => true,
|
||||||
|
'has_archive' => true,
|
||||||
|
'menu_icon' => 'dashicons-format-chat',
|
||||||
|
'supports' => array( 'title', 'editor', 'page-attributes' ),
|
||||||
|
'rewrite' => array( 'slug' => 'faq' ),
|
||||||
|
'show_in_rest' => true,
|
||||||
|
) );
|
||||||
|
register_taxonomy( 'faq_category', 'faq', array(
|
||||||
|
'label' => __( 'FAQ Kategorien', 'minecraft-modern-theme' ),
|
||||||
|
'rewrite' => array( 'slug' => 'faq-kategorie' ),
|
||||||
|
'hierarchical' => true,
|
||||||
|
'show_in_rest' => true,
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'init', 'create_faq_post_type' );
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// FAQ-Seitenerstellung
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
function create_faq_page_automatically() {
|
||||||
|
if ( ! get_theme_mod( 'faq_enabled', true ) ) return;
|
||||||
|
|
||||||
|
// BUG-FIX: get_page_by_title() ist seit WP 6.2 deprecated. Ersetzt durch WP_Query.
|
||||||
|
$faq_query = new WP_Query( array(
|
||||||
|
'post_type' => 'page',
|
||||||
|
'title' => 'FAQ',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'posts_per_page' => 1,
|
||||||
|
'no_found_rows' => true,
|
||||||
|
'update_post_meta_cache' => false,
|
||||||
|
'update_post_term_cache' => false,
|
||||||
|
) );
|
||||||
|
if ( $faq_query->have_posts() ) return;
|
||||||
|
|
||||||
|
wp_insert_post( array(
|
||||||
|
'post_title' => 'FAQ',
|
||||||
|
'post_content' => 'Diese Seite zeigt alle FAQs an. Der Inhalt wird automatisch generiert.',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'post_type' => 'page',
|
||||||
|
'post_author' => 1,
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'customize_save_after', 'create_faq_page_automatically' );
|
||||||
|
|
||||||
|
|
||||||
|
function load_faq_page_template( $template ) {
|
||||||
|
if ( get_theme_mod( 'faq_enabled', true ) && is_page() ) {
|
||||||
|
global $post;
|
||||||
|
if ( $post && $post->post_title === 'FAQ' ) {
|
||||||
|
// BUG-FIX: get_template_directory() erzwang das Parent-Template und
|
||||||
|
// ignorierte ein archive-faq.php im Child-Theme. locate_template()
|
||||||
|
// bevorzugt das Child-Theme und fällt sonst aufs Parent zurück.
|
||||||
|
$t = locate_template( 'archive-faq.php' );
|
||||||
|
if ( $t ) return $t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
add_filter( 'template_include', 'load_faq_page_template' );
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Automatische Erstellung der statischen Startseite
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Automatische "Home" Seitenerstellung
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
function set_static_front_page_automatically() {
|
||||||
|
if ( 'page' !== get_option( 'show_on_front' ) ) {
|
||||||
|
// BUG-FIX: get_page_by_title() ist seit WP 6.2 deprecated. Ersetzt durch WP_Query.
|
||||||
|
$home_query = new WP_Query( array(
|
||||||
|
'post_type' => 'page',
|
||||||
|
'title' => 'Home',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'posts_per_page' => 1,
|
||||||
|
'no_found_rows' => true,
|
||||||
|
'update_post_meta_cache' => false,
|
||||||
|
'update_post_term_cache' => false,
|
||||||
|
) );
|
||||||
|
$home_page = $home_query->have_posts() ? $home_query->posts[0] : null;
|
||||||
|
if ( ! $home_page ) {
|
||||||
|
$home_page_id = wp_insert_post( array(
|
||||||
|
'post_title' => 'Home',
|
||||||
|
'post_content' => 'Diese Seite dient als statische Startseite.',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'post_type' => 'page',
|
||||||
|
'post_author' => 1,
|
||||||
|
) );
|
||||||
|
} else {
|
||||||
|
$home_page_id = $home_page->ID;
|
||||||
|
}
|
||||||
|
if ( $home_page_id ) {
|
||||||
|
update_option( 'show_on_front', 'page' );
|
||||||
|
update_option( 'page_on_front', $home_page_id );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'after_switch_theme', 'set_static_front_page_automatically' );
|
||||||
|
|
||||||
|
|
||||||
|
function add_home_body_class( $classes ) {
|
||||||
|
if ( is_front_page() && ! get_theme_mod( 'show_home_title', true ) ) {
|
||||||
|
$classes[] = 'home-title-hidden';
|
||||||
|
}
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
|
add_filter( 'body_class', 'add_home_body_class' );
|
||||||
@@ -0,0 +1,308 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Header-Hilfsfunktionen, Menue-Layouts und Beitrags-Sidebar
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// MENÜ-LAYOUTS: Hilfsfunktionen für header.php
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
if ( ! function_exists('mm_branding') ) :
|
||||||
|
function mm_branding( $show_title_with_logo = false ) { ?>
|
||||||
|
<div class="site-branding">
|
||||||
|
<?php if ( function_exists('the_custom_logo') && has_custom_logo() ) : ?>
|
||||||
|
<?php the_custom_logo(); ?>
|
||||||
|
<?php if ( $show_title_with_logo ) : ?>
|
||||||
|
<p class="site-title">
|
||||||
|
<a href="<?php echo esc_url( home_url('/') ); ?>" rel="home"><?php bloginfo('name'); ?></a>
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php if ( is_front_page() && is_home() ) : ?>
|
||||||
|
<h1 class="site-title"><a href="<?php echo esc_url( home_url('/') ); ?>" rel="home"><?php bloginfo('name'); ?></a></h1>
|
||||||
|
<?php else : ?>
|
||||||
|
<p class="site-title"><a href="<?php echo esc_url( home_url('/') ); ?>" rel="home"><?php bloginfo('name'); ?></a></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php }
|
||||||
|
endif;
|
||||||
|
|
||||||
|
if ( ! function_exists('mm_nav') ) :
|
||||||
|
function mm_nav( $extra_class = '' ) {
|
||||||
|
$menu_style = get_theme_mod( 'header_menu_style', 'classic' );
|
||||||
|
?>
|
||||||
|
<nav id="site-navigation" class="main-navigation <?php echo esc_attr($extra_class); ?>" role="navigation"
|
||||||
|
aria-label="<?php esc_attr_e('Hauptmenü', 'minecraft-modern-theme'); ?>">
|
||||||
|
<?php
|
||||||
|
// BUG-FIX: .menu-toggle nur für Classic / Centered / Mega ausgeben.
|
||||||
|
// Im Sidebar-Layout sitzt die Navigation im <aside> Panel –
|
||||||
|
// der Hamburger wird dort nicht gebraucht und verursacht JS-Konflikte.
|
||||||
|
if ( $menu_style !== 'sidebar' ) : ?>
|
||||||
|
<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false">
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php wp_nav_menu( array(
|
||||||
|
'theme_location' => 'primary',
|
||||||
|
'container' => false,
|
||||||
|
'menu_class' => 'primary-menu',
|
||||||
|
'fallback_cb' => false,
|
||||||
|
) ); ?>
|
||||||
|
</nav>
|
||||||
|
<?php }
|
||||||
|
endif;
|
||||||
|
|
||||||
|
if ( ! function_exists('mm_icons') ) :
|
||||||
|
function mm_icons() {
|
||||||
|
$social_icons = array(
|
||||||
|
'bluesky' => 'fab fa-bluesky', 'discord' => 'fab fa-discord', 'youtube' => 'fab fa-youtube',
|
||||||
|
'twitter' => 'fab fa-x-twitter', 'facebook' => 'fab fa-facebook-f',
|
||||||
|
'instagram' => 'fab fa-instagram', 'tiktok' => 'fab fa-tiktok',
|
||||||
|
'twitch' => 'fab fa-twitch', 'steam' => 'fab fa-steam',
|
||||||
|
'github' => 'fab fa-github', 'linkedin' => 'fab fa-linkedin-in',
|
||||||
|
'pinterest' => 'fab fa-pinterest-p', 'reddit' => 'fab fa-reddit-alien',
|
||||||
|
'mastodon' => 'fab fa-mastodon', 'threads' => 'fab fa-threads',
|
||||||
|
'kickstarter' => 'fab fa-kickstarter', 'teamspeak' => 'fab fa-teamspeak', 'spotify' => 'fab fa-spotify',
|
||||||
|
'stoat' => 'fab fa-diaspora',
|
||||||
|
); ?>
|
||||||
|
<div class="header-info">
|
||||||
|
<div class="header-search">
|
||||||
|
<button class="header-search-toggle" aria-label="<?php esc_attr_e('Suche öffnen', 'minecraft-modern-theme'); ?>" aria-expanded="false">
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
</button>
|
||||||
|
<div class="header-search-dropdown" aria-hidden="true">
|
||||||
|
<?php get_search_form(); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="social-links">
|
||||||
|
<?php foreach ( $social_icons as $key => $class ) :
|
||||||
|
$url = get_theme_mod( 'social_' . $key );
|
||||||
|
if ( $url ) echo '<a href="' . esc_url($url) . '" target="_blank" rel="noopener noreferrer" aria-label="' . esc_attr($key) . '"><i class="' . esc_attr($class) . '"></i></a>';
|
||||||
|
endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php }
|
||||||
|
endif;
|
||||||
|
|
||||||
|
|
||||||
|
// === Menü-Design Customizer-Einstellung ===
|
||||||
|
function minecraft_modern_menu_style_customizer( $wp_customize ) {
|
||||||
|
$wp_customize->add_section( 'header_menu_style_section', array(
|
||||||
|
'title' => __( 'Menü-Design', 'minecraft-modern-theme' ),
|
||||||
|
'priority' => 30,
|
||||||
|
) );
|
||||||
|
$wp_customize->add_setting( 'header_menu_style', array(
|
||||||
|
'default' => 'classic',
|
||||||
|
'sanitize_callback' => 'sanitize_text_field',
|
||||||
|
'transport' => 'refresh',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'header_menu_style', array(
|
||||||
|
'label' => __( 'Menü-Layout wählen', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'header_menu_style_section',
|
||||||
|
'type' => 'select',
|
||||||
|
'choices' => array(
|
||||||
|
'classic' => __( '① Classic – Logo links, Menü Mitte, Icons rechts', 'minecraft-modern-theme' ),
|
||||||
|
'centered' => __( '② Zentriert – Logo oben, Menü darunter', 'minecraft-modern-theme' ),
|
||||||
|
'sidebar' => __( '③ Sidebar – Menü als vertikale Leiste', 'minecraft-modern-theme' ),
|
||||||
|
'mega' => __( '④ Mega-Menü – breite Dropdown-Spalten', 'minecraft-modern-theme' ),
|
||||||
|
),
|
||||||
|
) );
|
||||||
|
|
||||||
|
// Branding-Position (gilt für alle Layouts)
|
||||||
|
$wp_customize->add_setting( 'sidebar_branding_position', array(
|
||||||
|
'default' => 'left',
|
||||||
|
'sanitize_callback' => 'sanitize_text_field',
|
||||||
|
'transport' => 'refresh',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'sidebar_branding_position', array(
|
||||||
|
'label' => __( 'Logo/Titel Position', 'minecraft-modern-theme' ),
|
||||||
|
'description' => __( 'Gilt für alle Menü-Layouts.', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'header_menu_style_section',
|
||||||
|
'type' => 'select',
|
||||||
|
'choices' => array(
|
||||||
|
'left' => __( 'Links', 'minecraft-modern-theme' ),
|
||||||
|
'center' => __( 'Mitte', 'minecraft-modern-theme' ),
|
||||||
|
'right' => __( 'Rechts', 'minecraft-modern-theme' ),
|
||||||
|
),
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'customize_register', 'minecraft_modern_menu_style_customizer' );
|
||||||
|
|
||||||
|
|
||||||
|
// === Sidebar-Menü JavaScript (nur wenn Sidebar-Layout aktiv) ===
|
||||||
|
function minecraft_modern_sidebar_menu_script() {
|
||||||
|
if ( get_theme_mod( 'header_menu_style', 'classic' ) !== 'sidebar' ) return;
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var toggle = document.querySelector('.sidebar-menu-toggle');
|
||||||
|
var sidebar = document.getElementById('header-sidebar');
|
||||||
|
var closeBtn = document.querySelector('.sidebar-menu-close');
|
||||||
|
|
||||||
|
// BUG-FIX: Overlay NICHT mehr per JS erstellen.
|
||||||
|
// header.php gibt bereits <div id="sidebar-overlay"> aus.
|
||||||
|
// Das alte createElement() erzeugte ein ZWEITES Overlay-Div,
|
||||||
|
// was zu doppelten Klick-Handlern und visuellem Flickern führte.
|
||||||
|
var overlay = document.getElementById('sidebar-overlay');
|
||||||
|
|
||||||
|
if (!toggle || !sidebar) return;
|
||||||
|
|
||||||
|
function openSidebar() {
|
||||||
|
sidebar.classList.add('is-open');
|
||||||
|
sidebar.setAttribute('aria-hidden', 'false');
|
||||||
|
toggle.setAttribute('aria-expanded', 'true');
|
||||||
|
if (overlay) overlay.classList.add('is-visible');
|
||||||
|
document.body.classList.add('sidebar-nav-open');
|
||||||
|
}
|
||||||
|
function closeSidebar() {
|
||||||
|
sidebar.classList.remove('is-open');
|
||||||
|
sidebar.setAttribute('aria-hidden', 'true');
|
||||||
|
toggle.setAttribute('aria-expanded', 'false');
|
||||||
|
if (overlay) overlay.classList.remove('is-visible');
|
||||||
|
document.body.classList.remove('sidebar-nav-open');
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle.addEventListener('click', openSidebar);
|
||||||
|
if (closeBtn) closeBtn.addEventListener('click', closeSidebar);
|
||||||
|
if (overlay) overlay.addEventListener('click', closeSidebar);
|
||||||
|
document.addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Escape') closeSidebar();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
add_action( 'wp_footer', 'minecraft_modern_sidebar_menu_script' );
|
||||||
|
|
||||||
|
|
||||||
|
// Such-Toggle wird von header-scroll.js behandelt.
|
||||||
|
|
||||||
|
|
||||||
|
// === Single-Post Sidebar registrieren ===
|
||||||
|
function minecraft_modern_single_sidebar() {
|
||||||
|
register_sidebar( array(
|
||||||
|
'name' => __( 'Beitrag Sidebar', 'minecraft-modern-theme' ),
|
||||||
|
'id' => 'single-post-sidebar',
|
||||||
|
'description' => __( 'Widget-Bereich für die Sidebar auf Einzelbeitrags-Seiten.', 'minecraft-modern-theme' ),
|
||||||
|
'before_widget' => '<div id="%1$s" class="widget %2$s sidebar-widget">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3 class="widget-title">',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'widgets_init', 'minecraft_modern_single_sidebar' );
|
||||||
|
|
||||||
|
|
||||||
|
// === Single-Post Sidebar Render-Funktion ===
|
||||||
|
function minecraft_modern_render_single_sidebar() {
|
||||||
|
if ( is_active_sidebar( 'single-post-sidebar' ) ) {
|
||||||
|
dynamic_sidebar( 'single-post-sidebar' );
|
||||||
|
} else {
|
||||||
|
?>
|
||||||
|
<div class="sidebar-widget widget_search">
|
||||||
|
<h3 class="widget-title"><?php _e('Suche', 'minecraft-modern-theme'); ?></h3>
|
||||||
|
<?php get_search_form(); ?>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-widget widget_recent_entries">
|
||||||
|
<h3 class="widget-title"><?php _e('Letzte Beiträge', 'minecraft-modern-theme'); ?></h3>
|
||||||
|
<?php $recent = new WP_Query( array( 'posts_per_page' => 5, 'post_status' => 'publish' ) );
|
||||||
|
if ( $recent->have_posts() ) : ?>
|
||||||
|
<ul class="sidebar-recent-posts">
|
||||||
|
<?php while ( $recent->have_posts() ) : $recent->the_post(); ?>
|
||||||
|
<li>
|
||||||
|
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
||||||
|
<span class="sidebar-post-date"><i class="fas fa-calendar-alt"></i> <?php echo esc_html( get_the_date() ); ?></span>
|
||||||
|
</li>
|
||||||
|
<?php endwhile; wp_reset_postdata(); ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-widget widget_categories">
|
||||||
|
<h3 class="widget-title"><?php _e('Kategorien', 'minecraft-modern-theme'); ?></h3>
|
||||||
|
<ul class="sidebar-categories">
|
||||||
|
<?php wp_list_categories( array( 'show_count' => true, 'title_li' => '', 'orderby' => 'count', 'order' => 'DESC', 'number' => 10 ) ); ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-widget widget_tag_cloud">
|
||||||
|
<h3 class="widget-title"><?php _e('Schlagwörter', 'minecraft-modern-theme'); ?></h3>
|
||||||
|
<?php wp_tag_cloud( array( 'smallest' => 11, 'largest' => 16, 'unit' => 'px', 'number' => 30, 'format' => 'flat', 'orderby' => 'count', 'order' => 'DESC' ) ); ?>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-widget sidebar-archive-dropdown">
|
||||||
|
<h3 class="widget-title"><?php _e('Archiv', 'minecraft-modern-theme'); ?></h3>
|
||||||
|
<select class="archive-select" onchange="if(this.value) window.location.href=this.value;">
|
||||||
|
<option value=""><?php _e('Monat auswählen', 'minecraft-modern-theme'); ?></option>
|
||||||
|
<?php wp_get_archives( array( 'type' => 'monthly', 'format' => 'option', 'show_post_count' => true ) ); ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Archiv-Widget Liste → Dropdown per JS umwandeln
|
||||||
|
function minecraft_modern_archive_to_dropdown() {
|
||||||
|
if ( ! is_single() ) return;
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
document.querySelectorAll('.single-sidebar .widget_archive').forEach(function(widget) {
|
||||||
|
var list = widget.querySelector('ul');
|
||||||
|
if (!list) return;
|
||||||
|
var select = document.createElement('select');
|
||||||
|
select.className = 'archive-select';
|
||||||
|
select.innerHTML = '<option value="">Monat auswählen</option>';
|
||||||
|
list.querySelectorAll('a').forEach(function(a) {
|
||||||
|
var opt = document.createElement('option');
|
||||||
|
opt.value = a.href;
|
||||||
|
opt.textContent = a.textContent;
|
||||||
|
select.appendChild(opt);
|
||||||
|
});
|
||||||
|
select.addEventListener('change', function() { if (this.value) window.location.href = this.value; });
|
||||||
|
list.replaceWith(select);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
add_action( 'wp_footer', 'minecraft_modern_archive_to_dropdown' );
|
||||||
|
|
||||||
|
|
||||||
|
// === Single-Post Sidebar Customizer-Einstellungen ===
|
||||||
|
function minecraft_modern_single_sidebar_customizer( $wp_customize ) {
|
||||||
|
$wp_customize->add_section( 'single_sidebar_section', array(
|
||||||
|
'title' => __( 'Beitrag Sidebar', 'minecraft-modern-theme' ),
|
||||||
|
'priority' => 55,
|
||||||
|
) );
|
||||||
|
$wp_customize->add_setting( 'single_sidebar_enabled', array(
|
||||||
|
'default' => true,
|
||||||
|
'sanitize_callback' => 'wp_validate_boolean',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'single_sidebar_enabled', array(
|
||||||
|
'label' => __( 'Sidebar auf Einzelbeiträgen anzeigen', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'single_sidebar_section',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_setting( 'single_sidebar_position', array(
|
||||||
|
'default' => 'right',
|
||||||
|
'sanitize_callback' => 'sanitize_text_field',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'single_sidebar_position', array(
|
||||||
|
'label' => __( 'Sidebar-Position', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'single_sidebar_section',
|
||||||
|
'type' => 'select',
|
||||||
|
'choices' => array(
|
||||||
|
'right' => __( 'Rechts', 'minecraft-modern-theme' ),
|
||||||
|
'left' => __( 'Links', 'minecraft-modern-theme' ),
|
||||||
|
),
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'customize_register', 'minecraft_modern_single_sidebar_customizer' );
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Eigene Login-URL statt /wp-login.php
|
||||||
|
*
|
||||||
|
* Der Slug wird im Customizer unter "Login-URL" gesetzt. Ist die Funktion aktiv,
|
||||||
|
* beantwortet WordPress das Login-Formular nur noch unter der eigenen Adresse;
|
||||||
|
* /wp-login.php und /wp-admin leiten für Nicht-Angemeldete auf die Startseite.
|
||||||
|
*
|
||||||
|
* WICHTIG - bewusst offen gelassen:
|
||||||
|
* - wp-admin/admin-ajax.php (Frontend-Plugins UND der OAuth-Rückkanal von
|
||||||
|
* Authentik: home_url('/wp-admin/admin-ajax.php?action=authentik_callback'))
|
||||||
|
* - wp-admin/admin-post.php (u. a. der Einstellungs-Export dieses Themes)
|
||||||
|
*
|
||||||
|
* NOTFALL - falls du dich aussperrst:
|
||||||
|
* In wp-config.php diese Zeile ergänzen, dann ist /wp-login.php sofort
|
||||||
|
* wieder erreichbar:
|
||||||
|
* define( 'MM_DISABLE_LOGIN_SLUG', true );
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slugs, die nicht verwendet werden dürfen (Kollision mit WordPress selbst).
|
||||||
|
*/
|
||||||
|
function mm_login_slug_reserviert() {
|
||||||
|
return array(
|
||||||
|
'wp-admin', 'wp-login', 'wp-login.php', 'wp-content', 'wp-includes',
|
||||||
|
'admin-ajax', 'admin-ajax.php', 'admin-post', 'admin-post.php',
|
||||||
|
'wp-json', 'feed', 'rss', 'rss2', 'index', 'index.php', 'xmlrpc.php',
|
||||||
|
'wp-cron.php', 'wp-signup.php', 'wp-activate.php',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liefert den aktiven Login-Slug - oder '' wenn die Funktion nicht greift.
|
||||||
|
*/
|
||||||
|
function mm_login_slug_get() {
|
||||||
|
// Notfall-Schalter aus wp-config.php hat immer Vorrang
|
||||||
|
if ( defined( 'MM_DISABLE_LOGIN_SLUG' ) && MM_DISABLE_LOGIN_SLUG ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if ( ! get_theme_mod( 'mm_login_slug_enabled', false ) ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$slug = trim( (string) get_theme_mod( 'mm_login_slug', '' ), '/' );
|
||||||
|
if ( $slug === '' || in_array( $slug, mm_login_slug_reserviert(), true ) ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return $slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pfad der aktuellen Anfrage, relativ zum WordPress-Stammverzeichnis.
|
||||||
|
* Berücksichtigt Installationen in einem Unterordner.
|
||||||
|
*/
|
||||||
|
function mm_login_slug_current_path() {
|
||||||
|
if ( empty( $_SERVER['REQUEST_URI'] ) ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$path = (string) wp_parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
|
||||||
|
$path = trim( $path, '/' );
|
||||||
|
|
||||||
|
$home = trim( (string) wp_parse_url( home_url(), PHP_URL_PATH ), '/' );
|
||||||
|
if ( $home !== '' && ( $path === $home || strpos( $path, $home . '/' ) === 0 ) ) {
|
||||||
|
$path = trim( substr( $path, strlen( $home ) ), '/' );
|
||||||
|
}
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ersetzt wp-login.php-Adressen durch die eigene Login-URL.
|
||||||
|
* Der Query-String bleibt erhalten (redirect_to, action=logout, interim-login ...).
|
||||||
|
*/
|
||||||
|
function mm_login_slug_rewrite_url( $url ) {
|
||||||
|
$slug = mm_login_slug_get();
|
||||||
|
if ( ! $slug || ! is_string( $url ) || strpos( $url, 'wp-login.php' ) === false ) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
$teile = explode( '?', $url, 2 );
|
||||||
|
$query = isset( $teile[1] ) ? $teile[1] : '';
|
||||||
|
$neu = home_url( '/' . $slug . '/' );
|
||||||
|
|
||||||
|
return $query !== '' ? $neu . '?' . $query : $neu;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_filter( 'login_url', 'mm_login_slug_rewrite_url', 20 );
|
||||||
|
add_filter( 'logout_url', 'mm_login_slug_rewrite_url', 20 );
|
||||||
|
add_filter( 'lostpassword_url', 'mm_login_slug_rewrite_url', 20 );
|
||||||
|
add_filter( 'register_url', 'mm_login_slug_rewrite_url', 20 );
|
||||||
|
add_filter( 'wp_redirect', 'mm_login_slug_rewrite_url', 20 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* site_url()/network_site_url() umschreiben, damit auch das Formular-Ziel
|
||||||
|
* (action="...wp-login.php") auf die eigene Adresse zeigt.
|
||||||
|
*
|
||||||
|
* Hinweis: Das Authentik-Plugin baut seine redirect_uri bewusst über home_url()
|
||||||
|
* und ist von diesem Filter deshalb nicht betroffen.
|
||||||
|
*/
|
||||||
|
function mm_login_slug_filter_site_url( $url, $path = '', $scheme = null ) {
|
||||||
|
return mm_login_slug_rewrite_url( $url );
|
||||||
|
}
|
||||||
|
add_filter( 'site_url', 'mm_login_slug_filter_site_url', 20, 3 );
|
||||||
|
add_filter( 'network_site_url', 'mm_login_slug_filter_site_url', 20, 3 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernstück: Anfragen abfangen, bevor WordPress die Query auflöst.
|
||||||
|
*/
|
||||||
|
function mm_login_slug_handle_request() {
|
||||||
|
$slug = mm_login_slug_get();
|
||||||
|
if ( ! $slug ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = mm_login_slug_current_path();
|
||||||
|
if ( $path === '' ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1) Eigene Login-Adresse -> wp-login.php ausliefern
|
||||||
|
if ( $path === $slug ) {
|
||||||
|
global $pagenow, $error, $interim_login, $action, $user_login;
|
||||||
|
$pagenow = 'wp-login.php';
|
||||||
|
require_once ABSPATH . 'wp-login.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Alte Login-Adresse -> Startseite
|
||||||
|
if ( $path === 'wp-login.php' ) {
|
||||||
|
wp_safe_redirect( home_url( '/' ), 302 );
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) /wp-admin für Nicht-Angemeldete -> Startseite.
|
||||||
|
// admin-ajax.php und admin-post.php bleiben offen, sonst brechen
|
||||||
|
// Frontend-AJAX und der Authentik-OAuth-Rückkanal.
|
||||||
|
if ( $path === 'wp-admin' || strpos( $path, 'wp-admin/' ) === 0 ) {
|
||||||
|
$datei = basename( $path );
|
||||||
|
$erlaubt = array( 'admin-ajax.php', 'admin-post.php' );
|
||||||
|
|
||||||
|
if ( ! in_array( $datei, $erlaubt, true ) && ! is_user_logged_in() ) {
|
||||||
|
wp_safe_redirect( home_url( '/' ), 302 );
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'init', 'mm_login_slug_handle_request', 1 );
|
||||||
|
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// CUSTOMIZER: Login-URL einstellen
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
function mm_login_slug_sanitize( $value ) {
|
||||||
|
$value = sanitize_title( (string) $value );
|
||||||
|
return in_array( $value, mm_login_slug_reserviert(), true ) ? '' : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prüft die Eingabe und meldet Kollisionen direkt im Customizer zurück,
|
||||||
|
* statt sie stillschweigend zu verwerfen.
|
||||||
|
*/
|
||||||
|
function mm_login_slug_validate( $validity, $value ) {
|
||||||
|
$value = sanitize_title( (string) $value );
|
||||||
|
|
||||||
|
if ( $value === '' ) {
|
||||||
|
return $validity; // leer ist erlaubt (= Funktion greift nicht)
|
||||||
|
}
|
||||||
|
if ( in_array( $value, mm_login_slug_reserviert(), true ) ) {
|
||||||
|
$validity->add( 'reserviert', __( 'Dieser Pfad ist von WordPress belegt. Bitte einen anderen wählen.', 'minecraft-modern-theme' ) );
|
||||||
|
return $validity;
|
||||||
|
}
|
||||||
|
// Kollision mit einer bestehenden Seite/Beitrag?
|
||||||
|
$vorhanden = get_page_by_path( $value, OBJECT, array( 'page', 'post' ) );
|
||||||
|
if ( $vorhanden ) {
|
||||||
|
$validity->add( 'belegt', sprintf(
|
||||||
|
/* translators: %s: Titel des kollidierenden Inhalts */
|
||||||
|
__( 'Der Pfad wird bereits von "%s" verwendet - diese Seite wäre dann nicht mehr erreichbar.', 'minecraft-modern-theme' ),
|
||||||
|
$vorhanden->post_title
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
return $validity;
|
||||||
|
}
|
||||||
|
add_filter( 'customize_validate_mm_login_slug', 'mm_login_slug_validate', 10, 2 );
|
||||||
|
|
||||||
|
function mm_login_slug_customizer( $wp_customize ) {
|
||||||
|
$notfall = "define( 'MM_DISABLE_LOGIN_SLUG', true );";
|
||||||
|
|
||||||
|
$wp_customize->add_section( 'mm_login_url_section', array(
|
||||||
|
'title' => __( 'Login-URL', 'minecraft-modern-theme' ),
|
||||||
|
'priority' => 85,
|
||||||
|
'description' => __( 'Ersetzt die Standard-Adresse /wp-login.php durch einen eigenen Pfad und reduziert so automatisierte Anmeldeversuche.', 'minecraft-modern-theme' )
|
||||||
|
. '<br><br><strong>' . esc_html__( 'Notfall:', 'minecraft-modern-theme' ) . '</strong> '
|
||||||
|
. esc_html__( 'Diese Zeile in die wp-config.php eintragen, dann ist /wp-login.php sofort wieder erreichbar:', 'minecraft-modern-theme' )
|
||||||
|
. '<br><code>' . esc_html( $notfall ) . '</code>',
|
||||||
|
) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_login_slug', array(
|
||||||
|
'default' => '',
|
||||||
|
'sanitize_callback' => 'mm_login_slug_sanitize',
|
||||||
|
'transport' => 'refresh',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'mm_login_slug', array(
|
||||||
|
'label' => __( 'Eigener Login-Pfad', 'minecraft-modern-theme' ),
|
||||||
|
'description' => sprintf(
|
||||||
|
/* translators: %s: Beispiel-URL */
|
||||||
|
__( 'Nur der Pfad, ohne Schrägstriche. Ergibt: %s', 'minecraft-modern-theme' ),
|
||||||
|
'<code>' . esc_html( home_url( '/' ) ) . 'DEIN-PFAD/</code>'
|
||||||
|
),
|
||||||
|
'section' => 'mm_login_url_section',
|
||||||
|
'type' => 'text',
|
||||||
|
) );
|
||||||
|
|
||||||
|
$wp_customize->add_setting( 'mm_login_slug_enabled', array(
|
||||||
|
'default' => false,
|
||||||
|
'sanitize_callback' => 'wp_validate_boolean',
|
||||||
|
'transport' => 'refresh',
|
||||||
|
) );
|
||||||
|
$wp_customize->add_control( 'mm_login_slug_enabled', array(
|
||||||
|
'label' => __( 'Eigene Login-URL aktivieren', 'minecraft-modern-theme' ),
|
||||||
|
'description' => __( 'Erst aktivieren, wenn oben ein Pfad eingetragen und gespeichert ist. Notiere dir die neue Adresse, bevor du dich abmeldest!', 'minecraft-modern-theme' ),
|
||||||
|
'section' => 'mm_login_url_section',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'customize_register', 'mm_login_slug_customizer' );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hinweis im Adminbereich mit der aktuell gültigen Login-Adresse.
|
||||||
|
*/
|
||||||
|
function mm_login_slug_admin_notice() {
|
||||||
|
$slug = mm_login_slug_get();
|
||||||
|
if ( ! $slug || ! current_user_can( 'manage_options' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$screen = get_current_screen();
|
||||||
|
if ( ! $screen || ! in_array( $screen->id, array( 'dashboard', 'themes' ), true ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf(
|
||||||
|
'<div class="notice notice-info"><p>%s <code>%s</code></p></div>',
|
||||||
|
esc_html__( 'Die Anmeldung erfolgt auf dieser Seite über:', 'minecraft-modern-theme' ),
|
||||||
|
esc_html( home_url( '/' . $slug . '/' ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_action( 'admin_notices', 'mm_login_slug_admin_notice' );
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Anpassungen der WordPress-Login-Seite
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// CUSTOM LOGIN FUNCTIONS
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
function minecraft_modern_login_assets() {
|
||||||
|
wp_enqueue_style(
|
||||||
|
'minecraft-modern-login-style',
|
||||||
|
get_template_directory_uri() . '/css/login-style.css',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/css/login-style.css' )
|
||||||
|
);
|
||||||
|
// Font Awesome lokal (identisches Handle wie im Frontend – kein Doppel-Laden)
|
||||||
|
wp_enqueue_style(
|
||||||
|
'font-awesome',
|
||||||
|
get_template_directory_uri() . '/css/fontawesome.min.css',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/css/fontawesome.min.css' )
|
||||||
|
);
|
||||||
|
|
||||||
|
// FIX: login-slider.js – erster Slide sofort sichtbar (fixiert)
|
||||||
|
wp_enqueue_script( 'minecraft-avatar-slider-script', get_template_directory_uri() . '/js/login-slider.js', array( 'jquery' ), filemtime( get_template_directory() . '/js/login-slider.js' ), true );
|
||||||
|
wp_enqueue_script( 'minecraft-modern-login-script', get_template_directory_uri() . '/js/login-script.js', array( 'jquery' ), filemtime( get_template_directory() . '/js/login-script.js' ), true );
|
||||||
|
|
||||||
|
wp_add_inline_script( 'minecraft-modern-login-script', "
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
$('.forgetmenot, #nav').wrapAll('<div class=\"login-options-container\"></div>');
|
||||||
|
});
|
||||||
|
" );
|
||||||
|
|
||||||
|
$slider_speed = get_theme_mod( 'login_avatar_slider_speed', 4 );
|
||||||
|
wp_localize_script( 'minecraft-avatar-slider-script', 'avatarSliderSettings', array(
|
||||||
|
'speed' => $slider_speed * 1000,
|
||||||
|
) );
|
||||||
|
|
||||||
|
$login_bg_image = get_theme_mod( 'login_background_image' );
|
||||||
|
if ( $login_bg_image ) {
|
||||||
|
wp_add_inline_style( 'minecraft-modern-login-style', "body.login { background-image: url('" . esc_url( $login_bg_image ) . "') !important; }" );
|
||||||
|
}
|
||||||
|
$logo_url = get_theme_mod( 'login_logo' );
|
||||||
|
if ( $logo_url ) {
|
||||||
|
wp_add_inline_style( 'minecraft-modern-login-style', ".login h1 a { background-image: url('" . esc_url( $logo_url ) . "') !important; }" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'login_enqueue_scripts', 'minecraft_modern_login_assets' );
|
||||||
|
|
||||||
|
|
||||||
|
function add_minecraft_avatar_slider_to_login() {
|
||||||
|
$avatar_html = '<div id="minecraft-avatar-slider">';
|
||||||
|
$has_avatars = false;
|
||||||
|
|
||||||
|
for ( $i = 1; $i <= 5; $i++ ) {
|
||||||
|
$uuid = get_theme_mod( 'login_avatar_uuid_' . $i );
|
||||||
|
if ( ! empty( $uuid ) ) {
|
||||||
|
$has_avatars = true;
|
||||||
|
$avatar_url = 'https://visage.surgeplay.com/full/' . $uuid . '.png';
|
||||||
|
// FIX: Klasse wird hier gesetzt, JS überschreibt sie trotzdem (kompatibel)
|
||||||
|
$active_class = ( $i === 1 ) ? 'avatar-slide avatar-slide-active' : 'avatar-slide';
|
||||||
|
$avatar_html .= '<img class="' . esc_attr( $active_class ) . '" src="' . esc_url( $avatar_url ) . '" alt="Minecraft Avatar ' . $i . '">';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$avatar_html .= '</div>';
|
||||||
|
|
||||||
|
if ( $has_avatars ) {
|
||||||
|
echo $avatar_html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'login_form', 'add_minecraft_avatar_slider_to_login' );
|
||||||
|
|
||||||
|
|
||||||
|
function add_post_login_links() {
|
||||||
|
?>
|
||||||
|
<div class="post-login-links">
|
||||||
|
<a href="<?php echo esc_url( home_url() ); ?>">← Zu <?php bloginfo( 'name' ); ?></a>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
add_action( 'login_form_bottom', 'add_post_login_links' );
|
||||||
|
|
||||||
|
|
||||||
|
function customize_login_page() {
|
||||||
|
add_filter( 'login_display_language_dropdown', '__return_false' );
|
||||||
|
add_filter( 'login_display_back_to_blog', '__return_false' );
|
||||||
|
}
|
||||||
|
add_action( 'login_head', 'customize_login_page' );
|
||||||
|
|
||||||
|
function custom_login_url() { return home_url(); }
|
||||||
|
add_filter( 'login_headerurl', 'custom_login_url' );
|
||||||
|
|
||||||
|
function custom_login_title() { return get_bloginfo( 'name' ); }
|
||||||
|
add_filter( 'login_headertext', 'custom_login_title' );
|
||||||
@@ -0,0 +1,367 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Eigene Links in der Backend-Seitenleiste
|
||||||
|
*
|
||||||
|
* Verwaltung unter dem Hauptmenüpunkt "Menü-Links". Jeder Eintrag erscheint
|
||||||
|
* als eigener Punkt in der linken Adminleiste und kann auf eine beliebige
|
||||||
|
* Adresse zeigen - auch auf externe Seiten.
|
||||||
|
*
|
||||||
|
* Technischer Hinweis: add_menu_page() schickt den Slug durch plugin_basename()
|
||||||
|
* und damit durch wp_normalize_path(). Dort bleibt "https://" nur erhalten,
|
||||||
|
* solange https als Stream-Wrapper registriert ist (hängt an allow_url_fopen).
|
||||||
|
* Ist die Direktive abgeschaltet - auf gehärteten Servern üblich - wird aus
|
||||||
|
* "https://" ein "https:/" und der Link ist kaputt. Die Einträge werden deshalb
|
||||||
|
* direkt in das globale $menu-Array geschrieben; dort bleibt die Adresse in
|
||||||
|
* jedem Fall unverändert (siehe wp-admin/menu-header.php).
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Auswählbare Einfügepositionen in der Seitenleiste. */
|
||||||
|
function mm_menu_links_positionen() {
|
||||||
|
return array(
|
||||||
|
'oben' => array( 'label' => __( 'Ganz oben (unter Dashboard)', 'minecraft-modern-theme' ), 'pos' => 3 ),
|
||||||
|
'inhalte' => array( 'label' => __( 'Nach den Inhalten', 'minecraft-modern-theme' ), 'pos' => 26 ),
|
||||||
|
'werkzeug' => array( 'label' => __( 'Bei den Werkzeugen', 'minecraft-modern-theme' ), 'pos' => 76 ),
|
||||||
|
'unten' => array( 'label' => __( 'Ganz unten', 'minecraft-modern-theme' ), 'pos' => 101 ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gespeicherte Links. */
|
||||||
|
function mm_menu_links_get() {
|
||||||
|
$links = get_option( 'mm_menu_links', array() );
|
||||||
|
return is_array( $links ) ? $links : array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prüft ein Linkziel und gibt es zurück - oder '' wenn es nicht zulässig ist.
|
||||||
|
*
|
||||||
|
* Erlaubt sind ausschliesslich http/https sowie relative Ziele innerhalb des
|
||||||
|
* Backends (z. B. edit.php?post_type=video). Alles andere - insbesondere
|
||||||
|
* javascript: und data: - wird verworfen, da die Adresse später unverändert
|
||||||
|
* als href in der Adminleiste landet.
|
||||||
|
*/
|
||||||
|
function mm_menu_links_url_pruefen( $url ) {
|
||||||
|
$url = (string) $url;
|
||||||
|
|
||||||
|
// Steuerzeichen und Leerraum entfernen. Ohne das liesse sich die
|
||||||
|
// Schema-Prüfung mit "java\nscript:..." umgehen - Browser ignorieren
|
||||||
|
// solche Zeichen beim Auflösen der Adresse.
|
||||||
|
$url = preg_replace( '/[\x00-\x20\x7F]/', '', $url );
|
||||||
|
if ( $url === '' ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protokollrelative Adressen (//example.com) nicht zulassen
|
||||||
|
if ( strpos( $url, '//' ) === 0 ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enthält das Ziel ein Schema?
|
||||||
|
if ( preg_match( '#^([a-z][a-z0-9+.\-]*):#i', $url, $t ) ) {
|
||||||
|
if ( ! in_array( strtolower( $t[1] ), array( 'http', 'https' ), true ) ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return esc_url_raw( $url, array( 'http', 'https' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relatives Ziel im Backend
|
||||||
|
return sanitize_text_field( $url );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// 1. Links in die Seitenleiste einhängen
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sucht ab $wunsch den nächsten freien Platz im Menü, damit vorhandene
|
||||||
|
* Einträge nicht überschrieben werden.
|
||||||
|
*/
|
||||||
|
function mm_menu_links_freier_platz( $wunsch ) {
|
||||||
|
global $menu;
|
||||||
|
|
||||||
|
// Bewusst nur der String-Schlüssel: Bei einem Float-Schlüssel schneidet PHP
|
||||||
|
// die Nachkommastellen ab, $menu[3.1] würde also $menu[3] abfragen und
|
||||||
|
// jede Zwischenposition fälschlich als belegt melden.
|
||||||
|
$pos = (float) $wunsch;
|
||||||
|
while ( isset( $menu[ (string) $pos ] ) ) {
|
||||||
|
$pos = round( $pos + 0.1, 1 );
|
||||||
|
}
|
||||||
|
return (string) $pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mm_menu_links_registrieren() {
|
||||||
|
global $menu;
|
||||||
|
|
||||||
|
$positionen = mm_menu_links_positionen();
|
||||||
|
|
||||||
|
foreach ( mm_menu_links_get() as $i => $link ) {
|
||||||
|
$titel = isset( $link['titel'] ) ? $link['titel'] : '';
|
||||||
|
|
||||||
|
// Zweite Prüfung beim Ausgeben: Die Adresse landet unverändert als
|
||||||
|
// href in der Adminleiste, deshalb auch hier nichts Ungeprüftes durchlassen.
|
||||||
|
$url = mm_menu_links_url_pruefen( $link['url'] ?? '' );
|
||||||
|
|
||||||
|
if ( $titel === '' || $url === '' ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$icon = ! empty( $link['icon'] ) ? $link['icon'] : 'dashicons-admin-links';
|
||||||
|
$extern = ! empty( $link['neues_fenster'] );
|
||||||
|
$schl = isset( $link['position'] ) ? $link['position'] : 'unten';
|
||||||
|
$wunsch = isset( $positionen[ $schl ] ) ? $positionen[ $schl ]['pos'] : 101;
|
||||||
|
|
||||||
|
$klassen = 'menu-top mm-menu-link';
|
||||||
|
if ( $extern ) {
|
||||||
|
$klassen .= ' mm-menu-link-extern';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aufbau wie in wp-admin/menu.php:
|
||||||
|
// 0 Beschriftung, 1 Fähigkeit, 2 Ziel, 3 Seitentitel, 4 Klassen, 5 Id, 6 Icon
|
||||||
|
$menu[ mm_menu_links_freier_platz( $wunsch ) ] = array(
|
||||||
|
$titel,
|
||||||
|
'read', // alle mit Backend-Zugang
|
||||||
|
$url,
|
||||||
|
$titel,
|
||||||
|
$klassen,
|
||||||
|
'mm-menu-link-' . (int) $i,
|
||||||
|
$icon,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'admin_menu', 'mm_menu_links_registrieren', 100 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Externe Links in einem neuen Tab öffnen.
|
||||||
|
* WordPress kennt kein target-Attribut für Menüpunkte, deshalb per Skript.
|
||||||
|
*/
|
||||||
|
function mm_menu_links_target() {
|
||||||
|
$hat_externe = false;
|
||||||
|
foreach ( mm_menu_links_get() as $link ) {
|
||||||
|
if ( ! empty( $link['neues_fenster'] ) ) {
|
||||||
|
$hat_externe = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( ! $hat_externe ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll('#adminmenu li.mm-menu-link-extern > a').forEach(function (a) {
|
||||||
|
a.target = '_blank';
|
||||||
|
a.rel = 'noopener noreferrer';
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
add_action( 'admin_footer', 'mm_menu_links_target' );
|
||||||
|
|
||||||
|
// Hinweis: Hier stand ein zusätzliches Pfeil-Symbol hinter externen Einträgen
|
||||||
|
// (::after mit einem Dashicon). Es brach bei kurzen Beschriftungen in die
|
||||||
|
// nächste Zeile um und wirkte dort wie ein loses Icon - deshalb entfernt.
|
||||||
|
// Externe Ziele erkennt man weiterhin daran, dass sie sich in einem neuen
|
||||||
|
// Tab öffnen.
|
||||||
|
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// 2. Verwaltungsseite
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
function mm_menu_links_admin_menu() {
|
||||||
|
add_menu_page(
|
||||||
|
__( 'Menü-Links', 'minecraft-modern-theme' ),
|
||||||
|
__( 'Menü-Links', 'minecraft-modern-theme' ),
|
||||||
|
'manage_options',
|
||||||
|
'mm-menu-links',
|
||||||
|
'mm_menu_links_seite',
|
||||||
|
'dashicons-admin-links',
|
||||||
|
63
|
||||||
|
);
|
||||||
|
register_setting( 'mm_menu_links_group', 'mm_menu_links', array(
|
||||||
|
'type' => 'array',
|
||||||
|
'sanitize_callback' => 'mm_menu_links_sanitize',
|
||||||
|
'default' => array(),
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'admin_menu', 'mm_menu_links_admin_menu' );
|
||||||
|
|
||||||
|
function mm_menu_links_sanitize( $roh ) {
|
||||||
|
$sauber = array();
|
||||||
|
if ( ! is_array( $roh ) ) {
|
||||||
|
return $sauber;
|
||||||
|
}
|
||||||
|
$erlaubte_positionen = array_keys( mm_menu_links_positionen() );
|
||||||
|
|
||||||
|
foreach ( $roh as $z ) {
|
||||||
|
$titel = sanitize_text_field( $z['titel'] ?? '' );
|
||||||
|
$url = mm_menu_links_url_pruefen( $z['url'] ?? '' );
|
||||||
|
|
||||||
|
// Zeilen ohne Beschriftung oder ohne zulässiges Ziel verwerfen
|
||||||
|
if ( $titel === '' || $url === '' ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pos = sanitize_key( $z['position'] ?? 'unten' );
|
||||||
|
|
||||||
|
$sauber[] = array(
|
||||||
|
'titel' => $titel,
|
||||||
|
'url' => $url,
|
||||||
|
'icon' => sanitize_html_class( $z['icon'] ?? '' ) ?: 'dashicons-admin-links',
|
||||||
|
'position' => in_array( $pos, $erlaubte_positionen, true ) ? $pos : 'unten',
|
||||||
|
'neues_fenster' => ! empty( $z['neues_fenster'] ) ? 1 : 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $sauber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Eine Eingabezeile. */
|
||||||
|
function mm_menu_links_zeile( $i, $z ) {
|
||||||
|
$titel = $z['titel'] ?? '';
|
||||||
|
$url = $z['url'] ?? '';
|
||||||
|
$icon = $z['icon'] ?? 'dashicons-admin-links';
|
||||||
|
$pos = $z['position'] ?? 'unten';
|
||||||
|
$extern = ! empty( $z['neues_fenster'] );
|
||||||
|
$n = 'mm_menu_links[' . $i . ']';
|
||||||
|
?>
|
||||||
|
<div class="mm-liste-zeile">
|
||||||
|
<span class="mm-vorschau dashicons <?php echo esc_attr( $icon ); ?>" aria-hidden="true"></span>
|
||||||
|
|
||||||
|
<label class="mm-spalte">
|
||||||
|
<span><?php esc_html_e( 'Beschriftung', 'minecraft-modern-theme' ); ?></span>
|
||||||
|
<input type="text" name="<?php echo esc_attr( $n ); ?>[titel]" value="<?php echo esc_attr( $titel ); ?>"
|
||||||
|
placeholder="<?php esc_attr_e( 'Discord', 'minecraft-modern-theme' ); ?>">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="mm-spalte mm-spalte-breit">
|
||||||
|
<span><?php esc_html_e( 'Adresse', 'minecraft-modern-theme' ); ?></span>
|
||||||
|
<input type="text" name="<?php echo esc_attr( $n ); ?>[url]" value="<?php echo esc_attr( $url ); ?>"
|
||||||
|
placeholder="https://discord.gg/...">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="mm-spalte">
|
||||||
|
<span><?php esc_html_e( 'Icon', 'minecraft-modern-theme' ); ?></span>
|
||||||
|
<input type="text" class="mm-icon-feld" name="<?php echo esc_attr( $n ); ?>[icon]"
|
||||||
|
value="<?php echo esc_attr( $icon ); ?>" placeholder="dashicons-admin-links">
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="mm-spalte">
|
||||||
|
<span><?php esc_html_e( 'Position', 'minecraft-modern-theme' ); ?></span>
|
||||||
|
<select name="<?php echo esc_attr( $n ); ?>[position]">
|
||||||
|
<?php foreach ( mm_menu_links_positionen() as $schl => $p ) : ?>
|
||||||
|
<option value="<?php echo esc_attr( $schl ); ?>" <?php selected( $pos, $schl ); ?>>
|
||||||
|
<?php echo esc_html( $p['label'] ); ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="mm-spalte mm-spalte-schmal mm-checkbox">
|
||||||
|
<span><?php esc_html_e( 'Neues Fenster', 'minecraft-modern-theme' ); ?></span>
|
||||||
|
<input type="checkbox" name="<?php echo esc_attr( $n ); ?>[neues_fenster]" value="1" <?php checked( $extern ); ?>>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button type="button" class="button-link mm-liste-entfernen" title="<?php esc_attr_e( 'Link entfernen', 'minecraft-modern-theme' ); ?>">
|
||||||
|
<span class="dashicons dashicons-trash" aria-hidden="true"></span>
|
||||||
|
<span class="screen-reader-text"><?php esc_html_e( 'Link entfernen', 'minecraft-modern-theme' ); ?></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
function mm_menu_links_seite() {
|
||||||
|
if ( ! current_user_can( 'manage_options' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$links = mm_menu_links_get();
|
||||||
|
?>
|
||||||
|
<div class="wrap mm-menu-links-admin">
|
||||||
|
<h1><?php esc_html_e( 'Menü-Links', 'minecraft-modern-theme' ); ?></h1>
|
||||||
|
<p class="description" style="max-width:760px;">
|
||||||
|
<?php esc_html_e( 'Diese Einträge erscheinen zusätzlich in der linken Adminleiste - für alle, die sich im Backend anmelden können. Als Adresse funktioniert eine vollständige externe Adresse (https://...) genauso wie ein internes Ziel, zum Beispiel edit.php?post_type=video.', 'minecraft-modern-theme' ); ?>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form method="post" action="options.php">
|
||||||
|
<?php settings_fields( 'mm_menu_links_group' ); ?>
|
||||||
|
|
||||||
|
<div class="mm-liste" data-mm-liste="mm_menu_links">
|
||||||
|
<?php foreach ( $links as $i => $z ) : ?>
|
||||||
|
<?php mm_menu_links_zeile( (int) $i, $z ); ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ( empty( $links ) ) : ?>
|
||||||
|
<p class="mm-leer"><?php esc_html_e( 'Noch keine Links angelegt.', 'minecraft-modern-theme' ); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<button type="button" class="button button-secondary mm-liste-hinzufuegen" data-ziel="mm_menu_links">
|
||||||
|
<span class="mm-plus" aria-hidden="true">+</span>
|
||||||
|
<?php esc_html_e( 'Link hinzufügen', 'minecraft-modern-theme' ); ?>
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script type="text/html" class="mm-liste-vorlage" data-fuer="mm_menu_links">
|
||||||
|
<?php mm_menu_links_zeile( '__INDEX__', array() ); ?>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php submit_button(); ?>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h2><?php esc_html_e( 'Häufige Symbole', 'minecraft-modern-theme' ); ?></h2>
|
||||||
|
<p class="description">
|
||||||
|
<?php esc_html_e( 'Trage eine dieser Klassen im Feld "Icon" ein. Die vollständige Liste findest du in der WordPress-Dokumentation unter "Dashicons".', 'minecraft-modern-theme' ); ?>
|
||||||
|
</p>
|
||||||
|
<ul class="mm-icon-liste">
|
||||||
|
<?php
|
||||||
|
$beispiele = array(
|
||||||
|
'dashicons-admin-links' => __( 'Link', 'minecraft-modern-theme' ),
|
||||||
|
'dashicons-external' => __( 'Extern', 'minecraft-modern-theme' ),
|
||||||
|
'dashicons-admin-site' => __( 'Webseite', 'minecraft-modern-theme' ),
|
||||||
|
'dashicons-groups' => __( 'Community', 'minecraft-modern-theme' ),
|
||||||
|
'dashicons-shield' => __( 'Sicherheit', 'minecraft-modern-theme' ),
|
||||||
|
'dashicons-chart-area' => __( 'Statistik', 'minecraft-modern-theme' ),
|
||||||
|
'dashicons-cloud' => __( 'Server', 'minecraft-modern-theme' ),
|
||||||
|
'dashicons-media-video' => __( 'Video', 'minecraft-modern-theme' ),
|
||||||
|
'dashicons-book' => __( 'Wiki', 'minecraft-modern-theme' ),
|
||||||
|
'dashicons-sos' => __( 'Support', 'minecraft-modern-theme' ),
|
||||||
|
);
|
||||||
|
foreach ( $beispiele as $klasse => $name ) :
|
||||||
|
?>
|
||||||
|
<li>
|
||||||
|
<span class="dashicons <?php echo esc_attr( $klasse ); ?>"></span>
|
||||||
|
<code><?php echo esc_html( $klasse ); ?></code>
|
||||||
|
<span class="mm-icon-name"><?php echo esc_html( $name ); ?></span>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Skript und Styles nur auf der Verwaltungsseite laden. */
|
||||||
|
function mm_menu_links_admin_assets( $hook ) {
|
||||||
|
if ( $hook !== 'toplevel_page_mm-menu-links' ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wp_enqueue_style(
|
||||||
|
'mm-menu-links-admin',
|
||||||
|
get_template_directory_uri() . '/css/menu-links-admin.css',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/css/menu-links-admin.css' )
|
||||||
|
);
|
||||||
|
wp_enqueue_script(
|
||||||
|
'mm-menu-links-admin',
|
||||||
|
get_template_directory_uri() . '/js/menu-links-admin.js',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/js/menu-links-admin.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_action( 'admin_enqueue_scripts', 'mm_menu_links_admin_assets' );
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Nach-oben-Button
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// SCROLL TO TOP BUTTON
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// FIX: Button wird jetzt im footer.php direkt ausgegeben (kein doppelter Button mehr).
|
||||||
|
// Diese Funktion bleibt als Fallback aber deaktiviert, damit es keinen Konflikt gibt.
|
||||||
|
// Falls footer.php NICHT angepasst wurde, diese Zeile auskommentieren:
|
||||||
|
// add_action( 'wp_footer', 'add_scroll_to_top_button' );
|
||||||
|
|
||||||
|
function add_scroll_to_top_button() {
|
||||||
|
?>
|
||||||
|
<a href="#" id="scroll-to-top" aria-label="<?php esc_attr_e( 'Nach oben scrollen', 'minecraft-modern-theme' ); ?>" title="<?php esc_attr_e( 'Nach oben', 'minecraft-modern-theme' ); ?>">
|
||||||
|
<i class="fas fa-chevron-up"></i>
|
||||||
|
</a>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
function minecraft_modern_scroll_to_top_script() {
|
||||||
|
wp_enqueue_script(
|
||||||
|
'minecraft-scroll-to-top-script',
|
||||||
|
get_template_directory_uri() . '/js/scroll-to-top.js',
|
||||||
|
array( 'jquery' ),
|
||||||
|
filemtime( get_template_directory() . '/js/scroll-to-top.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_action( 'wp_enqueue_scripts', 'minecraft_modern_scroll_to_top_script' );
|
||||||
@@ -0,0 +1,447 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Export und Import saemtlicher Theme-Einstellungen
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// THEME SETTINGS EXPORT / IMPORT
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
add_action( 'admin_post_export_theme_settings', 'handle_theme_settings_export' );
|
||||||
|
|
||||||
|
function handle_theme_settings_export() {
|
||||||
|
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
||||||
|
wp_die( __( 'Du hast keine Berechtigung, diese Aktion auszuführen.', 'minecraft-modern-theme' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$theme_slug = get_option( 'stylesheet' );
|
||||||
|
$data = array(
|
||||||
|
'_version' => '3.0',
|
||||||
|
'_exported' => date( 'Y-m-d H:i:s' ),
|
||||||
|
'_theme' => $theme_slug,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 1. Alle Customizer-Einstellungen (Theme Mods)
|
||||||
|
// Enthält: Farben, Slider, Hero, Social Links, Menü-Design, Login-Einstellungen, Sidebar-Einstellungen usw.
|
||||||
|
$data['theme_mods'] = get_theme_mods();
|
||||||
|
|
||||||
|
// 2. Announcement-Bar (gespeichert als wp_options, nicht als Theme Mod)
|
||||||
|
$announcement_keys = array(
|
||||||
|
'mm_announcement_enabled', 'mm_announcement_text', 'mm_announcement_bg',
|
||||||
|
'mm_announcement_color', 'mm_announcement_font_size', 'mm_announcement_font_family',
|
||||||
|
'mm_announcement_position', 'mm_announcement_countdown_enabled',
|
||||||
|
'mm_announcement_countdown_label', 'mm_announcement_countdown_date',
|
||||||
|
'mm_announcement_countdown_expired_msg',
|
||||||
|
);
|
||||||
|
foreach ( $announcement_keys as $key ) {
|
||||||
|
$data['announcement'][ $key ] = get_option( $key );
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Widget-Konfigurationen aller Theme-Sidebars
|
||||||
|
$theme_sidebars = array(
|
||||||
|
'single-post-sidebar',
|
||||||
|
'homepage-sidebar-top', 'homepage-sidebar-middle-1',
|
||||||
|
'homepage-sidebar-middle-2', 'homepage-sidebar-bottom',
|
||||||
|
'homepage-sidebar-extra', 'footer-1', 'footer-2', 'footer-3',
|
||||||
|
);
|
||||||
|
$all_sidebars = wp_get_sidebars_widgets();
|
||||||
|
$widget_data = array();
|
||||||
|
foreach ( $theme_sidebars as $sidebar_id ) {
|
||||||
|
$widget_data[ $sidebar_id ] = array();
|
||||||
|
if ( empty( $all_sidebars[ $sidebar_id ] ) ) continue;
|
||||||
|
foreach ( $all_sidebars[ $sidebar_id ] as $widget_id ) {
|
||||||
|
if ( ! preg_match( '/^(.+)-(\d+)$/', $widget_id, $m ) ) continue;
|
||||||
|
$type = $m[1];
|
||||||
|
$index = intval( $m[2] );
|
||||||
|
$all = get_option( 'widget_' . $type, array() );
|
||||||
|
$widget_data[ $sidebar_id ][] = array(
|
||||||
|
'type' => $type,
|
||||||
|
'index' => $index,
|
||||||
|
'settings' => isset( $all[ $index ] ) ? $all[ $index ] : array(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['widgets'] = $widget_data;
|
||||||
|
|
||||||
|
// 4. Team-Mitglieder (mit UUID, Banner, Thumbnail)
|
||||||
|
$team_data = array();
|
||||||
|
$team_query = new WP_Query( array(
|
||||||
|
'post_type' => 'team_member',
|
||||||
|
'posts_per_page' => -1,
|
||||||
|
'orderby' => 'menu_order',
|
||||||
|
'order' => 'ASC',
|
||||||
|
) );
|
||||||
|
if ( $team_query->have_posts() ) {
|
||||||
|
while ( $team_query->have_posts() ) {
|
||||||
|
$team_query->the_post();
|
||||||
|
$post_id = get_the_ID();
|
||||||
|
$team_data[] = array(
|
||||||
|
'title' => get_the_title(),
|
||||||
|
'content' => get_the_content(),
|
||||||
|
'rank' => get_post_meta( $post_id, '_team_member_rank', true ),
|
||||||
|
'uuid' => get_post_meta( $post_id, '_team_member_uuid', true ),
|
||||||
|
'banner_id' => get_post_meta( $post_id, '_team_member_banner', true ),
|
||||||
|
'thumbnail_id' => get_post_thumbnail_id( $post_id ),
|
||||||
|
'menu_order' => get_post_field( 'menu_order', $post_id ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
wp_reset_postdata();
|
||||||
|
}
|
||||||
|
$data['team'] = $team_data;
|
||||||
|
|
||||||
|
// 5. FAQ-Einträge (theme-eigener Custom Post Type)
|
||||||
|
$faq_data = array();
|
||||||
|
$faq_query = new WP_Query( array(
|
||||||
|
'post_type' => 'faq',
|
||||||
|
'posts_per_page' => -1,
|
||||||
|
'orderby' => 'menu_order',
|
||||||
|
'order' => 'ASC',
|
||||||
|
) );
|
||||||
|
if ( $faq_query->have_posts() ) {
|
||||||
|
while ( $faq_query->have_posts() ) {
|
||||||
|
$faq_query->the_post();
|
||||||
|
$terms = wp_get_post_terms( get_the_ID(), 'faq_category', array( 'fields' => 'names' ) );
|
||||||
|
$faq_data[] = array(
|
||||||
|
'title' => get_the_title(),
|
||||||
|
'content' => get_the_content(),
|
||||||
|
'menu_order' => get_post_field( 'menu_order', get_the_ID() ),
|
||||||
|
'categories' => is_wp_error( $terms ) ? array() : $terms,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
wp_reset_postdata();
|
||||||
|
}
|
||||||
|
$data['faqs'] = $faq_data;
|
||||||
|
|
||||||
|
// 6. Custom CSS (Customizer → Zusätzliches CSS)
|
||||||
|
$data['custom_css'] = wp_get_custom_css();
|
||||||
|
|
||||||
|
// 7. Homepage-Seite (falls eingestellt)
|
||||||
|
$homepage_id = get_option( 'page_on_front' );
|
||||||
|
if ( $homepage_id ) {
|
||||||
|
$homepage = get_post( $homepage_id );
|
||||||
|
if ( $homepage ) {
|
||||||
|
$data['homepage'] = array(
|
||||||
|
'title' => $homepage->post_title,
|
||||||
|
'content' => $homepage->post_content,
|
||||||
|
'excerpt' => $homepage->post_excerpt,
|
||||||
|
'featured_img' => get_post_thumbnail_id( $homepage_id ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. Navigation Menüs mit Items
|
||||||
|
$nav_menus = array();
|
||||||
|
$all_nav_menus = wp_get_nav_menus();
|
||||||
|
foreach ( $all_nav_menus as $menu ) {
|
||||||
|
$nav_menus[ $menu->slug ] = array(
|
||||||
|
'name' => $menu->name,
|
||||||
|
'description' => $menu->description,
|
||||||
|
'items' => array(),
|
||||||
|
);
|
||||||
|
$menu_items = wp_get_nav_menu_items( $menu->term_id );
|
||||||
|
if ( $menu_items ) {
|
||||||
|
foreach ( $menu_items as $item ) {
|
||||||
|
$nav_menus[ $menu->slug ]['items'][] = array(
|
||||||
|
'title' => $item->title,
|
||||||
|
'url' => $item->url,
|
||||||
|
'description' => $item->description,
|
||||||
|
'type' => $item->type,
|
||||||
|
'type_label' => $item->type_label,
|
||||||
|
'object' => $item->object,
|
||||||
|
'object_id' => $item->object_id,
|
||||||
|
'parent' => $item->menu_item_parent,
|
||||||
|
'menu_order' => $item->menu_order,
|
||||||
|
'target' => get_post_meta( $item->ID, '_menu_item_target', true ),
|
||||||
|
'classes' => implode( ' ', (array) $item->classes ),
|
||||||
|
'xfn' => get_post_meta( $item->ID, '_menu_item_xfn', true ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['nav_menus'] = $nav_menus;
|
||||||
|
|
||||||
|
// 9. Menü-Positionen (welches Menü ist welchem Theme-Location zugewiesen)
|
||||||
|
$data['nav_menu_locations'] = get_theme_mod( 'nav_menu_locations', array() );
|
||||||
|
|
||||||
|
$json = json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );
|
||||||
|
header( 'Content-Type: application/json; charset=utf-8' );
|
||||||
|
header( 'Content-Disposition: attachment; filename=' . $theme_slug . '-theme-backup-' . date( 'Y-m-d' ) . '.json' );
|
||||||
|
header( 'Pragma: no-cache' );
|
||||||
|
header( 'Expires: 0' );
|
||||||
|
echo $json;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
add_action( 'wp_ajax_import_theme_settings', 'handle_theme_settings_import' );
|
||||||
|
|
||||||
|
function handle_theme_settings_import() {
|
||||||
|
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
||||||
|
wp_send_json_error( __( 'Keine Berechtigung.', 'minecraft-modern-theme' ) );
|
||||||
|
}
|
||||||
|
check_ajax_referer( 'theme-import-nonce', 'nonce' );
|
||||||
|
|
||||||
|
if ( empty( $_FILES['import_file']['tmp_name'] ) ) {
|
||||||
|
wp_send_json_error( __( 'Keine Datei hochgeladen.', 'minecraft-modern-theme' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$json_content = file_get_contents( $_FILES['import_file']['tmp_name'] );
|
||||||
|
$data = json_decode( $json_content, true );
|
||||||
|
|
||||||
|
if ( json_last_error() !== JSON_ERROR_NONE || ! is_array( $data ) ) {
|
||||||
|
wp_send_json_error( __( 'Ungültige JSON-Datei.', 'minecraft-modern-theme' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$imported = array();
|
||||||
|
$version = isset( $data['_version'] ) ? $data['_version'] : '1.0';
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 1. Customizer / Theme Mods
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
$mods = array();
|
||||||
|
if ( $version === '3.0' && isset( $data['theme_mods'] ) ) {
|
||||||
|
$mods = $data['theme_mods'];
|
||||||
|
} elseif ( $version === '2.0' && isset( $data['theme_mods'] ) ) {
|
||||||
|
$mods = $data['theme_mods'];
|
||||||
|
} else {
|
||||||
|
// Altes v1-Format: alles auf oberster Ebene
|
||||||
|
$skip = array( '_version', '_exported', '_theme', 'announcement', 'widgets', 'team', 'faqs', 'menus', 'wp_options', 'custom_css', 'team_data' );
|
||||||
|
foreach ( $data as $k => $v ) {
|
||||||
|
if ( ! in_array( $k, $skip ) ) $mods[ $k ] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ( $mods as $key => $value ) {
|
||||||
|
set_theme_mod( $key, $value );
|
||||||
|
}
|
||||||
|
$imported[] = 'Customizer-Einstellungen';
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 2. Announcement-Bar
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
$announcement_keys = array(
|
||||||
|
'mm_announcement_enabled', 'mm_announcement_text', 'mm_announcement_bg',
|
||||||
|
'mm_announcement_color', 'mm_announcement_font_size', 'mm_announcement_font_family',
|
||||||
|
'mm_announcement_position', 'mm_announcement_countdown_enabled',
|
||||||
|
'mm_announcement_countdown_label', 'mm_announcement_countdown_date',
|
||||||
|
'mm_announcement_countdown_expired_msg',
|
||||||
|
);
|
||||||
|
$ann = isset( $data['announcement'] ) ? $data['announcement'] : $data;
|
||||||
|
foreach ( $announcement_keys as $key ) {
|
||||||
|
if ( array_key_exists( $key, $ann ) ) {
|
||||||
|
update_option( $key, $ann[ $key ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$imported[] = 'Ankündigung';
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 3. Widgets
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
if ( ! empty( $data['widgets'] ) ) {
|
||||||
|
$current_sidebars = get_option( 'sidebars_widgets', array() );
|
||||||
|
foreach ( $data['widgets'] as $sidebar_id => $widgets ) {
|
||||||
|
$current_sidebars[ $sidebar_id ] = array();
|
||||||
|
foreach ( $widgets as $widget ) {
|
||||||
|
$type = sanitize_key( $widget['type'] );
|
||||||
|
$index = intval( $widget['index'] );
|
||||||
|
$all = get_option( 'widget_' . $type, array() );
|
||||||
|
$all[ $index ] = $widget['settings'];
|
||||||
|
update_option( 'widget_' . $type, $all );
|
||||||
|
$current_sidebars[ $sidebar_id ][] = $type . '-' . $index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update_option( 'sidebars_widgets', $current_sidebars );
|
||||||
|
$imported[] = 'Widgets';
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 4. Team-Mitglieder
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
$team_data = isset( $data['team'] ) ? $data['team'] : ( isset( $data['team_data'] ) ? $data['team_data'] : array() );
|
||||||
|
if ( ! empty( $team_data ) ) {
|
||||||
|
$existing = new WP_Query( array( 'post_type' => 'team_member', 'posts_per_page' => -1, 'fields' => 'ids' ) );
|
||||||
|
if ( $existing->have_posts() ) {
|
||||||
|
foreach ( $existing->posts as $pid ) wp_delete_post( $pid, true );
|
||||||
|
}
|
||||||
|
wp_reset_postdata();
|
||||||
|
foreach ( $team_data as $member ) {
|
||||||
|
$id = wp_insert_post( array(
|
||||||
|
'post_title' => sanitize_text_field( $member['title'] ),
|
||||||
|
'post_content' => wp_kses_post( $member['content'] ),
|
||||||
|
'post_type' => 'team_member',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'menu_order' => intval( isset( $member['menu_order'] ) ? $member['menu_order'] : 0 ),
|
||||||
|
) );
|
||||||
|
if ( $id && ! is_wp_error( $id ) ) {
|
||||||
|
// Rank
|
||||||
|
if ( ! empty( $member['rank'] ) ) {
|
||||||
|
update_post_meta( $id, '_team_member_rank', sanitize_text_field( $member['rank'] ) );
|
||||||
|
}
|
||||||
|
// UUID
|
||||||
|
if ( ! empty( $member['uuid'] ) ) {
|
||||||
|
update_post_meta( $id, '_team_member_uuid', sanitize_text_field( $member['uuid'] ) );
|
||||||
|
}
|
||||||
|
// Thumbnail
|
||||||
|
if ( ! empty( $member['thumbnail_id'] ) ) {
|
||||||
|
set_post_thumbnail( $id, intval( $member['thumbnail_id'] ) );
|
||||||
|
}
|
||||||
|
// Banner
|
||||||
|
if ( ! empty( $member['banner_id'] ) ) {
|
||||||
|
update_post_meta( $id, '_team_member_banner', intval( $member['banner_id'] ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$imported[] = count( $team_data ) . ' Team-Mitglieder';
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 5. FAQs
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
if ( ! empty( $data['faqs'] ) ) {
|
||||||
|
$existing = new WP_Query( array( 'post_type' => 'faq', 'posts_per_page' => -1, 'fields' => 'ids' ) );
|
||||||
|
if ( $existing->have_posts() ) {
|
||||||
|
foreach ( $existing->posts as $pid ) wp_delete_post( $pid, true );
|
||||||
|
}
|
||||||
|
wp_reset_postdata();
|
||||||
|
foreach ( $data['faqs'] as $faq ) {
|
||||||
|
$id = wp_insert_post( array(
|
||||||
|
'post_title' => sanitize_text_field( $faq['title'] ),
|
||||||
|
'post_content' => wp_kses_post( $faq['content'] ),
|
||||||
|
'post_type' => 'faq',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'menu_order' => intval( isset( $faq['menu_order'] ) ? $faq['menu_order'] : 0 ),
|
||||||
|
) );
|
||||||
|
if ( $id && ! is_wp_error( $id ) && ! empty( $faq['categories'] ) ) {
|
||||||
|
foreach ( (array) $faq['categories'] as $cat_name ) {
|
||||||
|
$term = term_exists( sanitize_text_field( $cat_name ), 'faq_category' );
|
||||||
|
if ( ! $term ) {
|
||||||
|
$term = wp_insert_term( sanitize_text_field( $cat_name ), 'faq_category' );
|
||||||
|
}
|
||||||
|
if ( ! is_wp_error( $term ) ) {
|
||||||
|
wp_set_post_terms( $id, array( intval( $term['term_id'] ) ), 'faq_category', true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$imported[] = count( $data['faqs'] ) . ' FAQs';
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 6. Custom CSS
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
if ( isset( $data['custom_css'] ) && $data['custom_css'] !== '' ) {
|
||||||
|
wp_update_custom_css_post( $data['custom_css'] );
|
||||||
|
$imported[] = 'Custom CSS';
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 7. Homepage-Seite
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
if ( ! empty( $data['homepage'] ) ) {
|
||||||
|
$homepage_id = get_option( 'page_on_front' );
|
||||||
|
if ( $homepage_id ) {
|
||||||
|
wp_update_post( array(
|
||||||
|
'ID' => $homepage_id,
|
||||||
|
'post_title' => sanitize_text_field( $data['homepage']['title'] ),
|
||||||
|
'post_content' => wp_kses_post( $data['homepage']['content'] ),
|
||||||
|
'post_excerpt' => sanitize_textarea_field( $data['homepage']['excerpt'] ),
|
||||||
|
) );
|
||||||
|
if ( ! empty( $data['homepage']['featured_img'] ) ) {
|
||||||
|
set_post_thumbnail( $homepage_id, intval( $data['homepage']['featured_img'] ) );
|
||||||
|
}
|
||||||
|
$imported[] = 'Homepage-Seite';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 8. Navigation Menüs mit Items
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
if ( ! empty( $data['nav_menus'] ) ) {
|
||||||
|
$menu_id_map = array(); // slug => term_id Mapping für Item-Parent-Zuordnung
|
||||||
|
|
||||||
|
// Alle existierenden Menüs löschen
|
||||||
|
$existing_menus = wp_get_nav_menus();
|
||||||
|
foreach ( $existing_menus as $menu ) {
|
||||||
|
wp_delete_nav_menu( $menu->term_id );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neue Menüs und Items importieren
|
||||||
|
foreach ( $data['nav_menus'] as $menu_slug => $menu_data ) {
|
||||||
|
$new_menu = wp_create_nav_menu( $menu_data['name'] );
|
||||||
|
if ( ! is_wp_error( $new_menu ) ) {
|
||||||
|
$menu_id_map[ $menu_slug ] = $new_menu;
|
||||||
|
|
||||||
|
// Items hinzufügen
|
||||||
|
if ( ! empty( $menu_data['items'] ) ) {
|
||||||
|
$item_id_map = array(); // Altes Item ID => Neues Item ID Mapping
|
||||||
|
|
||||||
|
// Erste Runde: Root-Items (parent = 0)
|
||||||
|
foreach ( $menu_data['items'] as $idx => $item ) {
|
||||||
|
if ( empty( $item['parent'] ) || $item['parent'] == 0 ) {
|
||||||
|
$item_id = wp_update_nav_menu_item( $new_menu, 0, array(
|
||||||
|
'menu-item-title' => sanitize_text_field( $item['title'] ),
|
||||||
|
'menu-item-url' => esc_url_raw( $item['url'] ),
|
||||||
|
'menu-item-description' => sanitize_text_field( $item['description'] ),
|
||||||
|
'menu-item-type' => sanitize_key( $item['type'] ),
|
||||||
|
'menu-item-object' => sanitize_key( $item['object'] ),
|
||||||
|
'menu-item-object-id' => intval( $item['object_id'] ),
|
||||||
|
'menu-item-target' => sanitize_text_field( $item['target'] ),
|
||||||
|
'menu-item-classes' => sanitize_text_field( $item['classes'] ),
|
||||||
|
'menu-item-xfn' => sanitize_text_field( $item['xfn'] ),
|
||||||
|
'menu-item-status' => 'publish',
|
||||||
|
) );
|
||||||
|
if ( $item_id && ! is_wp_error( $item_id ) ) {
|
||||||
|
$item_id_map[ $idx ] = $item_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zweite Runde: Sub-Items (parent > 0)
|
||||||
|
foreach ( $menu_data['items'] as $idx => $item ) {
|
||||||
|
if ( ! empty( $item['parent'] ) && $item['parent'] > 0 ) {
|
||||||
|
$parent_item_id = isset( $item_id_map[ $item['parent'] - 1 ] ) ? $item_id_map[ $item['parent'] - 1 ] : 0;
|
||||||
|
$item_id = wp_update_nav_menu_item( $new_menu, 0, array(
|
||||||
|
'menu-item-title' => sanitize_text_field( $item['title'] ),
|
||||||
|
'menu-item-url' => esc_url_raw( $item['url'] ),
|
||||||
|
'menu-item-description' => sanitize_text_field( $item['description'] ),
|
||||||
|
'menu-item-type' => sanitize_key( $item['type'] ),
|
||||||
|
'menu-item-object' => sanitize_key( $item['object'] ),
|
||||||
|
'menu-item-object-id' => intval( $item['object_id'] ),
|
||||||
|
'menu-item-parent-id' => $parent_item_id,
|
||||||
|
'menu-item-target' => sanitize_text_field( $item['target'] ),
|
||||||
|
'menu-item-classes' => sanitize_text_field( $item['classes'] ),
|
||||||
|
'menu-item-xfn' => sanitize_text_field( $item['xfn'] ),
|
||||||
|
'menu-item-status' => 'publish',
|
||||||
|
) );
|
||||||
|
if ( $item_id && ! is_wp_error( $item_id ) ) {
|
||||||
|
$item_id_map[ $idx ] = $item_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$imported[] = 'Navigation Menüs (' . count( $data['nav_menus'] ) . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 9. Menü-Positionen
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
if ( ! empty( $data['nav_menu_locations'] ) ) {
|
||||||
|
set_theme_mod( 'nav_menu_locations', $data['nav_menu_locations'] );
|
||||||
|
$imported[] = 'Menü-Positionen';
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success( sprintf(
|
||||||
|
__( 'Erfolgreich wiederhergestellt: %s', 'minecraft-modern-theme' ),
|
||||||
|
implode( ', ', $imported )
|
||||||
|
) );
|
||||||
|
}
|
||||||
@@ -0,0 +1,513 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Team-Modul: Custom Post Type, Verwaltungsseite und AJAX-Handler
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// TEAM MODUL
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
function create_team_post_type() {
|
||||||
|
if ( get_theme_mod( 'team_enabled', true ) ) {
|
||||||
|
register_post_type( 'team_member', array(
|
||||||
|
'labels' => array(
|
||||||
|
'name' => __( 'Team', 'minecraft-modern-theme' ),
|
||||||
|
'singular_name' => __( 'Teammitglied', 'minecraft-modern-theme' ),
|
||||||
|
'add_new' => __( 'Neues Mitglied', 'minecraft-modern-theme' ),
|
||||||
|
'menu_name' => __( 'Team', 'minecraft-modern-theme' ),
|
||||||
|
),
|
||||||
|
'public' => true,
|
||||||
|
'has_archive' => true,
|
||||||
|
'menu_icon' => 'dashicons-groups',
|
||||||
|
'supports' => array( 'title', 'thumbnail', 'page-attributes' ),
|
||||||
|
'rewrite' => array( 'slug' => 'team' ),
|
||||||
|
'show_in_rest' => true,
|
||||||
|
'show_in_menu' => false,
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'init', 'create_team_post_type' );
|
||||||
|
|
||||||
|
|
||||||
|
function add_team_meta_boxes() {
|
||||||
|
add_meta_box( 'team_member_rank_box', __( 'Rang & Position', 'minecraft-modern-theme' ), 'team_member_rank_callback', 'team_member', 'side', 'default' );
|
||||||
|
}
|
||||||
|
add_action( 'add_meta_boxes', 'add_team_meta_boxes' );
|
||||||
|
|
||||||
|
function team_member_rank_callback( $post ) {
|
||||||
|
wp_nonce_field( 'team_member_rank_save', 'team_member_rank_nonce' );
|
||||||
|
$value = get_post_meta( $post->ID, '_team_member_rank', true );
|
||||||
|
?>
|
||||||
|
<p>
|
||||||
|
<label for="team_member_rank" style="font-weight:600;">Rang:</label>
|
||||||
|
<input type="text" id="team_member_rank" name="team_member_rank" value="<?php echo esc_attr( $value ); ?>" style="width:100%;" placeholder="z.B. Admin, Mod">
|
||||||
|
</p>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_team_member_rank( $post_id ) {
|
||||||
|
if ( ! isset( $_POST['team_member_rank_nonce'] ) ) return;
|
||||||
|
if ( ! wp_verify_nonce( $_POST['team_member_rank_nonce'], 'team_member_rank_save' ) ) return;
|
||||||
|
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
|
||||||
|
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
|
||||||
|
if ( isset( $_POST['team_member_rank'] ) ) {
|
||||||
|
update_post_meta( $post_id, '_team_member_rank', sanitize_text_field( $_POST['team_member_rank'] ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'save_post', 'save_team_member_rank' );
|
||||||
|
|
||||||
|
|
||||||
|
add_action( 'admin_menu', 'register_team_manager_page' );
|
||||||
|
function register_team_manager_page() {
|
||||||
|
add_menu_page( 'Team Manager', 'Team Manager', 'manage_options', 'mm-team-manager', 'mm_team_manager_page_html', 'dashicons-groups', 6 );
|
||||||
|
add_action( 'admin_enqueue_scripts', function( $hook ) {
|
||||||
|
if ( $hook === 'toplevel_page_mm-team-manager' ) {
|
||||||
|
wp_enqueue_media();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Breite-Fix nur auf der Team-Manager-Seite
|
||||||
|
function mm_team_manager_admin_css() {
|
||||||
|
$screen = get_current_screen();
|
||||||
|
if ( ! $screen || $screen->id !== 'toplevel_page_mm-team-manager' ) return;
|
||||||
|
echo '<style>.toplevel_page_mm-team-manager .card{max-width:100%!important;}.toplevel_page_mm-team-manager #mm-add-member-form{display:grid!important;grid-template-columns:repeat(auto-fit,minmax(250px,1fr))!important;gap:20px!important;}</style>';
|
||||||
|
}
|
||||||
|
add_action( 'admin_head', 'mm_team_manager_admin_css' );
|
||||||
|
|
||||||
|
function mm_team_manager_page_html() {
|
||||||
|
?>
|
||||||
|
<div class="wrap" style="max-width:1200px;">
|
||||||
|
<h1>Team Verwaltung</h1>
|
||||||
|
<p>Hier kannst du Teammitglieder hinzufügen, sortieren und bearbeiten.</p>
|
||||||
|
|
||||||
|
<div class="card" style="background:#fff;border:1px solid #ccd0d4;border-left:4px solid #0073aa;padding:20px;margin-bottom:20px;">
|
||||||
|
<h2>Neues Mitglied hinzufügen</h2>
|
||||||
|
<form id="mm-add-member-form" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px;align-items:start;">
|
||||||
|
<div>
|
||||||
|
<label for="new_name"><strong>Name:</strong></label><br>
|
||||||
|
<input type="text" id="new_name" style="width:100%;" required>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="new_rank"><strong>Rang:</strong></label><br>
|
||||||
|
<input type="text" id="new_rank" style="width:100%;" placeholder="z.B. Admin, Mod">
|
||||||
|
</div>
|
||||||
|
<div style="grid-column:1/-1;">
|
||||||
|
<label for="new_bio"><strong>Kurzbeschreibung:</strong></label><br>
|
||||||
|
<textarea id="new_bio" rows="2" style="width:100%;" placeholder="Kurztext..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="grid-column:1/-1;display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap;">
|
||||||
|
<!-- UUID Feld -->
|
||||||
|
<div style="flex:1;min-width:200px;">
|
||||||
|
<label for="new_uuid"><strong>Minecraft UUID:</strong></label><br>
|
||||||
|
<input type="text" id="new_uuid" style="width:100%;margin-top:4px;" placeholder="z.B. 069a79f4-44e9-4726-a5be-fca90e38aaf5">
|
||||||
|
<p style="margin:4px 0 0;color:#666;font-size:12px;">UUID eingeben → Avatar wird automatisch geladen</p>
|
||||||
|
</div>
|
||||||
|
<!-- ODER Avatar-Bild hochladen -->
|
||||||
|
<div style="flex:1;min-width:200px;">
|
||||||
|
<label><strong>Oder: Avatar-Bild:</strong></label><br>
|
||||||
|
<div style="margin-top:4px;display:flex;align-items:center;gap:10px;">
|
||||||
|
<input type="hidden" id="new_image_id" value="">
|
||||||
|
<button type="button" class="button mm-upload-btn" data-target="new_image_id">Bild auswählen</button>
|
||||||
|
<span id="new_image_name" style="color:#666;font-size:12px;">Kein Bild gewählt</span>
|
||||||
|
</div>
|
||||||
|
<p style="margin:4px 0 0;color:#666;font-size:12px;">Wird ignoriert wenn UUID gesetzt ist</p>
|
||||||
|
</div>
|
||||||
|
<!-- Banner-Bild -->
|
||||||
|
<div style="flex:1;min-width:200px;">
|
||||||
|
<label><strong>Banner-Bild:</strong></label><br>
|
||||||
|
<div style="margin-top:4px;display:flex;align-items:center;gap:10px;">
|
||||||
|
<input type="hidden" id="new_banner_id" value="">
|
||||||
|
<button type="button" class="button mm-upload-btn" data-target="new_banner_id">Banner auswählen</button>
|
||||||
|
<span id="new_banner_name" style="color:#666;font-size:12px;">Kein Banner gewählt</span>
|
||||||
|
</div>
|
||||||
|
<p style="margin:4px 0 0;color:#666;font-size:12px;">Hintergrundbild der Card (optional)</p>
|
||||||
|
<div id="new_banner_preview" style="margin-top:8px;width:100%;height:50px;background:#eee;border:1px solid #ccc;border-radius:4px;overflow:hidden;background-size:cover;background-position:center;"></div>
|
||||||
|
</div>
|
||||||
|
<!-- Avatar Vorschau -->
|
||||||
|
<div style="flex:0 0 80px;">
|
||||||
|
<label><strong>Vorschau:</strong></label><br>
|
||||||
|
<div id="new_image_preview" style="width:80px;height:80px;background:#eee;border:1px solid #ccc;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;margin-top:4px;">
|
||||||
|
<span style="color:#999;font-size:11px;">–</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="grid-column:1/-1;">
|
||||||
|
<button type="submit" class="button button-primary button-large" style="width:100%;">Hinzufügen</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<button id="save-order-btn" class="button button-primary" style="margin-top:16px;float:right;">Reihenfolge speichern</button>
|
||||||
|
<div id="order-save-msg" style="margin-top:16px;float:left;color:green;display:none;">Reihenfolge gespeichert!</div>
|
||||||
|
<div style="clear:both;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card" style="background:#fff;padding:20px;">
|
||||||
|
<table class="wp-list-table widefat fixed striped" id="team-table" style="width:100%;table-layout:fixed;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width:60px;">Bild</th>
|
||||||
|
<th style="width:18%;">Name</th>
|
||||||
|
<th style="width:15%;">Rang</th>
|
||||||
|
<th>Bio</th>
|
||||||
|
<th style="width:180px;">UUID / Bild</th>
|
||||||
|
<th style="width:70px;text-align:center;">Sort.</th>
|
||||||
|
<th style="width:100px;text-align:right;">Aktionen</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="team-list-body">
|
||||||
|
<?php
|
||||||
|
$team_query = new WP_Query( array( 'post_type' => 'team_member', 'posts_per_page' => -1, 'orderby' => 'menu_order', 'order' => 'ASC' ) );
|
||||||
|
if ( $team_query->have_posts() ) :
|
||||||
|
while ( $team_query->have_posts() ) : $team_query->the_post();
|
||||||
|
$id = get_the_ID();
|
||||||
|
$name = get_the_title();
|
||||||
|
$rank = get_post_meta( $id, '_team_member_rank', true );
|
||||||
|
$bio = get_the_content();
|
||||||
|
$uuid = get_post_meta( $id, '_team_member_uuid', true );
|
||||||
|
$img_id = get_post_thumbnail_id( $id );
|
||||||
|
$banner_id = get_post_meta( $id, '_team_member_banner', true );
|
||||||
|
$banner_url = $banner_id ? wp_get_attachment_image_url( $banner_id, 'medium' ) : false;
|
||||||
|
|
||||||
|
// Avatar anzeigen: UUID > Bild > Placeholder
|
||||||
|
if ( $uuid ) {
|
||||||
|
$avatar_src = 'https://visage.surgeplay.com/bust/' . esc_attr($uuid) . '.png';
|
||||||
|
} elseif ( $img_id ) {
|
||||||
|
$avatar_src = wp_get_attachment_image_url( $img_id, array(40,40) );
|
||||||
|
} else {
|
||||||
|
$avatar_src = false;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<tr data-id="<?php echo $id; ?>">
|
||||||
|
<td style="text-align:center;vertical-align:middle;">
|
||||||
|
<div class="mm-avatar-preview" style="width:40px;height:40px;background:#eee;display:inline-flex;align-items:center;justify-content:center;overflow:hidden;border-radius:4px;border:1px solid #ddd;">
|
||||||
|
<?php if ( $avatar_src ) : ?>
|
||||||
|
<img src="<?php echo esc_url($avatar_src); ?>" style="width:100%;height:100%;object-fit:cover;">
|
||||||
|
<?php else : ?>
|
||||||
|
<span style="font-size:20px;">👤</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td><input type="text" class="inline-edit" data-field="post_title" value="<?php echo esc_attr( $name ); ?>" style="width:100%;box-sizing:border-box;padding:6px;"></td>
|
||||||
|
<td><input type="text" class="inline-edit" data-field="_team_member_rank" value="<?php echo esc_attr( $rank ); ?>" style="width:100%;box-sizing:border-box;padding:6px;"></td>
|
||||||
|
<td><input type="text" class="inline-edit" data-field="post_content" value="<?php echo esc_attr( wp_strip_all_tags( $bio ) ); ?>" style="width:100%;box-sizing:border-box;padding:6px;"></td>
|
||||||
|
<td>
|
||||||
|
<input type="text" class="inline-edit uuid-field" data-field="_team_member_uuid"
|
||||||
|
value="<?php echo esc_attr( $uuid ); ?>"
|
||||||
|
placeholder="UUID oder leer lassen"
|
||||||
|
style="width:100%;box-sizing:border-box;padding:6px;font-size:11px;margin-bottom:4px;">
|
||||||
|
<div style="display:flex;align-items:center;gap:6px;margin-top:4px;">
|
||||||
|
<input type="hidden" class="row-banner-id" value="<?php echo esc_attr( $banner_id ); ?>">
|
||||||
|
<button type="button" class="button button-small mm-upload-btn-banner" data-id="<?php echo $id; ?>" style="font-size:11px;">Banner</button>
|
||||||
|
<?php if ( $banner_url ) : ?>
|
||||||
|
<div style="width:40px;height:20px;border-radius:3px;overflow:hidden;background:url('<?php echo esc_url($banner_url); ?>') center/cover;border:1px solid #ccc;"></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td style="text-align:center;vertical-align:middle;">
|
||||||
|
<button class="button button-small sort-up" title="Nach oben">▲</button>
|
||||||
|
<button class="button button-small sort-down" title="Nach unten">▼</button>
|
||||||
|
</td>
|
||||||
|
<td style="text-align:right;vertical-align:middle;">
|
||||||
|
<button class="button button-primary button-small save-row" title="Speichern">💾</button>
|
||||||
|
<button class="button button-small delete-row" title="Löschen">🗑️</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
endwhile;
|
||||||
|
else :
|
||||||
|
echo '<tr><td colspan="7" style="text-align:center;">Noch keine Mitglieder vorhanden.</td></tr>';
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
var mediaUploader;
|
||||||
|
$(document).on('click', '.mm-upload-btn', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var targetInput = $(this).data('target');
|
||||||
|
var isBanner = (targetInput === 'new_banner_id');
|
||||||
|
var uploader = wp.media({ title: isBanner ? 'Banner auswählen' : 'Bild auswählen', button: { text: 'Auswählen' }, multiple: false });
|
||||||
|
uploader.on('select', function() {
|
||||||
|
var att = uploader.state().get('selection').first().toJSON();
|
||||||
|
$('#' + targetInput).val(att.id);
|
||||||
|
if (isBanner) {
|
||||||
|
$('#new_banner_name').text(att.title);
|
||||||
|
var url = att.sizes && att.sizes.medium ? att.sizes.medium.url : att.url;
|
||||||
|
$('#new_banner_preview').css({'background-image': 'url(' + url + ')', 'background-size': 'cover', 'background-position': 'center'});
|
||||||
|
} else {
|
||||||
|
$('#new_image_name').text(att.title);
|
||||||
|
var thumb = att.sizes && att.sizes.thumbnail ? att.sizes.thumbnail.url : att.url;
|
||||||
|
$('#new_image_preview').html('<img src="' + thumb + '" style="width:100%;height:100%;object-fit:cover;">');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
uploader.open();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#mm-add-member-form').on('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $form = $(this);
|
||||||
|
var btn = $form.find('button[type="submit"]').prop('disabled', true).text('Lade...');
|
||||||
|
$.ajax({
|
||||||
|
url: ajaxurl,
|
||||||
|
type: 'POST',
|
||||||
|
timeout: 15000,
|
||||||
|
data: {
|
||||||
|
action: 'mm_add_team_member',
|
||||||
|
name: $('#new_name').val(),
|
||||||
|
rank: $('#new_rank').val(),
|
||||||
|
bio: $('#new_bio').val(),
|
||||||
|
img_id: $('#new_image_id').val(),
|
||||||
|
uuid: $('#new_uuid').val(),
|
||||||
|
banner_id: $('#new_banner_id').val(),
|
||||||
|
nonce: '<?php echo wp_create_nonce( 'mm_team_nonce' ); ?>'
|
||||||
|
},
|
||||||
|
success: function(r) {
|
||||||
|
if (r.success) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert('Fehler: ' + r.data);
|
||||||
|
btn.prop('disabled', false).text('Hinzufügen');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status) {
|
||||||
|
alert('Verbindungsfehler (' + status + '). Bitte erneut versuchen.');
|
||||||
|
btn.prop('disabled', false).text('Hinzufügen');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Banner-Upload in Tabellenzeile
|
||||||
|
$(document).on('click', '.mm-upload-btn-banner', function() {
|
||||||
|
var row = $(this).closest('tr');
|
||||||
|
var uploader = wp.media({ title: 'Banner auswählen', button: { text: 'Auswählen' }, multiple: false });
|
||||||
|
uploader.on('select', function() {
|
||||||
|
var att = uploader.state().get('selection').first().toJSON();
|
||||||
|
row.find('.row-banner-id').val(att.id);
|
||||||
|
var url = att.sizes && att.sizes.medium ? att.sizes.medium.url : att.url;
|
||||||
|
var preview = row.find('.mm-upload-btn-banner').next('div');
|
||||||
|
if (preview.length) {
|
||||||
|
preview.css({'background-image': 'url('+url+')'});
|
||||||
|
} else {
|
||||||
|
row.find('.mm-upload-btn-banner').after('<div style="width:40px;height:20px;border-radius:3px;overflow:hidden;background:url('+url+') center/cover;border:1px solid #ccc;display:inline-block;vertical-align:middle;margin-left:4px;"></div>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
uploader.open();
|
||||||
|
});
|
||||||
|
var uuidTimer;
|
||||||
|
$('#new_uuid').on('input', function() {
|
||||||
|
clearTimeout(uuidTimer);
|
||||||
|
var uuid = $(this).val().trim();
|
||||||
|
var preview = $('#new_image_preview');
|
||||||
|
if (!uuid) {
|
||||||
|
preview.html('<span style="color:#999;font-size:11px;">–</span>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uuidTimer = setTimeout(function() {
|
||||||
|
var url = 'https://visage.surgeplay.com/bust/' + uuid + '.png';
|
||||||
|
preview.html('<img src="' + url + '" style="width:100%;height:100%;object-fit:cover;" onerror="this.parentNode.innerHTML=\'<span style=color:#c00;font-size:11px>Ungültig</span>\'" />');
|
||||||
|
}, 600);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.save-row').on('click', function() {
|
||||||
|
var row = $(this).closest('tr'), btn = $(this);
|
||||||
|
var data = { action: 'mm_update_team_member', id: row.data('id'), nonce: '<?php echo wp_create_nonce( 'mm_team_nonce' ); ?>' };
|
||||||
|
row.find('.inline-edit').each(function() {
|
||||||
|
var f = $(this).data('field'), v = $(this).val();
|
||||||
|
if (f === 'post_title') data.title = v;
|
||||||
|
if (f === '_team_member_rank') data.rank = v;
|
||||||
|
if (f === 'post_content') data.bio = v;
|
||||||
|
if (f === '_team_member_uuid') data.uuid = v;
|
||||||
|
});
|
||||||
|
// Bild-ID falls vorhanden
|
||||||
|
var imgInput = row.find('.row-img-id');
|
||||||
|
if (imgInput.length) data.img_id = imgInput.val();
|
||||||
|
// Banner-ID
|
||||||
|
var bannerInput = row.find('.row-banner-id');
|
||||||
|
if (bannerInput.length) data.banner_id = bannerInput.val();
|
||||||
|
|
||||||
|
btn.text('✓').prop('disabled', true);
|
||||||
|
$.post(ajaxurl, data, function(r) {
|
||||||
|
// Avatar live aktualisieren
|
||||||
|
if (data.uuid) {
|
||||||
|
var url = 'https://visage.surgeplay.com/bust/' + data.uuid + '.png';
|
||||||
|
row.find('.mm-avatar-preview').html('<img src="' + url + '" style="width:100%;height:100%;object-fit:cover;">');
|
||||||
|
}
|
||||||
|
setTimeout(function(){ btn.text('💾').prop('disabled', false); }, 1000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.delete-row').on('click', function() {
|
||||||
|
if (!confirm('Löschen?')) return;
|
||||||
|
var row = $(this).closest('tr');
|
||||||
|
$.post(ajaxurl, { action: 'mm_delete_team_member', id: row.data('id'), nonce: '<?php echo wp_create_nonce( 'mm_team_nonce' ); ?>' }, function() { row.fadeOut().remove(); });
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.sort-up').on('click', function() { var r = $(this).closest('tr'), p = r.prev('tr'); if (p.length) r.insertBefore(p); });
|
||||||
|
$('.sort-down').on('click', function() { var r = $(this).closest('tr'), n = r.next('tr'); if (n.length) r.insertAfter(n); });
|
||||||
|
// Reihenfolge speichern
|
||||||
|
$('#save-order-btn').on('click', function() {
|
||||||
|
var ids = [];
|
||||||
|
$('#team-list-body tr').each(function(){ ids.push($(this).data('id')); });
|
||||||
|
var btn = $(this);
|
||||||
|
btn.prop('disabled', true).text('Speichern...');
|
||||||
|
$('#order-save-msg').hide();
|
||||||
|
$.post(ajaxurl, {
|
||||||
|
action: 'mm_save_team_order',
|
||||||
|
ids: ids,
|
||||||
|
nonce: '<?php echo wp_create_nonce( 'mm_team_nonce' ); ?>'
|
||||||
|
}, function(r) {
|
||||||
|
btn.prop('disabled', false).text('Reihenfolge speichern');
|
||||||
|
if(r.success){
|
||||||
|
$('#order-save-msg').fadeIn().delay(1200).fadeOut();
|
||||||
|
} else {
|
||||||
|
alert('Fehler beim Speichern der Reihenfolge!');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
// AJAX-Handler für Reihenfolge speichern
|
||||||
|
add_action( 'wp_ajax_mm_save_team_order', 'handle_mm_save_team_order' );
|
||||||
|
function handle_mm_save_team_order() {
|
||||||
|
check_ajax_referer( 'mm_team_nonce', 'nonce' );
|
||||||
|
if ( ! current_user_can( 'edit_posts' ) ) wp_send_json_error( 'Keine Berechtigung' );
|
||||||
|
if ( empty( $_POST['ids'] ) ) {
|
||||||
|
wp_send_json_error( 'Keine IDs' );
|
||||||
|
}
|
||||||
|
$ids = is_array($_POST['ids']) ? $_POST['ids'] : explode(',', $_POST['ids']);
|
||||||
|
$ids = array_map('intval', $ids);
|
||||||
|
$pos = 0;
|
||||||
|
foreach ( $ids as $id ) {
|
||||||
|
wp_update_post( array( 'ID' => $id, 'menu_order' => $pos ) );
|
||||||
|
$pos++;
|
||||||
|
}
|
||||||
|
wp_send_json_success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
add_action( 'wp_ajax_mm_add_team_member', 'handle_mm_add_member' );
|
||||||
|
function handle_mm_add_member() {
|
||||||
|
check_ajax_referer( 'mm_team_nonce', 'nonce' );
|
||||||
|
if ( ! current_user_can( 'publish_posts' ) ) wp_send_json_error( 'Keine Berechtigung' );
|
||||||
|
|
||||||
|
$id = wp_insert_post( array(
|
||||||
|
'post_title' => sanitize_text_field( $_POST['name'] ),
|
||||||
|
'post_content' => sanitize_textarea_field( $_POST['bio'] ),
|
||||||
|
'post_type' => 'team_member',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'menu_order' => 999,
|
||||||
|
) );
|
||||||
|
|
||||||
|
if ( ! $id || is_wp_error( $id ) ) {
|
||||||
|
wp_send_json_error( 'Fehler beim Erstellen' );
|
||||||
|
}
|
||||||
|
|
||||||
|
update_post_meta( $id, '_team_member_rank', sanitize_text_field( $_POST['rank'] ) );
|
||||||
|
|
||||||
|
// UUID speichern (kein externer Request hier – nur als Text speichern)
|
||||||
|
if ( ! empty( $_POST['uuid'] ) ) {
|
||||||
|
$uuid = sanitize_text_field( trim( $_POST['uuid'] ) );
|
||||||
|
update_post_meta( $id, '_team_member_uuid', $uuid );
|
||||||
|
} elseif ( ! empty( $_POST['img_id'] ) ) {
|
||||||
|
set_post_thumbnail( $id, intval( $_POST['img_id'] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Banner-Bild speichern
|
||||||
|
if ( ! empty( $_POST['banner_id'] ) ) {
|
||||||
|
update_post_meta( $id, '_team_member_banner', intval( $_POST['banner_id'] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success( array( 'id' => $id, 'msg' => 'Hinzugefügt' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
add_action( 'wp_ajax_mm_update_team_member', 'handle_mm_update_team_member' );
|
||||||
|
function handle_mm_update_team_member() {
|
||||||
|
check_ajax_referer( 'mm_team_nonce', 'nonce' );
|
||||||
|
if ( ! current_user_can( 'edit_posts' ) ) wp_send_json_error( 'Keine Berechtigung' );
|
||||||
|
$id = intval( $_POST['id'] );
|
||||||
|
wp_update_post( array(
|
||||||
|
'ID' => $id,
|
||||||
|
'post_title' => sanitize_text_field( $_POST['title'] ),
|
||||||
|
'post_content' => sanitize_textarea_field( $_POST['bio'] ),
|
||||||
|
) );
|
||||||
|
update_post_meta( $id, '_team_member_rank', sanitize_text_field( $_POST['rank'] ) );
|
||||||
|
// UUID speichern oder löschen
|
||||||
|
if ( isset( $_POST['uuid'] ) ) {
|
||||||
|
$uuid = sanitize_text_field( trim( $_POST['uuid'] ) );
|
||||||
|
if ( $uuid ) {
|
||||||
|
update_post_meta( $id, '_team_member_uuid', $uuid );
|
||||||
|
} else {
|
||||||
|
delete_post_meta( $id, '_team_member_uuid' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Bild nur setzen wenn keine UUID
|
||||||
|
if ( empty( $_POST['uuid'] ) && ! empty( $_POST['img_id'] ) ) {
|
||||||
|
set_post_thumbnail( $id, intval( $_POST['img_id'] ) );
|
||||||
|
}
|
||||||
|
// Banner speichern
|
||||||
|
if ( isset( $_POST['banner_id'] ) ) {
|
||||||
|
if ( ! empty( $_POST['banner_id'] ) ) {
|
||||||
|
update_post_meta( $id, '_team_member_banner', intval( $_POST['banner_id'] ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wp_send_json_success( 'Gespeichert' );
|
||||||
|
}
|
||||||
|
|
||||||
|
add_action( 'wp_ajax_mm_delete_team_member', 'handle_mm_delete_team_member' );
|
||||||
|
function handle_mm_delete_team_member() {
|
||||||
|
check_ajax_referer( 'mm_team_nonce', 'nonce' );
|
||||||
|
if ( ! current_user_can( 'delete_posts' ) ) wp_send_json_error( 'Keine Berechtigung' );
|
||||||
|
wp_delete_post( intval( $_POST['id'] ), true );
|
||||||
|
wp_send_json_success( 'Gelöscht' );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function create_team_page_automatically() {
|
||||||
|
if ( get_theme_mod( 'team_enabled', true ) && get_page_by_title( 'Team' ) == null ) {
|
||||||
|
wp_insert_post( array( 'post_title' => 'Team', 'post_status' => 'publish', 'post_type' => 'page', 'post_author' => 1 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'customize_save_after', 'create_team_page_automatically' );
|
||||||
|
|
||||||
|
|
||||||
|
function load_team_page_template( $template ) {
|
||||||
|
if ( ! get_theme_mod( 'team_enabled', true ) ) return $template;
|
||||||
|
|
||||||
|
// BUG-FIX: locate_template() statt get_template_directory() – so wird ein
|
||||||
|
// archive-team.php im Child-Theme berücksichtigt.
|
||||||
|
$is_team_page = false;
|
||||||
|
if ( is_post_type_archive( 'team_member' ) ) {
|
||||||
|
$is_team_page = true;
|
||||||
|
} elseif ( is_page() ) {
|
||||||
|
$obj = get_queried_object();
|
||||||
|
$is_team_page = ( $obj && $obj->post_name === 'team' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $is_team_page ) {
|
||||||
|
$t = locate_template( 'archive-team.php' );
|
||||||
|
if ( $t ) return $t;
|
||||||
|
}
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
add_filter( 'template_include', 'load_team_page_template' );
|
||||||
|
|
||||||
|
|
||||||
|
// Doppelte team_customize_register entfernt – ist jetzt in inc/customizer.php
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Theme-Setup, lokale Schriften und Einbindung von Styles/Skripten
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Theme Setup ===
|
||||||
|
function minecraft_modern_setup() {
|
||||||
|
add_theme_support( 'title-tag' );
|
||||||
|
add_theme_support( 'post-thumbnails' );
|
||||||
|
|
||||||
|
add_theme_support( 'custom-logo', array(
|
||||||
|
'height' => 9999,
|
||||||
|
'width' => 9999,
|
||||||
|
'flex-height' => true,
|
||||||
|
'flex-width' => true,
|
||||||
|
'header_text' => array( 'site-title', 'site-description' ),
|
||||||
|
) );
|
||||||
|
|
||||||
|
add_theme_support( 'custom-background' );
|
||||||
|
|
||||||
|
register_nav_menus( array(
|
||||||
|
'primary' => __( 'Hauptmenü', 'minecraft-modern-theme' ),
|
||||||
|
'footer' => __( 'Footer-Menü', 'minecraft-modern-theme' ),
|
||||||
|
) );
|
||||||
|
|
||||||
|
// FIX: 'script' und 'style' ergänzt für sauberes HTML5-Output-Format
|
||||||
|
add_theme_support( 'html5', array(
|
||||||
|
'search-form', 'comment-form', 'comment-list',
|
||||||
|
'gallery', 'caption', 'script', 'style',
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'after_setup_theme', 'minecraft_modern_setup' );
|
||||||
|
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// LOKALE SCHRIFTEN (DSGVO)
|
||||||
|
// =========================================================================
|
||||||
|
// Schriften liegen unter /fonts/<slug>/font.css samt woff2-Dateien und werden
|
||||||
|
// lokal ausgeliefert. Dadurch wird beim Seitenaufruf keine Verbindung zu
|
||||||
|
// fonts.googleapis.com / fonts.gstatic.com aufgebaut und keine Besucher-IP
|
||||||
|
// an Google übertragen.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wandelt einen Schriftnamen in den Ordnernamen unter /fonts/ um.
|
||||||
|
* "Open Sans" -> "open-sans"
|
||||||
|
*/
|
||||||
|
function mm_font_slug( $font_name ) {
|
||||||
|
return strtolower( str_replace( ' ', '-', trim( $font_name ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bindet eine lokal gehostete Schrift ein.
|
||||||
|
*
|
||||||
|
* Das Handle wird aus dem Schriftnamen abgeleitet ("Open Sans" -> mm-font-open-sans).
|
||||||
|
* Dadurch wird dieselbe Schrift automatisch nur einmal eingebunden, auch wenn sie
|
||||||
|
* an mehreren Stellen angefordert wird (z. B. Basis- und Slider-Schrift beide Raleway).
|
||||||
|
*
|
||||||
|
* @param string $font_name Schriftname, z. B. "Open Sans".
|
||||||
|
* @return bool True, wenn die Schrift lokal vorhanden war und eingebunden wurde.
|
||||||
|
*/
|
||||||
|
function mm_enqueue_local_font( $font_name ) {
|
||||||
|
if ( empty( $font_name ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$slug = mm_font_slug( $font_name );
|
||||||
|
$rel = '/fonts/' . $slug . '/font.css';
|
||||||
|
$path = get_template_directory() . $rel;
|
||||||
|
|
||||||
|
if ( ! file_exists( $path ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wp_enqueue_style( 'mm-font-' . $slug, get_template_directory_uri() . $rel, array(), filemtime( $path ) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// === Styles & Scripts laden ===
|
||||||
|
function minecraft_modern_scripts() {
|
||||||
|
// Haupt-Stylesheet des Parent-Themes.
|
||||||
|
// Bewusst get_template_directory_uri() statt get_stylesheet_uri(): Bei aktivem
|
||||||
|
// Child-Theme zeigt get_stylesheet_uri() auf das Child. Das Child-Theme belegt
|
||||||
|
// dasselbe Handle mit der Parent-Datei – zeigten beide auf unterschiedliche
|
||||||
|
// Dateien, entschiede die Aufrufreihenfolge darüber, welches CSS geladen wird
|
||||||
|
// (WordPress ignoriert den zweiten Aufruf eines bereits registrierten Handles).
|
||||||
|
// So liefern beide Seiten dieselbe Datei und die Reihenfolge ist egal.
|
||||||
|
wp_enqueue_style(
|
||||||
|
'minecraft-modern-style',
|
||||||
|
get_template_directory_uri() . '/style.css',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/style.css' )
|
||||||
|
);
|
||||||
|
|
||||||
|
// Bei aktivem Child-Theme dessen style.css danach laden, damit das Theme auch
|
||||||
|
// dann vollständig ist, wenn das Child keine eigene Enqueue-Funktion mitbringt.
|
||||||
|
if ( is_child_theme() && file_exists( get_stylesheet_directory() . '/style.css' ) ) {
|
||||||
|
wp_enqueue_style(
|
||||||
|
'minecraft-modern-child-style',
|
||||||
|
get_stylesheet_uri(),
|
||||||
|
array( 'minecraft-modern-style' ),
|
||||||
|
filemtime( get_stylesheet_directory() . '/style.css' )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basis-Schrift des Themes (lokal, siehe mm_enqueue_local_font)
|
||||||
|
mm_enqueue_local_font( 'Raleway' );
|
||||||
|
|
||||||
|
// Font Awesome (lokal statt cdnjs) – vorher als fester <link> in header.php
|
||||||
|
wp_enqueue_style(
|
||||||
|
'font-awesome',
|
||||||
|
get_template_directory_uri() . '/css/fontawesome.min.css',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/css/fontawesome.min.css' )
|
||||||
|
);
|
||||||
|
|
||||||
|
// Swiper.js CSS (lokal statt CDN)
|
||||||
|
wp_enqueue_style(
|
||||||
|
'swiper-css',
|
||||||
|
get_template_directory_uri() . '/css/swiper-bundle.min.css',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/css/swiper-bundle.min.css' )
|
||||||
|
);
|
||||||
|
|
||||||
|
// Header-Scroll + Suche Toggle
|
||||||
|
wp_enqueue_script(
|
||||||
|
'minecraft-modern-header-script',
|
||||||
|
get_template_directory_uri() . '/js/header-scroll.js',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/js/header-scroll.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Navigation (Dropdown + Außenklick-Schließen)
|
||||||
|
wp_enqueue_script(
|
||||||
|
'minecraft-navigation',
|
||||||
|
get_template_directory_uri() . '/js/navigation.js',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/js/navigation.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Swiper.js (lokal statt CDN)
|
||||||
|
wp_enqueue_script(
|
||||||
|
'swiper-js',
|
||||||
|
get_template_directory_uri() . '/js/swiper-bundle.min.js',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/js/swiper-bundle.min.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Slider-Init
|
||||||
|
wp_enqueue_script(
|
||||||
|
'minecraft-modern-slider-script',
|
||||||
|
get_template_directory_uri() . '/js/slider-init.js',
|
||||||
|
array( 'swiper-js' ),
|
||||||
|
filemtime( get_template_directory() . '/js/slider-init.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Theme Toggle
|
||||||
|
wp_enqueue_script(
|
||||||
|
'theme-toggle-script',
|
||||||
|
get_template_directory_uri() . '/js/theme-toggle.js',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/js/theme-toggle.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// BUG-FIX: post_type_exists('faq') prüft nur ob der CPT registriert ist, nicht ob wir
|
||||||
|
// auf einer FAQ-Seite sind – das Script wurde damit seitenübergreifend geladen.
|
||||||
|
// Jetzt: nur auf FAQ-Archiv-, Einzel- und Seiten mit FAQ-Template laden.
|
||||||
|
if ( post_type_exists( 'faq' ) && ( is_post_type_archive( 'faq' ) || is_singular( 'faq' ) || is_page( 'FAQ' ) || is_page( 'faq' ) ) ) {
|
||||||
|
wp_enqueue_script(
|
||||||
|
'faq-accordion-script',
|
||||||
|
get_template_directory_uri() . '/js/faq-accordion.js',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/js/faq-accordion.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIX: 'loop' ergänzt – war in slider-init.js als sliderSettings.loop referenziert, aber nie übergeben
|
||||||
|
wp_localize_script(
|
||||||
|
'minecraft-modern-slider-script',
|
||||||
|
'sliderSettings',
|
||||||
|
array(
|
||||||
|
'hideArrows' => get_theme_mod( 'slider_hide_arrows', false ) ? '1' : '0',
|
||||||
|
'hidePagination' => get_theme_mod( 'slider_hide_pagination', false ) ? '1' : '0',
|
||||||
|
'effect' => get_theme_mod( 'slider_effect', 'fade' ),
|
||||||
|
'direction' => get_theme_mod( 'slider_direction', 'horizontal' ),
|
||||||
|
'defaultMode' => get_theme_mod( 'default_theme_mode', 'dark' ),
|
||||||
|
'loop' => get_theme_mod( 'slider_loop', true ) ? '1' : '0',
|
||||||
|
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
wp_localize_script(
|
||||||
|
'minecraft-modern-header-script',
|
||||||
|
'headerSettings',
|
||||||
|
array(
|
||||||
|
'isCustomizer' => is_customize_preview(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add_action( 'wp_enqueue_scripts', 'minecraft_modern_scripts' );
|
||||||
|
|
||||||
|
|
||||||
|
// FIX: Scroll-to-Top via Customizer ein-/ausblendbar
|
||||||
|
function minecraft_modern_scroll_to_top_css() {
|
||||||
|
if ( ! get_theme_mod( 'show_scroll_to_top', true ) ) {
|
||||||
|
wp_add_inline_style( 'minecraft-modern-style', '#scroll-to-top { display: none !important; }' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'wp_enqueue_scripts', 'minecraft_modern_scroll_to_top_css', 25 );
|
||||||
|
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// PERFORMANCE: WordPress-Emoji-Ersetzung abschalten
|
||||||
|
// =========================================================================
|
||||||
|
// WordPress prüft per JavaScript, ob der Browser den neuesten Emoji-Satz
|
||||||
|
// kennt. Fällt der Test negativ aus (unter Windows 10 häufig der Fall),
|
||||||
|
// werden ALLE Emoji im Seiteninhalt durch SVG-Grafiken von s.w.org ersetzt.
|
||||||
|
// Auf dieser Seite waren das 9 externe Downloads mit rund 13 Sekunden
|
||||||
|
// Gesamtladezeit – ausgelöst durch die Emoji in der Ankündigungs-Leiste und
|
||||||
|
// den Assistent-Buttons.
|
||||||
|
//
|
||||||
|
// Ohne das Skript stellt der Browser die Emoji als ganz normale Schriftzeichen
|
||||||
|
// dar; sie bleiben also sichtbar, es entfällt nur der externe Bilder-Download.
|
||||||
|
// Zum Rückgängigmachen genügt es, die folgende Funktion samt Hooks zu löschen.
|
||||||
|
function minecraft_modern_disable_emoji_scripts() {
|
||||||
|
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
|
||||||
|
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
|
||||||
|
remove_action( 'wp_print_styles', 'print_emoji_styles' );
|
||||||
|
remove_action( 'admin_print_styles', 'print_emoji_styles' );
|
||||||
|
remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
|
||||||
|
remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
|
||||||
|
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
|
||||||
|
}
|
||||||
|
add_action( 'init', 'minecraft_modern_disable_emoji_scripts' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entfernt zusätzlich das Emoji-Skript aus dem TinyMCE-Editor.
|
||||||
|
*/
|
||||||
|
function minecraft_modern_disable_emoji_tinymce( $plugins ) {
|
||||||
|
return is_array( $plugins ) ? array_diff( $plugins, array( 'wpemoji' ) ) : array();
|
||||||
|
}
|
||||||
|
add_filter( 'tiny_mce_plugins', 'minecraft_modern_disable_emoji_tinymce' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verhindert den DNS-Prefetch auf s.w.org, den WordPress sonst zusätzlich setzt.
|
||||||
|
*/
|
||||||
|
function minecraft_modern_remove_emoji_dns_prefetch( $urls, $relation_type ) {
|
||||||
|
if ( 'dns-prefetch' === $relation_type ) {
|
||||||
|
$emoji_svg_url = apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/' );
|
||||||
|
$urls = array_diff( $urls, array( $emoji_svg_url ) );
|
||||||
|
}
|
||||||
|
return $urls;
|
||||||
|
}
|
||||||
|
add_filter( 'wp_resource_hints', 'minecraft_modern_remove_emoji_dns_prefetch', 10, 2 );
|
||||||
@@ -1,141 +1,141 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Minecraft Modern Theme - Updater & Dashboard Status
|
* Minecraft Modern Theme - Updater & Dashboard Status
|
||||||
*
|
*
|
||||||
* Diese Datei prüft auf neue Versionen via Gitea API und zeigt den Status im Dashboard an.
|
* 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.
|
* Aus Sicherheitsgründen ist das automatische Update deaktiviert, um Datenverlust zu vermeiden.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Minecraft_Modern_Theme_Manager {
|
class Minecraft_Modern_Theme_Manager {
|
||||||
|
|
||||||
// BUG-FIX: Hardcoded 'Minecraft-Modern-Theme' schlug auf Linux-Servern
|
// BUG-FIX: Hardcoded 'Minecraft-Modern-Theme' schlug auf Linux-Servern
|
||||||
// (case-sensitive Dateisystem) fehl, wenn das Verzeichnis kleingeschrieben ist.
|
// (case-sensitive Dateisystem) fehl, wenn das Verzeichnis kleingeschrieben ist.
|
||||||
// get_template() liefert immer den echten Verzeichnisnamen.
|
// get_template() liefert immer den echten Verzeichnisnamen.
|
||||||
private $theme_slug;
|
private $theme_slug;
|
||||||
private $repo = 'M_Viper/Minecraft-Modern-Theme';
|
private $repo = 'M_Viper/Minecraft-Modern-Theme';
|
||||||
private $transient_key = 'mm_theme_update_check';
|
private $transient_key = 'mm_theme_update_check';
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->theme_slug = get_template();
|
$this->theme_slug = get_template();
|
||||||
|
|
||||||
add_action( 'admin_notices', [ $this, 'display_update_notice' ] );
|
add_action( 'admin_notices', [ $this, 'display_update_notice' ] );
|
||||||
add_action( 'wp_dashboard_setup', [ $this, 'add_dashboard_widget' ] );
|
add_action( 'wp_dashboard_setup', [ $this, 'add_dashboard_widget' ] );
|
||||||
add_action( 'admin_init', [ $this, 'handle_refresh_request' ] );
|
add_action( 'admin_init', [ $this, 'handle_refresh_request' ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holt die API-Daten von Gitea (mit Transient-Cache).
|
* Holt die API-Daten von Gitea (mit Transient-Cache).
|
||||||
*/
|
*/
|
||||||
private function get_latest_release() {
|
private function get_latest_release() {
|
||||||
$update_data = get_transient( $this->transient_key );
|
$update_data = get_transient( $this->transient_key );
|
||||||
|
|
||||||
if ( false === $update_data ) {
|
if ( false === $update_data ) {
|
||||||
$api_url = "https://git.viper.ipv64.net/api/v1/repos/{$this->repo}/releases/latest";
|
$api_url = "https://git.viper.ipv64.net/api/v1/repos/{$this->repo}/releases/latest";
|
||||||
$response = wp_remote_get( $api_url, [ 'timeout' => 10 ] );
|
$response = wp_remote_get( $api_url, [ 'timeout' => 10 ] );
|
||||||
|
|
||||||
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
|
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
|
||||||
set_transient( $this->transient_key, [ 'error' => true ], 2 * HOUR_IN_SECONDS );
|
set_transient( $this->transient_key, [ 'error' => true ], 2 * HOUR_IN_SECONDS );
|
||||||
return [ 'error' => true ];
|
return [ 'error' => true ];
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = json_decode( wp_remote_retrieve_body( $response ) );
|
$data = json_decode( wp_remote_retrieve_body( $response ) );
|
||||||
$new_version = ltrim( $data->tag_name, 'vV' );
|
$new_version = ltrim( $data->tag_name, 'vV' );
|
||||||
|
|
||||||
$update_data = [
|
$update_data = [
|
||||||
'version' => $new_version,
|
'version' => $new_version,
|
||||||
'url' => "https://git.viper.ipv64.net/{$this->repo}/releases",
|
'url' => "https://git.viper.ipv64.net/{$this->repo}/releases",
|
||||||
];
|
];
|
||||||
|
|
||||||
set_transient( $this->transient_key, $update_data, 12 * HOUR_IN_SECONDS );
|
set_transient( $this->transient_key, $update_data, 12 * HOUR_IN_SECONDS );
|
||||||
}
|
}
|
||||||
|
|
||||||
return $update_data;
|
return $update_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zeigt die gelbe Info-Box oben im Admin-Bereich an, wenn ein Update verfügbar ist.
|
* Zeigt die gelbe Info-Box oben im Admin-Bereich an, wenn ein Update verfügbar ist.
|
||||||
*/
|
*/
|
||||||
public function display_update_notice() {
|
public function display_update_notice() {
|
||||||
if ( ! current_user_can( 'update_themes' ) ) return;
|
if ( ! current_user_can( 'update_themes' ) ) return;
|
||||||
|
|
||||||
$latest = $this->get_latest_release();
|
$latest = $this->get_latest_release();
|
||||||
if ( isset( $latest['error'] ) ) return;
|
if ( isset( $latest['error'] ) ) return;
|
||||||
|
|
||||||
$current_version = wp_get_theme( $this->theme_slug )->get( 'Version' );
|
$current_version = wp_get_theme( $this->theme_slug )->get( 'Version' );
|
||||||
if ( ! $current_version ) return;
|
if ( ! $current_version ) return;
|
||||||
|
|
||||||
if ( version_compare( $current_version, $latest['version'], '<' ) ) {
|
if ( version_compare( $current_version, $latest['version'], '<' ) ) {
|
||||||
?>
|
?>
|
||||||
<div class="notice notice-warning is-dismissible">
|
<div class="notice notice-warning is-dismissible">
|
||||||
<p>
|
<p>
|
||||||
<span class="dashicons dashicons-update" style="color: #dba617; margin-right: 5px;"></span>
|
<span class="dashicons dashicons-update" style="color: #dba617; margin-right: 5px;"></span>
|
||||||
<strong>Minecraft Modern Update verfügbar:</strong>
|
<strong>Minecraft Modern Update verfügbar:</strong>
|
||||||
Version <strong><?php echo esc_html( $latest['version'] ); ?></strong> ist bereit zum Download.
|
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;">
|
<a href="<?php echo esc_url( $latest['url'] ); ?>" target="_blank" style="margin-left: 10px; font-weight: bold;">
|
||||||
Zum Download →
|
Zum Download →
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fügt das Widget zum WordPress-Dashboard hinzu.
|
* Fügt das Widget zum WordPress-Dashboard hinzu.
|
||||||
*/
|
*/
|
||||||
public function add_dashboard_widget() {
|
public function add_dashboard_widget() {
|
||||||
wp_add_dashboard_widget(
|
wp_add_dashboard_widget(
|
||||||
'mm_theme_status_widget',
|
'mm_theme_status_widget',
|
||||||
'Minecraft Modern Theme Status',
|
'Minecraft Modern Theme Status',
|
||||||
[ $this, 'render_widget_content' ]
|
[ $this, 'render_widget_content' ]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTML-Inhalt des Dashboard-Widgets.
|
* HTML-Inhalt des Dashboard-Widgets.
|
||||||
*/
|
*/
|
||||||
public function render_widget_content() {
|
public function render_widget_content() {
|
||||||
$current_version = wp_get_theme( $this->theme_slug )->get( 'Version' );
|
$current_version = wp_get_theme( $this->theme_slug )->get( 'Version' );
|
||||||
$latest = $this->get_latest_release();
|
$latest = $this->get_latest_release();
|
||||||
|
|
||||||
echo '<div class="mm-status-widget">';
|
echo '<div class="mm-status-widget">';
|
||||||
echo '<p><span class="dashicons dashicons-admin-appearance"></span> <strong>Installiert:</strong> ' . esc_html( $current_version ?: '–' ) . '</p>';
|
echo '<p><span class="dashicons dashicons-admin-appearance"></span> <strong>Installiert:</strong> ' . esc_html( $current_version ?: '–' ) . '</p>';
|
||||||
|
|
||||||
if ( isset( $latest['version'] ) ) {
|
if ( isset( $latest['version'] ) ) {
|
||||||
echo '<p><span class="dashicons dashicons-cloud"></span> <strong>Aktuellste:</strong> ' . esc_html( $latest['version'] ) . '</p>';
|
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'], '<' ) ) {
|
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 '<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 '<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 '<a href="' . esc_url( $latest['url'] ) . '" class="button button-primary" target="_blank">Download ZIP von Gitea</a>';
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
} else {
|
} else {
|
||||||
echo '<p style="color: #46b450; font-weight: bold; margin-top: 15px;">';
|
echo '<p style="color: #46b450; font-weight: bold; margin-top: 15px;">';
|
||||||
echo '<span class="dashicons dashicons-yes"></span> Theme ist aktuell.</p>';
|
echo '<span class="dashicons dashicons-yes"></span> Theme ist aktuell.</p>';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
echo '<p style="color: #d63638;"><span class="dashicons dashicons-warning"></span> Prüfung fehlgeschlagen.</p>';
|
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' );
|
$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 '<hr><p><small><a href="' . esc_url( $refresh_url ) . '">Update-Cache jetzt leeren</a></small></p>';
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verarbeitet den Klick auf "Update-Cache jetzt leeren".
|
* Verarbeitet den Klick auf "Update-Cache jetzt leeren".
|
||||||
*/
|
*/
|
||||||
public function handle_refresh_request() {
|
public function handle_refresh_request() {
|
||||||
if ( isset( $_GET['mm_refresh_check'] ) && check_admin_referer( 'mm_refresh_action' ) ) {
|
if ( isset( $_GET['mm_refresh_check'] ) && check_admin_referer( 'mm_refresh_action' ) ) {
|
||||||
delete_transient( $this->transient_key );
|
delete_transient( $this->transient_key );
|
||||||
wp_redirect( admin_url( 'index.php' ) );
|
wp_redirect( admin_url( 'index.php' ) );
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new Minecraft_Modern_Theme_Manager();
|
new Minecraft_Modern_Theme_Manager();
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Registrierung der Footer- und Startseiten-Widget-Bereiche
|
||||||
|
*
|
||||||
|
* Ausgelagert aus functions.php.
|
||||||
|
*
|
||||||
|
* @package Minecraft-Modern-Theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// === Footer-Widgets registrieren ===
|
||||||
|
function minecraft_modern_footer_widgets() {
|
||||||
|
register_sidebar( array(
|
||||||
|
'name' => __( 'Footer Links', 'minecraft-modern-theme' ),
|
||||||
|
'id' => 'footer-left',
|
||||||
|
'description' => __( 'Widget-Bereich links im Footer.', 'minecraft-modern-theme' ),
|
||||||
|
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h4 class="widget-title">',
|
||||||
|
'after_title' => '</h4>',
|
||||||
|
) );
|
||||||
|
for ( $i = 1; $i <= 3; $i++ ) {
|
||||||
|
register_sidebar( array(
|
||||||
|
'name' => sprintf( __( 'Footer Spalte %d', 'minecraft-modern-theme' ), $i ),
|
||||||
|
'id' => 'footer-' . $i,
|
||||||
|
'description' => sprintf( __( 'Widget für die %d. Spalte im Footer.', 'minecraft-modern-theme' ), $i ),
|
||||||
|
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h4 class="widget-title">',
|
||||||
|
'after_title' => '</h4>',
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
register_sidebar( array(
|
||||||
|
'name' => __( 'Footer Rechts', 'minecraft-modern-theme' ),
|
||||||
|
'id' => 'footer-right',
|
||||||
|
'description' => __( 'Widget-Bereich rechts im Footer.', 'minecraft-modern-theme' ),
|
||||||
|
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h4 class="widget-title">',
|
||||||
|
'after_title' => '</h4>',
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'widgets_init', 'minecraft_modern_footer_widgets' );
|
||||||
|
|
||||||
|
|
||||||
|
// === Homepage Sidebar registrieren ===
|
||||||
|
function minecraft_modern_homepage_sidebar() {
|
||||||
|
register_sidebar( array(
|
||||||
|
'name' => __( 'Startseiten Sidebar - Oben', 'minecraft-modern-theme' ),
|
||||||
|
'id' => 'homepage-sidebar-top',
|
||||||
|
'description' => __( 'Widget-Bereich oben in der Sidebar (z.B. für wichtige Infos).', 'minecraft-modern-theme' ),
|
||||||
|
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3 class="widget-title">',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
) );
|
||||||
|
register_sidebar( array(
|
||||||
|
'name' => __( 'Startseiten Sidebar - Mitte 1', 'minecraft-modern-theme' ),
|
||||||
|
'id' => 'homepage-sidebar-middle-1',
|
||||||
|
'description' => __( 'Widget-Bereich in der Mitte der Sidebar.', 'minecraft-modern-theme' ),
|
||||||
|
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3 class="widget-title">',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
) );
|
||||||
|
register_sidebar( array(
|
||||||
|
'name' => __( 'Startseiten Sidebar - Mitte 2', 'minecraft-modern-theme' ),
|
||||||
|
'id' => 'homepage-sidebar-middle-2',
|
||||||
|
'description' => __( 'Zweiter Widget-Bereich in der Mitte der Sidebar.', 'minecraft-modern-theme' ),
|
||||||
|
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3 class="widget-title">',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
) );
|
||||||
|
register_sidebar( array(
|
||||||
|
'name' => __( 'Startseiten Sidebar - Unten', 'minecraft-modern-theme' ),
|
||||||
|
'id' => 'homepage-sidebar-bottom',
|
||||||
|
'description' => __( 'Widget-Bereich unten in der Sidebar.', 'minecraft-modern-theme' ),
|
||||||
|
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3 class="widget-title">',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
) );
|
||||||
|
register_sidebar( array(
|
||||||
|
'name' => __( 'Startseiten Sidebar - Extra', 'minecraft-modern-theme' ),
|
||||||
|
'id' => 'homepage-sidebar-extra',
|
||||||
|
'description' => __( 'Zusätzlicher Widget-Bereich für spezielle Inhalte.', 'minecraft-modern-theme' ),
|
||||||
|
'before_widget' => '<div id="%1$s" class="widget %2$s">',
|
||||||
|
'after_widget' => '</div>',
|
||||||
|
'before_title' => '<h3 class="widget-title">',
|
||||||
|
'after_title' => '</h3>',
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
add_action( 'widgets_init', 'minecraft_modern_homepage_sidebar' );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rendert alle Sidebar-Sections der Homepage.
|
||||||
|
* Ersetzt den doppelten Sidebar-Code in front-page.php.
|
||||||
|
*/
|
||||||
|
function minecraft_modern_render_sidebar_sections() {
|
||||||
|
$sections = array(
|
||||||
|
'homepage-sidebar-top',
|
||||||
|
'homepage-sidebar-middle-1',
|
||||||
|
'homepage-sidebar-middle-2',
|
||||||
|
'homepage-sidebar-bottom',
|
||||||
|
'homepage-sidebar-extra',
|
||||||
|
);
|
||||||
|
$classes = array(
|
||||||
|
'homepage-sidebar-top' => 'sidebar-top',
|
||||||
|
'homepage-sidebar-middle-1' => 'sidebar-middle-1',
|
||||||
|
'homepage-sidebar-middle-2' => 'sidebar-middle-2',
|
||||||
|
'homepage-sidebar-bottom' => 'sidebar-bottom',
|
||||||
|
'homepage-sidebar-extra' => 'sidebar-extra',
|
||||||
|
);
|
||||||
|
foreach ( $sections as $sidebar_id ) {
|
||||||
|
if ( is_active_sidebar( $sidebar_id ) ) {
|
||||||
|
$class = isset( $classes[ $sidebar_id ] ) ? ' ' . $classes[ $sidebar_id ] : '';
|
||||||
|
echo '<div class="sidebar-section' . esc_attr( $class ) . '">';
|
||||||
|
dynamic_sidebar( $sidebar_id );
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,76 +1,76 @@
|
|||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
const bar = document.getElementById("mm-announcement");
|
const bar = document.getElementById("mm-announcement");
|
||||||
if (!bar) return;
|
if (!bar) return;
|
||||||
|
|
||||||
// --- 1. Positionierung ---
|
// --- 1. Positionierung ---
|
||||||
const position = bar.dataset.position || 'below-header';
|
const position = bar.dataset.position || 'below-header';
|
||||||
|
|
||||||
if (position === "top") {
|
if (position === "top") {
|
||||||
document.body.insertAdjacentElement('afterbegin', bar);
|
document.body.insertAdjacentElement('afterbegin', bar);
|
||||||
} else if (position === "below-slider") {
|
} else if (position === "below-slider") {
|
||||||
const anchor = document.getElementById("mm-announcement-anchor");
|
const anchor = document.getElementById("mm-announcement-anchor");
|
||||||
if (anchor) {
|
if (anchor) {
|
||||||
anchor.replaceWith(bar);
|
anchor.replaceWith(bar);
|
||||||
} else {
|
} else {
|
||||||
const header = document.getElementById("masthead");
|
const header = document.getElementById("masthead");
|
||||||
if (header) header.insertAdjacentElement('afterend', bar);
|
if (header) header.insertAdjacentElement('afterend', bar);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// "below-header" und alle anderen Positionen
|
// "below-header" und alle anderen Positionen
|
||||||
const header = document.getElementById("masthead");
|
const header = document.getElementById("masthead");
|
||||||
if (header) header.insertAdjacentElement('afterend', bar);
|
if (header) header.insertAdjacentElement('afterend', bar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 2. Schließen-Button ---
|
// --- 2. Schließen-Button ---
|
||||||
const closeBtn = bar.querySelector(".mm-announcement-close");
|
const closeBtn = bar.querySelector(".mm-announcement-close");
|
||||||
if (closeBtn) {
|
if (closeBtn) {
|
||||||
closeBtn.addEventListener("click", function () {
|
closeBtn.addEventListener("click", function () {
|
||||||
bar.style.transition = 'opacity 0.3s ease';
|
bar.style.transition = 'opacity 0.3s ease';
|
||||||
bar.style.opacity = '0';
|
bar.style.opacity = '0';
|
||||||
setTimeout(function() { bar.style.display = "none"; }, 300);
|
setTimeout(function() { bar.style.display = "none"; }, 300);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 3. Countdown Timer ---
|
// --- 3. Countdown Timer ---
|
||||||
const timerElement = document.querySelector('.mm-countdown-timer');
|
const timerElement = document.querySelector('.mm-countdown-timer');
|
||||||
|
|
||||||
if (timerElement) {
|
if (timerElement) {
|
||||||
const targetDateString = timerElement.getAttribute('data-date');
|
const targetDateString = timerElement.getAttribute('data-date');
|
||||||
const expiredMessage = timerElement.getAttribute('data-expired') || 'Abgelaufen';
|
const expiredMessage = timerElement.getAttribute('data-expired') || 'Abgelaufen';
|
||||||
|
|
||||||
if (!targetDateString) {
|
if (!targetDateString) {
|
||||||
timerElement.style.display = 'none';
|
timerElement.style.display = 'none';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const countDownDate = new Date(targetDateString).getTime();
|
const countDownDate = new Date(targetDateString).getTime();
|
||||||
|
|
||||||
// FIX: Tick-Funktion auslagern und SOFORT aufrufen – kein 1s-Flackern beim Laden
|
// FIX: Tick-Funktion auslagern und SOFORT aufrufen – kein 1s-Flackern beim Laden
|
||||||
function tick() {
|
function tick() {
|
||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
const distance = countDownDate - now;
|
const distance = countDownDate - now;
|
||||||
|
|
||||||
if (distance < 0) {
|
if (distance < 0) {
|
||||||
clearInterval(timerInterval);
|
clearInterval(timerInterval);
|
||||||
timerElement.innerHTML = expiredMessage;
|
timerElement.innerHTML = expiredMessage;
|
||||||
timerElement.style.color = '#ff3333';
|
timerElement.style.color = '#ff3333';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
||||||
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||||
|
|
||||||
const fDays = days > 0 ? days + 'd ' : '';
|
const fDays = days > 0 ? days + 'd ' : '';
|
||||||
const fHours = String(hours).padStart(2, '0');
|
const fHours = String(hours).padStart(2, '0');
|
||||||
const fMinutes = String(minutes).padStart(2, '0');
|
const fMinutes = String(minutes).padStart(2, '0');
|
||||||
const fSeconds = String(seconds).padStart(2, '0');
|
const fSeconds = String(seconds).padStart(2, '0');
|
||||||
|
|
||||||
timerElement.innerHTML = fDays + fHours + ':' + fMinutes + ':' + fSeconds;
|
timerElement.innerHTML = fDays + fHours + ':' + fMinutes + ':' + fSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
tick(); // Sofort ausführen
|
tick(); // Sofort ausführen
|
||||||
const timerInterval = setInterval(tick, 1000);
|
const timerInterval = setInterval(tick, 1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1 +1 @@
|
|||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/**
|
||||||
|
* Verwaltungsseite "Menü-Links": Zeilen hinzufügen, entfernen,
|
||||||
|
* Icon-Vorschau aktualisieren.
|
||||||
|
*/
|
||||||
|
( function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/** Feldnamen durchnummerieren, damit PHP ein lückenloses Array erhält. */
|
||||||
|
function neuNummerieren( liste ) {
|
||||||
|
var feld = liste.getAttribute( 'data-mm-liste' );
|
||||||
|
if ( ! feld ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var muster = new RegExp( feld.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' ) + '\\[[^\\]]*\\]' );
|
||||||
|
|
||||||
|
liste.querySelectorAll( ':scope > .mm-liste-zeile' ).forEach( function ( zeile, i ) {
|
||||||
|
zeile.querySelectorAll( '[name^="' + feld + '["]' ).forEach( function ( eingabe ) {
|
||||||
|
eingabe.name = eingabe.name.replace( muster, feld + '[' + i + ']' );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Vorschausymbol links in der Zeile an das Icon-Feld angleichen. */
|
||||||
|
function vorschauAktualisieren( zeile ) {
|
||||||
|
var feld = zeile.querySelector( '.mm-icon-feld' );
|
||||||
|
var bild = zeile.querySelector( '.mm-vorschau' );
|
||||||
|
if ( ! feld || ! bild ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var klasse = feld.value.trim() || 'dashicons-admin-links';
|
||||||
|
bild.className = 'mm-vorschau dashicons ' + klasse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Zeile hinzufügen ---
|
||||||
|
document.addEventListener( 'click', function ( e ) {
|
||||||
|
var knopf = e.target.closest( '.mm-liste-hinzufuegen' );
|
||||||
|
if ( ! knopf ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var feld = knopf.getAttribute( 'data-ziel' );
|
||||||
|
var liste = document.querySelector( '.mm-liste[data-mm-liste="' + feld + '"]' );
|
||||||
|
var vorlage = document.querySelector( '.mm-liste-vorlage[data-fuer="' + feld + '"]' );
|
||||||
|
if ( ! liste || ! vorlage ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var huelle = document.createElement( 'div' );
|
||||||
|
huelle.innerHTML = vorlage.innerHTML.replace( /__INDEX__/g, String( Date.now() ) ).trim();
|
||||||
|
|
||||||
|
var zeile = huelle.querySelector( '.mm-liste-zeile' );
|
||||||
|
if ( ! zeile ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
liste.appendChild( zeile );
|
||||||
|
neuNummerieren( liste );
|
||||||
|
|
||||||
|
var hinweis = document.querySelector( '.mm-leer' );
|
||||||
|
if ( hinweis ) {
|
||||||
|
hinweis.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
var erstes = zeile.querySelector( 'input' );
|
||||||
|
if ( erstes ) {
|
||||||
|
erstes.focus();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// --- Zeile entfernen ---
|
||||||
|
document.addEventListener( 'click', function ( e ) {
|
||||||
|
var knopf = e.target.closest( '.mm-liste-entfernen' );
|
||||||
|
if ( ! knopf ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var zeile = knopf.closest( '.mm-liste-zeile' );
|
||||||
|
var liste = zeile ? zeile.closest( '.mm-liste' ) : null;
|
||||||
|
if ( ! zeile || ! liste ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zeile.remove();
|
||||||
|
neuNummerieren( liste );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// --- Icon-Vorschau ---
|
||||||
|
document.addEventListener( 'input', function ( e ) {
|
||||||
|
if ( e.target.classList.contains( 'mm-icon-feld' ) ) {
|
||||||
|
var zeile = e.target.closest( '.mm-liste-zeile' );
|
||||||
|
if ( zeile ) {
|
||||||
|
vorschauAktualisieren( zeile );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Klick auf ein Beispielsymbol trägt die Klasse in die letzte Zeile ein
|
||||||
|
document.addEventListener( 'click', function ( e ) {
|
||||||
|
var code = e.target.closest( '.mm-icon-liste code' );
|
||||||
|
if ( ! code ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var zeilen = document.querySelectorAll( '.mm-liste-zeile' );
|
||||||
|
if ( ! zeilen.length ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var letzte = zeilen[ zeilen.length - 1 ];
|
||||||
|
var feld = letzte.querySelector( '.mm-icon-feld' );
|
||||||
|
if ( feld ) {
|
||||||
|
feld.value = code.textContent.trim();
|
||||||
|
vorschauAktualisieren( letzte );
|
||||||
|
feld.focus();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} )();
|
||||||
@@ -1,63 +1,63 @@
|
|||||||
// Lädt skinview3d von CDN
|
// Lädt skinview3d von CDN
|
||||||
(function(){
|
(function(){
|
||||||
if(document.getElementById('skinview3d-cdn')) return;
|
if(document.getElementById('skinview3d-cdn')) return;
|
||||||
var s = document.createElement('script');
|
var s = document.createElement('script');
|
||||||
s.id = 'skinview3d-cdn';
|
s.id = 'skinview3d-cdn';
|
||||||
s.src = 'https://unpkg.com/skinview3d@4.1.1/bundles/skinview3d.min.js';
|
s.src = 'https://unpkg.com/skinview3d@4.1.1/bundles/skinview3d.min.js';
|
||||||
s.onload = function() {
|
s.onload = function() {
|
||||||
window.skinview3dReady = true;
|
window.skinview3dReady = true;
|
||||||
};
|
};
|
||||||
document.head.appendChild(s);
|
document.head.appendChild(s);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
window.showMinecraftSkinModal = function(uuid) {
|
window.showMinecraftSkinModal = function(uuid) {
|
||||||
if(document.getElementById('minecraft-skin-modal')) return;
|
if(document.getElementById('minecraft-skin-modal')) return;
|
||||||
var modal = document.createElement('div');
|
var modal = document.createElement('div');
|
||||||
modal.id = 'minecraft-skin-modal';
|
modal.id = 'minecraft-skin-modal';
|
||||||
modal.innerHTML = `
|
modal.innerHTML = `
|
||||||
<div class="sv3d-modal-bg"></div>
|
<div class="sv3d-modal-bg"></div>
|
||||||
<div class="sv3d-modal-content">
|
<div class="sv3d-modal-content">
|
||||||
<button class="sv3d-modal-close" aria-label="Schließen">×</button>
|
<button class="sv3d-modal-close" aria-label="Schließen">×</button>
|
||||||
<div id="sv3d-canvas-wrap" style="width:320px;height:320px;"></div>
|
<div id="sv3d-canvas-wrap" style="width:320px;height:320px;"></div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
document.body.appendChild(modal);
|
document.body.appendChild(modal);
|
||||||
document.querySelector('.sv3d-modal-close').onclick = function(){ modal.remove(); };
|
document.querySelector('.sv3d-modal-close').onclick = function(){ modal.remove(); };
|
||||||
document.querySelector('.sv3d-modal-bg').onclick = function(){ modal.remove(); };
|
document.querySelector('.sv3d-modal-bg').onclick = function(){ modal.remove(); };
|
||||||
|
|
||||||
function renderSkin() {
|
function renderSkin() {
|
||||||
var skinUrl = `https://crafatar.com/skins/${uuid}`;
|
var skinUrl = `https://crafatar.com/skins/${uuid}`;
|
||||||
var canvas = document.createElement('canvas');
|
var canvas = document.createElement('canvas');
|
||||||
canvas.width = 320; canvas.height = 320;
|
canvas.width = 320; canvas.height = 320;
|
||||||
document.getElementById('sv3d-canvas-wrap').appendChild(canvas);
|
document.getElementById('sv3d-canvas-wrap').appendChild(canvas);
|
||||||
var viewer = new skinview3d.SkinViewer({
|
var viewer = new skinview3d.SkinViewer({
|
||||||
canvas: canvas,
|
canvas: canvas,
|
||||||
width: 320,
|
width: 320,
|
||||||
height: 320,
|
height: 320,
|
||||||
skin: skinUrl
|
skin: skinUrl
|
||||||
});
|
});
|
||||||
viewer.controls.enableZoom = false;
|
viewer.controls.enableZoom = false;
|
||||||
viewer.animation = new skinview3d.WalkingAnimation();
|
viewer.animation = new skinview3d.WalkingAnimation();
|
||||||
viewer.animation.speed = 1.2;
|
viewer.animation.speed = 1.2;
|
||||||
viewer.animation.play();
|
viewer.animation.play();
|
||||||
}
|
}
|
||||||
if(window.skinview3dReady) renderSkin();
|
if(window.skinview3dReady) renderSkin();
|
||||||
else {
|
else {
|
||||||
var check = setInterval(function(){
|
var check = setInterval(function(){
|
||||||
if(window.skinview3dReady) { clearInterval(check); renderSkin(); }
|
if(window.skinview3dReady) { clearInterval(check); renderSkin(); }
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Avatar-Widget-Click-Handler
|
// Avatar-Widget-Click-Handler
|
||||||
window.addEventListener('DOMContentLoaded', function(){
|
window.addEventListener('DOMContentLoaded', function(){
|
||||||
var widget = document.getElementById('minecraft-avatar-widget');
|
var widget = document.getElementById('minecraft-avatar-widget');
|
||||||
if(widget) {
|
if(widget) {
|
||||||
widget.style.cursor = 'pointer';
|
widget.style.cursor = 'pointer';
|
||||||
widget.title = 'Klicke für 3D Skin-Ansicht';
|
widget.title = 'Klicke für 3D Skin-Ansicht';
|
||||||
widget.onclick = function(){
|
widget.onclick = function(){
|
||||||
var uuid = widget.getAttribute('data-uuid');
|
var uuid = widget.getAttribute('data-uuid');
|
||||||
if(uuid) window.showMinecraftSkinModal(uuid);
|
if(uuid) window.showMinecraftSkinModal(uuid);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user