Upload folder via GUI - includes

This commit is contained in:
Git Manager GUI
2026-05-11 09:17:15 +02:00
parent 85cb7ef400
commit 4c4e87c565
8 changed files with 477 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
// Extra Spalten in der Admin-Übersicht
add_filter( 'manage_mc_news_posts_columns', 'mcn_admin_columns' );
function mcn_admin_columns( $cols ) {
$new = [];
foreach ( $cols as $key => $val ) {
$new[ $key ] = $val;
if ( $key === 'title' ) {
$new['mcn_pinned'] = '📌 Angepinnt';
$new['mcn_badge'] = '🏷️ Badge';
$new['mcn_category'] = '📂 Kategorie';
}
}
return $new;
}
add_action( 'manage_mc_news_posts_custom_column', 'mcn_admin_column_content', 10, 2 );
function mcn_admin_column_content( $col, $post_id ) {
switch ( $col ) {
case 'mcn_pinned':
echo get_post_meta( $post_id, '_mcn_pinned', true ) ? '✅' : '—';
break;
case 'mcn_badge':
$b = get_post_meta( $post_id, '_mcn_badge', true );
echo $b ? '<strong>' . esc_html( $b ) . '</strong>' : '—';
break;
case 'mcn_category':
$terms = get_the_terms( $post_id, 'mc_news_category' );
if ( $terms ) {
echo esc_html( implode( ', ', wp_list_pluck( $terms, 'name' ) ) );
} else {
echo '—';
}
break;
}
}

35
includes/assets.php Normal file
View File

@@ -0,0 +1,35 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
add_action( 'wp_enqueue_scripts', 'mcn_enqueue_assets' );
function mcn_enqueue_assets() {
global $post;
// Nur laden wenn Shortcode auf der Seite ist
if ( is_a( $post, 'WP_Post' ) && (
has_shortcode( $post->post_content, 'server_news' ) ||
is_singular( 'mc_news' ) ||
is_post_type_archive( 'mc_news' )
) ) {
wp_enqueue_style(
'mcn-styles',
MCN_URL . 'assets/css/mcn-style.css',
[],
MCN_VERSION
);
wp_enqueue_script(
'mcn-scripts',
MCN_URL . 'assets/js/mcn-script.js',
[],
MCN_VERSION,
true
);
}
}
add_action( 'admin_enqueue_scripts', 'mcn_admin_assets' );
function mcn_admin_assets( $hook ) {
$screen = get_current_screen();
if ( $screen && $screen->post_type === 'mc_news' ) {
wp_enqueue_style( 'mcn-admin', MCN_URL . 'assets/css/mcn-admin.css', [], MCN_VERSION );
}
}

60
includes/metaboxes.php Normal file
View File

@@ -0,0 +1,60 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
add_action( 'add_meta_boxes', 'mcn_add_metaboxes' );
function mcn_add_metaboxes() {
add_meta_box(
'mcn_news_options',
'⛏ News-Einstellungen',
'mcn_render_metabox',
'mc_news',
'side',
'high'
);
}
function mcn_render_metabox( $post ) {
wp_nonce_field( 'mcn_save_meta', 'mcn_nonce' );
$pinned = get_post_meta( $post->ID, '_mcn_pinned', true );
$badge = get_post_meta( $post->ID, '_mcn_badge', true );
$server_ip = get_post_meta( $post->ID, '_mcn_server_ip', true );
?>
<p>
<label><strong>📌 Angepinnt (immer oben)</strong></label><br>
<input type="checkbox" name="mcn_pinned" value="1" <?php checked( $pinned, '1' ); ?>>
<span>Diese News oben anzeigen</span>
</p>
<hr>
<p>
<label><strong>🏷️ Badge / Label</strong></label><br>
<select name="mcn_badge" style="width:100%">
<option value=""> Kein Badge </option>
<?php
$badges = [ 'NEU', 'WICHTIG', 'HOT', 'BETA', 'LIVE', 'BALD' ];
foreach ( $badges as $b ) {
printf( '<option value="%s" %s>%s</option>', $b, selected( $badge, $b, false ), $b );
}
?>
</select>
</p>
<hr>
<p>
<label><strong>🖥️ Server-IP (optional)</strong></label><br>
<input type="text" name="mcn_server_ip" value="<?php echo esc_attr( $server_ip ); ?>"
placeholder="play.deinserver.de" style="width:100%">
<small>Wird in der News-Karte angezeigt</small>
</p>
<?php
}
add_action( 'save_post_mc_news', 'mcn_save_metabox' );
function mcn_save_metabox( $post_id ) {
if ( ! isset( $_POST['mcn_nonce'] ) || ! wp_verify_nonce( $_POST['mcn_nonce'], 'mcn_save_meta' ) ) return;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( ! current_user_can( 'edit_post', $post_id ) ) return;
update_post_meta( $post_id, '_mcn_pinned', isset( $_POST['mcn_pinned'] ) ? '1' : '' );
update_post_meta( $post_id, '_mcn_badge', sanitize_text_field( $_POST['mcn_badge'] ?? '' ) );
update_post_meta( $post_id, '_mcn_server_ip', sanitize_text_field( $_POST['mcn_server_ip'] ?? '' ) );
}

31
includes/post-type.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
add_action( 'init', 'mcn_register_post_type' );
function mcn_register_post_type() {
$labels = [
'name' => 'Server News',
'singular_name' => 'News',
'add_new' => 'News hinzufügen',
'add_new_item' => 'Neue News erstellen',
'edit_item' => 'News bearbeiten',
'new_item' => 'Neue News',
'view_item' => 'News ansehen',
'search_items' => 'News suchen',
'not_found' => 'Keine News gefunden',
'not_found_in_trash' => 'Keine News im Papierkorb',
'menu_name' => '⛏ Server News',
];
register_post_type( 'mc_news', [
'labels' => $labels,
'public' => true,
'show_in_menu' => true,
'menu_icon' => 'dashicons-megaphone',
'menu_position' => 5,
'supports' => [ 'title', 'editor', 'thumbnail', 'excerpt', 'author' ],
'has_archive' => true,
'rewrite' => [ 'slug' => 'server-news' ],
'show_in_rest' => true,
] );
}

140
includes/shortcode.php Normal file
View File

@@ -0,0 +1,140 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
add_shortcode( 'server_news', 'mcn_render_shortcode' );
function mcn_render_shortcode( $atts ) {
$atts = shortcode_atts( [
'anzahl' => 10,
'kategorie' => '',
'layout' => 'grid', // grid | list
'badge' => '',
], $atts, 'server_news' );
$args = [
'post_type' => 'mc_news',
'posts_per_page' => intval( $atts['anzahl'] ),
'post_status' => 'publish',
'meta_query' => [],
'tax_query' => [],
];
// Kategorie-Filter
if ( ! empty( $atts['kategorie'] ) ) {
$args['tax_query'][] = [
'taxonomy' => 'mc_news_category',
'field' => 'slug',
'terms' => array_map( 'trim', explode( ',', $atts['kategorie'] ) ),
];
}
// Angepinnte zuerst
$pinned_args = $args;
$pinned_args['meta_query'][] = [ 'key' => '_mcn_pinned', 'value' => '1' ];
$pinned_query = new WP_Query( $pinned_args );
$normal_args = $args;
$normal_args['meta_query'][] = [
'relation' => 'OR',
[ 'key' => '_mcn_pinned', 'compare' => 'NOT EXISTS' ],
[ 'key' => '_mcn_pinned', 'value' => '', 'compare' => '=' ],
];
$normal_query = new WP_Query( $normal_args );
ob_start();
?>
<div class="mcn-wrapper mcn-layout-<?php echo esc_attr( $atts['layout'] ); ?>">
<?php // ---- Filter-Bar ---- ?>
<div class="mcn-filterbar">
<button class="mcn-filter-btn active" data-filter="all">📋 Alle</button>
<?php
$cats = get_terms( [ 'taxonomy' => 'mc_news_category', 'hide_empty' => true ] );
foreach ( $cats as $cat ) {
$icon = ! empty( $cat->description ) ? $cat->description . ' ' : '';
printf(
'<button class="mcn-filter-btn" data-filter="%s">%s%s</button>',
esc_attr( $cat->slug ),
$icon,
esc_html( $cat->name )
);
}
?>
</div>
<div class="mcn-grid">
<?php
// Angepinnte zuerst
foreach ( [ $pinned_query, $normal_query ] as $query ) {
while ( $query->have_posts() ) {
$query->the_post();
$post_id = get_the_ID();
$pinned = get_post_meta( $post_id, '_mcn_pinned', true );
$badge = get_post_meta( $post_id, '_mcn_badge', true );
$server_ip = get_post_meta( $post_id, '_mcn_server_ip', true );
$cats = get_the_terms( $post_id, 'mc_news_category' );
$cat_slugs = $cats ? implode( ' ', wp_list_pluck( $cats, 'slug' ) ) : '';
$cat_name = $cats ? $cats[0]->name : '';
$cat_icon = $cats ? $cats[0]->description : '📰';
?>
<article class="mcn-card <?php echo $pinned ? 'mcn-pinned' : ''; ?>"
data-category="<?php echo esc_attr( $cat_slugs ); ?>">
<?php if ( $pinned ) : ?>
<div class="mcn-pin-label">📌 Angepinnt</div>
<?php endif; ?>
<?php if ( $badge ) : ?>
<div class="mcn-badge mcn-badge-<?php echo esc_attr( strtolower( $badge ) ); ?>"><?php echo esc_html( $badge ); ?></div>
<?php endif; ?>
<?php if ( has_post_thumbnail() ) : ?>
<div class="mcn-card-image">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail( 'medium_large' ); ?>
</a>
</div>
<?php endif; ?>
<div class="mcn-card-body">
<?php if ( $cat_name ) : ?>
<span class="mcn-cat-tag"><?php echo $cat_icon . ' ' . esc_html( $cat_name ); ?></span>
<?php endif; ?>
<h2 class="mcn-card-title">
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</h2>
<div class="mcn-card-meta">
<span class="mcn-date">📅 <?php echo get_the_date( 'd.m.Y' ); ?></span>
<span class="mcn-author">✍️ <?php the_author(); ?></span>
</div>
<div class="mcn-card-excerpt">
<?php echo wp_trim_words( get_the_excerpt(), 20, '…' ); ?>
</div>
<?php if ( $server_ip ) : ?>
<div class="mcn-server-ip">
🖥️ <span><?php echo esc_html( $server_ip ); ?></span>
<button class="mcn-copy-btn" data-ip="<?php echo esc_attr( $server_ip ); ?>">Kopieren</button>
</div>
<?php endif; ?>
<a href="<?php the_permalink(); ?>" class="mcn-read-more">Weiterlesen →</a>
</div>
</article>
<?php
}
}
wp_reset_postdata();
?>
</div><!-- .mcn-grid -->
<div class="mcn-empty" style="display:none">
<p>😔 Keine News in dieser Kategorie gefunden.</p>
</div>
</div><!-- .mcn-wrapper -->
<?php
return ob_get_clean();
}

50
includes/taxonomies.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
add_action( 'init', 'msn_register_taxonomies' );
function msn_register_taxonomies() {
/* --- Kategorie (Update, Event, Wartung …) --- */
register_taxonomy( 'msn_category', 'msn_news', [
'labels' => [
'name' => 'News-Kategorien',
'singular_name' => 'Kategorie',
'add_new_item' => 'Neue Kategorie',
'edit_item' => 'Kategorie bearbeiten',
'search_items' => 'Kategorien suchen',
'not_found' => 'Keine Kategorien gefunden',
'menu_name' => 'Kategorien',
],
'hierarchical' => true,
'show_in_menu' => true,
'show_in_rest' => true,
'rewrite' => [ 'slug' => 'news-kategorie' ],
] );
}
/* -------------------------------------------------------
Standard-Kategorien beim ersten Aktivieren anlegen
------------------------------------------------------- */
add_action( 'init', 'msn_insert_default_categories', 20 );
function msn_insert_default_categories() {
if ( get_option( 'msn_defaults_created' ) ) return;
$defaults = [
[ 'name' => '🔧 Update', 'slug' => 'update', 'description' => 'Server-Updates & Patches' ],
[ 'name' => '🎉 Event', 'slug' => 'event', 'description' => 'Community-Events & Aktionen' ],
[ 'name' => '⚠️ Wartung', 'slug' => 'wartung', 'description' => 'Geplante Wartungsarbeiten' ],
[ 'name' => '📢 Ankündigung', 'slug' => 'ankundigung','description' => 'Wichtige Ankündigungen' ],
[ 'name' => '🐛 Bugfix', 'slug' => 'bugfix', 'description' => 'Fehlerbehebungen' ],
];
foreach ( $defaults as $cat ) {
if ( ! term_exists( $cat['slug'], 'msn_category' ) ) {
wp_insert_term( $cat['name'], 'msn_category', [
'slug' => $cat['slug'],
'description' => $cat['description'],
] );
}
}
update_option( 'msn_defaults_created', true );
}

45
includes/taxonomy.php Normal file
View File

@@ -0,0 +1,45 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
add_action( 'init', 'mcn_register_taxonomy' );
function mcn_register_taxonomy() {
$labels = [
'name' => 'Kategorien',
'singular_name' => 'Kategorie',
'search_items' => 'Kategorien suchen',
'all_items' => 'Alle Kategorien',
'parent_item' => 'Übergeordnete Kategorie',
'edit_item' => 'Kategorie bearbeiten',
'update_item' => 'Kategorie aktualisieren',
'add_new_item' => 'Neue Kategorie',
'new_item_name' => 'Name der neuen Kategorie',
'menu_name' => 'Kategorien',
];
register_taxonomy( 'mc_news_category', 'mc_news', [
'labels' => $labels,
'hierarchical' => true,
'public' => true,
'show_admin_column' => true,
'rewrite' => [ 'slug' => 'news-kategorie' ],
'show_in_rest' => true,
] );
// Standard-Kategorien beim ersten Aufruf anlegen
add_action( 'init', function() {
$defaults = [
'Update' => '🔄',
'Event' => '🎉',
'Wartung' => '🔧',
'Wichtig' => '⚠️',
'Community' => '👥',
];
foreach ( $defaults as $name => $icon ) {
if ( ! term_exists( $name, 'mc_news_category' ) ) {
wp_insert_term( $name, 'mc_news_category', [
'description' => $icon,
] );
}
}
}, 20 );
}

78
includes/widget.php Normal file
View File

@@ -0,0 +1,78 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
add_action( 'widgets_init', function() {
register_widget( 'MCN_Latest_News_Widget' );
} );
class MCN_Latest_News_Widget extends WP_Widget {
public function __construct() {
parent::__construct( 'mcn_latest_news', '⛏ Minecraft Server News', [
'description' => 'Zeigt die neuesten Server-News in der Sidebar.',
] );
}
public function widget( $args, $instance ) {
$title = apply_filters( 'widget_title', $instance['title'] ?? 'Server News' );
$anzahl = intval( $instance['anzahl'] ?? 3 );
echo $args['before_widget'];
if ( $title ) echo $args['before_title'] . $title . $args['after_title'];
$query = new WP_Query( [
'post_type' => 'mc_news',
'posts_per_page' => $anzahl,
'post_status' => 'publish',
] );
if ( $query->have_posts() ) {
echo '<ul class="mcn-widget-list">';
while ( $query->have_posts() ) {
$query->the_post();
$cats = get_the_terms( get_the_ID(), 'mc_news_category' );
$icon = ( $cats && ! empty( $cats[0]->description ) ) ? $cats[0]->description . ' ' : '📰 ';
printf(
'<li class="mcn-widget-item"><a href="%s">%s%s</a><span class="mcn-widget-date">%s</span></li>',
get_permalink(),
$icon,
get_the_title(),
get_the_date( 'd.m.Y' )
);
}
echo '</ul>';
wp_reset_postdata();
} else {
echo '<p>Noch keine News vorhanden.</p>';
}
echo $args['after_widget'];
}
public function form( $instance ) {
$title = $instance['title'] ?? 'Server News';
$anzahl = $instance['anzahl'] ?? 3;
?>
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>">Titel:</label>
<input class="widefat" type="text" id="<?php echo $this->get_field_id( 'title' ); ?>"
name="<?php echo $this->get_field_name( 'title' ); ?>"
value="<?php echo esc_attr( $title ); ?>">
</p>
<p>
<label for="<?php echo $this->get_field_id( 'anzahl' ); ?>">Anzahl News:</label>
<input class="widefat" type="number" min="1" max="10"
id="<?php echo $this->get_field_id( 'anzahl' ); ?>"
name="<?php echo $this->get_field_name( 'anzahl' ); ?>"
value="<?php echo esc_attr( $anzahl ); ?>">
</p>
<?php
}
public function update( $new, $old ) {
return [
'title' => sanitize_text_field( $new['title'] ),
'anzahl' => intval( $new['anzahl'] ),
];
}
}