mc-player-history.php aktualisiert
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
/*
|
||||
Plugin Name: MC Player History
|
||||
Description: Spielerverlauf deines Minecraft Servers.
|
||||
Version: 1.1.0
|
||||
Author: Dein Name
|
||||
Version: 1.1.1
|
||||
Author: M_Viper
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
@@ -119,10 +119,33 @@ function mcph_sync_from_statusapi() {
|
||||
foreach ( $players as $p ) {
|
||||
$name = isset( $p->name ) ? sanitize_text_field( $p->name ) : '';
|
||||
$prefix = isset( $p->prefix ) ? sanitize_text_field( $p->prefix ) : '';
|
||||
// UUID aus API übernehmen, falls vorhanden, sonst legacy-Hash
|
||||
if ( isset( $p->uuid ) && !empty( $p->uuid ) ) {
|
||||
$uuid = sanitize_text_field( $p->uuid );
|
||||
} else {
|
||||
$uuid = 'legacy-' . md5( strtolower( trim( $name ) ) );
|
||||
}
|
||||
if ( empty( $name ) ) continue;
|
||||
|
||||
// Prüfe ob Spieler bereits existiert (nach UUID ODER Username)
|
||||
$exists = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $table_name WHERE uuid = %s", $uuid ) );
|
||||
|
||||
// Falls nicht per UUID gefunden, prüfe nach Username (für Migration alter Einträge)
|
||||
if ( ! $exists ) {
|
||||
$old_entry = $wpdb->get_row( $wpdb->prepare( "SELECT id, uuid FROM $table_name WHERE username = %s", $name ) );
|
||||
if ( $old_entry ) {
|
||||
// Alter Eintrag gefunden - UUID aktualisieren statt neuen Eintrag
|
||||
$wpdb->update(
|
||||
$table_name,
|
||||
array( 'uuid' => $uuid, 'prefix' => $prefix, 'last_seen' => current_time( 'mysql' ), 'is_online' => 1 ),
|
||||
array( 'id' => $old_entry->id ),
|
||||
array( '%s', '%s', '%s', '%d' ),
|
||||
array( '%d' )
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$now = current_time( 'mysql' );
|
||||
|
||||
if ( $exists ) {
|
||||
@@ -181,7 +204,12 @@ function mcph_generate_player_html( $limit = 500, $only_online = false, $is_ajax
|
||||
$has_live_data = true;
|
||||
foreach ( $api_response as $p ) {
|
||||
if ( isset( $p->name ) ) {
|
||||
// UUID aus API übernehmen, falls vorhanden, sonst legacy-Hash
|
||||
if ( isset( $p->uuid ) && !empty( $p->uuid ) ) {
|
||||
$uuid = sanitize_text_field( $p->uuid );
|
||||
} else {
|
||||
$uuid = 'legacy-' . md5( strtolower( trim( $p->name ) ) );
|
||||
}
|
||||
$live_online_uuids[ $uuid ] = true;
|
||||
}
|
||||
}
|
||||
@@ -218,7 +246,18 @@ function mcph_generate_player_html( $limit = 500, $only_online = false, $is_ajax
|
||||
|
||||
$username = esc_html( $row->username );
|
||||
$prefix = mcph_parse_minecraft_colors( $row->prefix );
|
||||
$avatar = 'https://minotar.net/avatar/' . $username . '/80';
|
||||
|
||||
// Avatar-Logik: Moderne 3D-Köpfe (alle in gleiche Richtung)
|
||||
$avatar = '';
|
||||
if ( strpos( $username, '.' ) !== false || ( isset($row->uuid) && strpos($row->uuid, 'xuid') === 0 ) ) {
|
||||
// Bedrock: mc-heads.net mit 3D Head
|
||||
$avatar = isset($row->uuid) && !empty($row->uuid)
|
||||
? 'https://mc-heads.net/head/' . esc_attr($row->uuid) . '/100'
|
||||
: 'https://mc-heads.net/head/' . $username . '/100';
|
||||
} else {
|
||||
// Java: mc-heads.net mit 3D Head (gleiche Richtung wie Bedrock)
|
||||
$avatar = 'https://mc-heads.net/head/' . $username . '/100';
|
||||
}
|
||||
|
||||
$anim_style = '';
|
||||
if ( ! $is_ajax ) {
|
||||
@@ -235,7 +274,7 @@ function mcph_generate_player_html( $limit = 500, $only_online = false, $is_ajax
|
||||
|
||||
// STRUKTUR: Bild -> Prefix -> Name -> Spacer -> Status
|
||||
echo '<div class="mc-player-card" style="' . $anim_style . '">';
|
||||
echo '<img src="' . $avatar . '" class="mc-avatar" alt="' . $username . '">';
|
||||
echo '<img src="' . $avatar . '" class="mc-avatar" alt="' . $username . '" loading="lazy">';
|
||||
|
||||
echo '<div class="mc-info-stack">';
|
||||
|
||||
@@ -275,6 +314,33 @@ function mcph_settings_init() {
|
||||
register_setting( 'mcph_plugin_options', 'mcph_statusapi_url' );
|
||||
}
|
||||
function mcph_options_page() {
|
||||
// Duplikate bereinigen
|
||||
if ( isset( $_POST['mcph_cleanup_duplicates'] ) && check_admin_referer( 'mcph_cleanup_action' ) ) {
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . 'mc_players';
|
||||
|
||||
// Finde Duplikate (gleicher Username, verschiedene UUIDs)
|
||||
$duplicates = $wpdb->get_results(
|
||||
"SELECT username, COUNT(*) as count, GROUP_CONCAT(id ORDER BY last_seen DESC) as ids
|
||||
FROM $table_name
|
||||
GROUP BY username
|
||||
HAVING count > 1"
|
||||
);
|
||||
|
||||
$cleaned = 0;
|
||||
foreach ( $duplicates as $dup ) {
|
||||
$ids = explode( ',', $dup->ids );
|
||||
// Behalte den neuesten (ersten), lösche die anderen
|
||||
array_shift( $ids );
|
||||
foreach ( $ids as $id ) {
|
||||
$wpdb->delete( $table_name, array( 'id' => $id ), array( '%d' ) );
|
||||
$cleaned++;
|
||||
}
|
||||
}
|
||||
|
||||
echo '<div class="notice notice-success"><p>' . $cleaned . ' Duplikate wurden entfernt.</p></div>';
|
||||
}
|
||||
|
||||
if ( isset( $_POST['mcph_manual_sync'] ) && check_admin_referer( 'mcph_manual_sync_action' ) ) {
|
||||
mcph_sync_from_statusapi();
|
||||
delete_transient( 'mcph_api_cache_data' );
|
||||
@@ -296,6 +362,14 @@ function mcph_options_page() {
|
||||
</table>
|
||||
<?php submit_button(); ?>
|
||||
</form>
|
||||
|
||||
<h2>Duplikate bereinigen</h2>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'mcph_cleanup_action' ); ?>
|
||||
<p class="description">Entfernt doppelte Spieler-Einträge aus der Datenbank.</p>
|
||||
<input type="submit" name="mcph_cleanup_duplicates" class="button button-secondary" value="Duplikate jetzt entfernen" />
|
||||
</form>
|
||||
|
||||
<h2>Manueller Sync</h2>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'mcph_manual_sync_action' ); ?>
|
||||
@@ -379,34 +453,41 @@ function mcph_shortcode( $atts ) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px; /* Weniger Abstand dazwischen */
|
||||
gap: 8px;
|
||||
padding: 20px 10px;
|
||||
background: #fff;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
background: linear-gradient(145deg, #ffffff 0%, #f8f9fa 100%);
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
cursor: default;
|
||||
position: relative; /* Fallback */
|
||||
position: relative;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.mc-player-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
|
||||
border-color: #ddd;
|
||||
transform: translateY(-8px) scale(1.02);
|
||||
box-shadow: 0 12px 24px rgba(0,0,0,0.15);
|
||||
border-color: #667eea;
|
||||
background: linear-gradient(145deg, #ffffff 0%, #f0f2ff 100%);
|
||||
}
|
||||
|
||||
.mc-avatar {
|
||||
border-radius: 4px;
|
||||
border: 3px solid #ddd;
|
||||
background: #fff;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
transition: border-color 0.3s;
|
||||
border-radius: 8px;
|
||||
border: 3px solid #e0e0e0;
|
||||
background: transparent;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
object-fit: contain;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mc-player-card:hover .mc-avatar {
|
||||
border-color: #bbb;
|
||||
border-color: #667eea;
|
||||
transform: scale(1.15) rotateY(10deg);
|
||||
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
/* INFOS BEREICH */
|
||||
@@ -415,10 +496,10 @@ function mcph_shortcode( $atts ) {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
flex-grow: 1; /* Füllt den Rest der Karte */
|
||||
position: relative; /* Referenz für absoluten Status */
|
||||
padding-bottom: 35px; /* Platz für Status unten */
|
||||
justify-content: flex-start; /* Oben ausrichten */
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
padding-bottom: 35px;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
/* 1. PREFIX */
|
||||
@@ -429,22 +510,24 @@ function mcph_shortcode( $atts ) {
|
||||
text-align: center;
|
||||
margin-bottom: 4px;
|
||||
line-height: 1.2;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
/* 2. NAME */
|
||||
.mc-name {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
color: #333;
|
||||
color: #2d3748;
|
||||
word-break: break-word;
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
/* 3. SPACER */
|
||||
.mc-spacer {
|
||||
flex-grow: 1; /* Nimmt ALLEN leeren Platz zwischen Name und Status ein */
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
/* 4. STATUS (UNTEN) */
|
||||
@@ -460,20 +543,42 @@ function mcph_shortcode( $atts ) {
|
||||
|
||||
.mc-status {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
padding: 5px 14px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8em;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.mc-online {
|
||||
background: linear-gradient(135deg, #d4f8e8 0%, #b8f2d9 100%);
|
||||
color: #0a7340;
|
||||
border: 1px solid #81e6b8;
|
||||
box-shadow: 0 2px 4px rgba(10, 115, 64, 0.1);
|
||||
}
|
||||
|
||||
.mc-offline {
|
||||
background: linear-gradient(135deg, #fff5f5 0%, #ffe5e5 100%);
|
||||
color: #c53030;
|
||||
border: 1px solid #fbb6b6;
|
||||
box-shadow: 0 2px 4px rgba(197, 48, 48, 0.1);
|
||||
}
|
||||
|
||||
.mc-player-card:hover .mc-status {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
.mc-online { background-color: #e6fffa; color: #28a745; border: 1px solid #b2f5ea; }
|
||||
.mc-offline { background-color: #fff5f5; color: #e53e3e; border: 1px solid #feb2b2; }
|
||||
|
||||
.mc-update-time {
|
||||
font-size: 0.8em;
|
||||
color: #999;
|
||||
font-size: 0.85em;
|
||||
color: #718096;
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
margin-top: 20px;
|
||||
font-style: italic;
|
||||
padding: 8px;
|
||||
background: rgba(102, 126, 234, 0.05);
|
||||
border-radius: 6px;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
@@ -481,10 +586,20 @@ function mcph_shortcode( $atts ) {
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.mc-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
|
||||
.mc-avatar { width: 50px; height: 50px; }
|
||||
.mc-name { font-size: 1em; }
|
||||
.mc-player-card { padding: 10px 5px; }
|
||||
.mc-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
.mc-avatar {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
||||
.mc-name {
|
||||
font-size: 1em;
|
||||
}
|
||||
.mc-player-card {
|
||||
padding: 15px 8px;
|
||||
}
|
||||
}
|
||||
</style>';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user