Initial commit
This commit is contained in:
735
door-status-voting.php
Normal file
735
door-status-voting.php
Normal file
@@ -0,0 +1,735 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Restaurant Tür-Status
|
||||
* Plugin URI: https://lucas-orth.de
|
||||
* Description: Interaktives Voting-Widget mit animierter Tür - Besucher können abstimmen ob ein Restaurant geöffnet oder geschlossen ist
|
||||
* Version: 1.1.0
|
||||
* Author: Lucas Orth
|
||||
* Author URI: https://lucas-orth.de
|
||||
* License: GPL v2 or later
|
||||
* Text Domain: door-status
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
define('DSV_VERSION', '1.0.0');
|
||||
define('DSV_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||
define('DSV_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||
|
||||
class DoorStatusVoting {
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
public static function get_instance() {
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private function __construct() {
|
||||
// Frontend
|
||||
add_shortcode('door_status', [$this, 'render_shortcode']);
|
||||
add_action('wp_enqueue_scripts', [$this, 'enqueue_frontend_assets']);
|
||||
|
||||
// AJAX Handlers
|
||||
add_action('wp_ajax_dsv_vote', [$this, 'handle_vote']);
|
||||
add_action('wp_ajax_nopriv_dsv_vote', [$this, 'handle_vote']);
|
||||
add_action('wp_ajax_dsv_remove_vote', [$this, 'handle_remove_vote']);
|
||||
add_action('wp_ajax_nopriv_dsv_remove_vote', [$this, 'handle_remove_vote']);
|
||||
add_action('wp_ajax_dsv_get_status', [$this, 'get_status']);
|
||||
add_action('wp_ajax_nopriv_dsv_get_status', [$this, 'get_status']);
|
||||
|
||||
// Admin
|
||||
add_action('admin_menu', [$this, 'add_admin_menu']);
|
||||
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']);
|
||||
add_action('wp_ajax_dsv_save_settings', [$this, 'save_settings']);
|
||||
add_action('wp_ajax_dsv_reset_votes', [$this, 'reset_votes']);
|
||||
add_action('wp_ajax_dsv_reset_votes_by_type', [$this, 'reset_votes_by_type']);
|
||||
add_action('wp_ajax_dsv_update_meta_status', [$this, 'update_meta_status']);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// FRONTEND
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Assets für Frontend laden
|
||||
*/
|
||||
public function enqueue_frontend_assets() {
|
||||
wp_enqueue_style(
|
||||
'dsv-frontend',
|
||||
DSV_PLUGIN_URL . 'assets/css/frontend.css',
|
||||
[],
|
||||
DSV_VERSION
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'dsv-frontend',
|
||||
DSV_PLUGIN_URL . 'assets/js/frontend.js',
|
||||
[],
|
||||
DSV_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script('dsv-frontend', 'dsvConfig', [
|
||||
'ajaxUrl' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('dsv_nonce')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode rendern
|
||||
*/
|
||||
public function render_shortcode($atts) {
|
||||
$atts = shortcode_atts([
|
||||
'post_id' => get_the_ID()
|
||||
], $atts);
|
||||
|
||||
$post_id = intval($atts['post_id']);
|
||||
|
||||
// Prüfen ob für diesen Post deaktiviert
|
||||
$disabled_posts = get_option('dsv_disabled_posts', []);
|
||||
if (in_array($post_id, $disabled_posts)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Votes laden
|
||||
$votes = $this->get_votes($post_id);
|
||||
$total = $votes['open'] + $votes['closed'];
|
||||
$open_percent = $total > 0 ? round(($votes['open'] / $total) * 100) : 50;
|
||||
|
||||
// Status ermitteln
|
||||
if ($votes['open'] > $votes['closed']) {
|
||||
$status = 'open';
|
||||
$status_text = 'GEÖFFNET';
|
||||
$status_icon = '🟢';
|
||||
} elseif ($votes['closed'] > $votes['open']) {
|
||||
$status = 'closed';
|
||||
$status_text = 'GESCHLOSSEN';
|
||||
$status_icon = '🔴';
|
||||
} else {
|
||||
$status = 'tied';
|
||||
$status_text = 'UNKLAR';
|
||||
$status_icon = '🟡';
|
||||
}
|
||||
|
||||
// User Vote aus Cookie prüfen
|
||||
$cookie_name = 'dsv_vote_' . $post_id;
|
||||
$user_vote = isset($_COOKIE[$cookie_name]) ? sanitize_text_field($_COOKIE[$cookie_name]) : null;
|
||||
$has_voted = !empty($user_vote);
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="dsv-widget"
|
||||
data-post-id="<?php echo esc_attr($post_id); ?>"
|
||||
data-status="<?php echo esc_attr($status); ?>"
|
||||
data-has-voted="<?php echo $has_voted ? 'true' : 'false'; ?>"
|
||||
data-user-vote="<?php echo esc_attr($user_vote); ?>">
|
||||
|
||||
<h3 class="dsv-title">Ist das Restaurant noch geöffnet?</h3>
|
||||
|
||||
<div class="dsv-main-row">
|
||||
<!-- Tür Container -->
|
||||
<div class="dsv-door-container">
|
||||
|
||||
<!-- Status Badge -->
|
||||
<div class="dsv-status-badge dsv-status-<?php echo esc_attr($status); ?>">
|
||||
<?php echo $status_icon; ?> <?php echo esc_html($status_text); ?>
|
||||
</div>
|
||||
|
||||
<!-- Türrahmen -->
|
||||
<div class="dsv-door-frame">
|
||||
|
||||
<!-- Licht hinter der Tür -->
|
||||
<div class="dsv-light"></div>
|
||||
|
||||
<!-- Lichtstrahlen -->
|
||||
<div class="dsv-light-rays">
|
||||
<div class="dsv-ray"></div>
|
||||
<div class="dsv-ray"></div>
|
||||
<div class="dsv-ray"></div>
|
||||
<div class="dsv-ray"></div>
|
||||
<div class="dsv-ray"></div>
|
||||
</div>
|
||||
|
||||
<!-- Die Tür -->
|
||||
<div class="dsv-door">
|
||||
<div class="dsv-door-grain"></div>
|
||||
<div class="dsv-door-panel dsv-door-panel-top"></div>
|
||||
<div class="dsv-door-panel dsv-door-panel-bottom"></div>
|
||||
<div class="dsv-door-handle">
|
||||
<div class="dsv-handle-plate"></div>
|
||||
<div class="dsv-handle-lever"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Schatten -->
|
||||
<div class="dsv-shadow"></div>
|
||||
</div>
|
||||
|
||||
<!-- Rechte Seite: Voting -->
|
||||
<div class="dsv-voting-section">
|
||||
<!-- Fortschrittsbalken -->
|
||||
<div class="dsv-progress-container">
|
||||
<div class="dsv-progress-bar">
|
||||
<div class="dsv-progress-open" style="width: <?php echo $open_percent; ?>%">
|
||||
<?php if ($open_percent > 15): ?>
|
||||
<span class="dsv-progress-count"><?php echo $votes['open']; ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="dsv-progress-closed" style="width: <?php echo 100 - $open_percent; ?>%">
|
||||
<?php if ((100 - $open_percent) > 15): ?>
|
||||
<span class="dsv-progress-count"><?php echo $votes['closed']; ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="dsv-progress-divider"></div>
|
||||
</div>
|
||||
<div class="dsv-progress-labels">
|
||||
<span class="dsv-label-open">Geöffnet (<?php echo $open_percent; ?>%)</span>
|
||||
<span class="dsv-label-closed">Geschlossen (<?php echo 100 - $open_percent; ?>%)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Voting Buttons -->
|
||||
<div class="dsv-buttons <?php echo $has_voted ? 'dsv-voted' : ''; ?>">
|
||||
<?php if (!$has_voted): ?>
|
||||
<button type="button" class="dsv-btn dsv-btn-open" data-vote="open">
|
||||
<span class="dsv-btn-icon">✓</span>
|
||||
<span class="dsv-btn-text">Geöffnet</span>
|
||||
</button>
|
||||
<button type="button" class="dsv-btn dsv-btn-closed" data-vote="closed">
|
||||
<span class="dsv-btn-icon">✗</span>
|
||||
<span class="dsv-btn-text">Geschlossen</span>
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<div class="dsv-voted-message dsv-voted-<?php echo esc_attr($user_vote); ?>">
|
||||
<span class="dsv-voted-icon"><?php echo $user_vote === 'open' ? '✓' : '✗'; ?></span>
|
||||
<span class="dsv-voted-text">
|
||||
Du hast für "<?php echo $user_vote === 'open' ? 'Geöffnet' : 'Geschlossen'; ?>" gestimmt
|
||||
</span>
|
||||
<button type="button" class="dsv-remove-vote" title="Stimme zurücknehmen">✕</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Teilnehmer Info -->
|
||||
<p class="dsv-info">
|
||||
<span class="dsv-total"><?php echo $total; ?></span> Besucher haben abgestimmt
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Votes aus Post Meta laden
|
||||
*/
|
||||
private function get_votes($post_id) {
|
||||
$data = get_post_meta($post_id, '_dsv_votes', true);
|
||||
if (!is_array($data)) {
|
||||
return ['open' => 0, 'closed' => 0];
|
||||
}
|
||||
|
||||
$open = $closed = 0;
|
||||
foreach ($data as $vote) {
|
||||
if ($vote === 'open') $open++;
|
||||
if ($vote === 'closed') $closed++;
|
||||
}
|
||||
return ['open' => $open, 'closed' => $closed];
|
||||
}
|
||||
|
||||
/**
|
||||
* User-Key generieren (IP Hash)
|
||||
*/
|
||||
private function get_user_key() {
|
||||
$ip = '';
|
||||
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
|
||||
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
|
||||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
|
||||
} else {
|
||||
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
|
||||
}
|
||||
return md5($ip . wp_salt());
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Vote speichern
|
||||
*/
|
||||
public function handle_vote() {
|
||||
check_ajax_referer('dsv_nonce', 'nonce');
|
||||
|
||||
$post_id = intval($_POST['post_id'] ?? 0);
|
||||
$vote = sanitize_text_field($_POST['vote'] ?? '');
|
||||
|
||||
if (!$post_id || !in_array($vote, ['open', 'closed'])) {
|
||||
wp_send_json_error(['message' => 'Ungültige Anfrage']);
|
||||
}
|
||||
|
||||
// Prüfen ob deaktiviert
|
||||
$disabled_posts = get_option('dsv_disabled_posts', []);
|
||||
if (in_array($post_id, $disabled_posts)) {
|
||||
wp_send_json_error(['message' => 'Voting deaktiviert']);
|
||||
}
|
||||
|
||||
$user_key = $this->get_user_key();
|
||||
$data = get_post_meta($post_id, '_dsv_votes', true);
|
||||
if (!is_array($data)) $data = [];
|
||||
|
||||
// Bereits gevotet? (Server-side Check)
|
||||
if (isset($data[$user_key])) {
|
||||
wp_send_json_error(['message' => 'Bereits abgestimmt']);
|
||||
}
|
||||
|
||||
// Vote speichern
|
||||
$data[$user_key] = $vote;
|
||||
update_post_meta($post_id, '_dsv_votes', $data);
|
||||
|
||||
// Cookie setzen (30 Tage)
|
||||
$cookie_name = 'dsv_vote_' . $post_id;
|
||||
setcookie($cookie_name, $vote, time() + (30 * DAY_IN_SECONDS), COOKIEPATH, COOKIE_DOMAIN);
|
||||
|
||||
// Neue Votes zurückgeben
|
||||
$votes = $this->get_votes($post_id);
|
||||
$total = $votes['open'] + $votes['closed'];
|
||||
$open_percent = $total > 0 ? round(($votes['open'] / $total) * 100) : 50;
|
||||
|
||||
wp_send_json_success([
|
||||
'votes' => $votes,
|
||||
'total' => $total,
|
||||
'openPercent' => $open_percent,
|
||||
'status' => $votes['open'] > $votes['closed'] ? 'open' :
|
||||
($votes['closed'] > $votes['open'] ? 'closed' : 'tied')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Aktuellen Status abrufen
|
||||
*/
|
||||
public function get_status() {
|
||||
$post_id = intval($_GET['post_id'] ?? 0);
|
||||
|
||||
if (!$post_id) {
|
||||
wp_send_json_error(['message' => 'Ungültige Post ID']);
|
||||
}
|
||||
|
||||
$votes = $this->get_votes($post_id);
|
||||
$total = $votes['open'] + $votes['closed'];
|
||||
$open_percent = $total > 0 ? round(($votes['open'] / $total) * 100) : 50;
|
||||
|
||||
wp_send_json_success([
|
||||
'votes' => $votes,
|
||||
'total' => $total,
|
||||
'openPercent' => $open_percent,
|
||||
'status' => $votes['open'] > $votes['closed'] ? 'open' :
|
||||
($votes['closed'] > $votes['open'] ? 'closed' : 'tied')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Vote entfernen
|
||||
*/
|
||||
public function handle_remove_vote() {
|
||||
check_ajax_referer('dsv_nonce', 'nonce');
|
||||
|
||||
$post_id = intval($_POST['post_id'] ?? 0);
|
||||
|
||||
if (!$post_id) {
|
||||
wp_send_json_error(['message' => 'Ungültige Anfrage']);
|
||||
}
|
||||
|
||||
$user_key = $this->get_user_key();
|
||||
$data = get_post_meta($post_id, '_dsv_votes', true);
|
||||
|
||||
if (!is_array($data) || !isset($data[$user_key])) {
|
||||
wp_send_json_error(['message' => 'Kein Vote gefunden']);
|
||||
}
|
||||
|
||||
// Vote entfernen
|
||||
unset($data[$user_key]);
|
||||
update_post_meta($post_id, '_dsv_votes', $data);
|
||||
|
||||
// Cookie löschen
|
||||
$cookie_name = 'dsv_vote_' . $post_id;
|
||||
setcookie($cookie_name, '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN);
|
||||
|
||||
// Neue Votes zurückgeben
|
||||
$votes = $this->get_votes($post_id);
|
||||
$total = $votes['open'] + $votes['closed'];
|
||||
$open_percent = $total > 0 ? round(($votes['open'] / $total) * 100) : 50;
|
||||
|
||||
wp_send_json_success([
|
||||
'votes' => $votes,
|
||||
'total' => $total,
|
||||
'openPercent' => $open_percent,
|
||||
'status' => $votes['open'] > $votes['closed'] ? 'open' :
|
||||
($votes['closed'] > $votes['open'] ? 'closed' : 'tied')
|
||||
]);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// ADMIN
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Admin Menü unter Werkzeuge
|
||||
*/
|
||||
public function add_admin_menu() {
|
||||
add_management_page(
|
||||
'Tür-Status Voting',
|
||||
'Tür-Status',
|
||||
'manage_options',
|
||||
'door-status-settings',
|
||||
[$this, 'render_admin_page']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Assets laden
|
||||
*/
|
||||
public function enqueue_admin_assets($hook) {
|
||||
if ($hook !== 'tools_page_door-status-settings') {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style(
|
||||
'dsv-admin',
|
||||
DSV_PLUGIN_URL . 'assets/css/admin.css',
|
||||
[],
|
||||
DSV_VERSION
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'dsv-admin',
|
||||
DSV_PLUGIN_URL . 'assets/js/admin.js',
|
||||
['jquery'],
|
||||
DSV_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script('dsv-admin', 'dsvAdmin', [
|
||||
'ajaxUrl' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('dsv_admin_nonce')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Seite rendern
|
||||
*/
|
||||
public function render_admin_page() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_die('Keine Berechtigung');
|
||||
}
|
||||
|
||||
$disabled_posts = get_option('dsv_disabled_posts', []);
|
||||
|
||||
// Alle Posts mit Votes holen
|
||||
global $wpdb;
|
||||
$posts_with_votes = $wpdb->get_col(
|
||||
"SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_dsv_votes'"
|
||||
);
|
||||
|
||||
?>
|
||||
<div class="wrap dsv-admin-wrap">
|
||||
<h1>🚪 Tür-Status Voting</h1>
|
||||
|
||||
<div class="dsv-admin-grid">
|
||||
|
||||
<!-- Shortcode Info -->
|
||||
<div class="dsv-admin-card">
|
||||
<h2>Shortcode</h2>
|
||||
<p>Füge das Voting-Widget mit folgendem Shortcode ein:</p>
|
||||
<code class="dsv-shortcode">[door_status]</code>
|
||||
<p class="description">
|
||||
Der Shortcode verwendet automatisch die aktuelle Post-ID.
|
||||
Du kannst ihn in Posts, Seiten oder Page-Builder einfügen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Deaktivierte Posts -->
|
||||
<div class="dsv-admin-card">
|
||||
<h2>Voting deaktivieren</h2>
|
||||
<p>Gib Post-IDs ein, für die das Voting deaktiviert werden soll (kommagetrennt):</p>
|
||||
<form id="dsv-settings-form">
|
||||
<textarea
|
||||
name="disabled_posts"
|
||||
id="dsv-disabled-posts"
|
||||
class="large-text"
|
||||
rows="3"
|
||||
placeholder="z.B. 123, 456, 789"
|
||||
><?php echo esc_textarea(implode(', ', $disabled_posts)); ?></textarea>
|
||||
<p class="description">
|
||||
Der Shortcode wird auf diesen Seiten nichts ausgeben.
|
||||
</p>
|
||||
<p>
|
||||
<button type="submit" class="button button-primary">
|
||||
Einstellungen speichern
|
||||
</button>
|
||||
<span class="dsv-save-status"></span>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Statistiken -->
|
||||
<div class="dsv-admin-card dsv-admin-card-full">
|
||||
<h2>Voting Übersicht</h2>
|
||||
|
||||
<?php if (empty($posts_with_votes)): ?>
|
||||
<p class="dsv-no-data">Noch keine Votes vorhanden.</p>
|
||||
<?php else: ?>
|
||||
<p>
|
||||
<button type="button" id="dsv-filter-mismatch" class="button">
|
||||
Nur Abweichungen anzeigen
|
||||
</button>
|
||||
</p>
|
||||
<table class="wp-list-table widefat fixed striped" id="dsv-votes-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Post</th>
|
||||
<th>Meta-Status</th>
|
||||
<th>Voting-Status</th>
|
||||
<th>Geöffnet</th>
|
||||
<th>Geschlossen</th>
|
||||
<th>Gesamt</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($posts_with_votes as $pid):
|
||||
$post = get_post($pid);
|
||||
if (!$post) continue;
|
||||
|
||||
$votes = $this->get_votes($pid);
|
||||
$total = $votes['open'] + $votes['closed'];
|
||||
$is_disabled = in_array($pid, $disabled_posts);
|
||||
|
||||
if ($votes['open'] > $votes['closed']) {
|
||||
$status_badge = '<span class="dsv-badge dsv-badge-open">Geöffnet</span>';
|
||||
} elseif ($votes['closed'] > $votes['open']) {
|
||||
$status_badge = '<span class="dsv-badge dsv-badge-closed">Geschlossen</span>';
|
||||
} else {
|
||||
$status_badge = '<span class="dsv-badge dsv-badge-tied">Unklar</span>';
|
||||
}
|
||||
|
||||
// JetEngine Meta-Feld "status" auslesen
|
||||
$meta_status = get_post_meta($pid, 'status', true);
|
||||
$meta_status_lower = mb_strtolower(trim($meta_status));
|
||||
if (in_array($meta_status_lower, ['geöffnet', 'geoeffnet', 'open', 'offen'])) {
|
||||
$meta_badge_class = 'dsv-badge-open';
|
||||
$meta_voting_match = ($votes['open'] > $votes['closed']);
|
||||
} elseif (in_array($meta_status_lower, ['geschlossen', 'closed', 'zu'])) {
|
||||
$meta_badge_class = 'dsv-badge-closed';
|
||||
$meta_voting_match = ($votes['closed'] > $votes['open']);
|
||||
} elseif (in_array($meta_status_lower, ['neuer betreiber'])) {
|
||||
$meta_badge_class = 'dsv-badge-tied';
|
||||
$meta_voting_match = false;
|
||||
} elseif (!empty($meta_status)) {
|
||||
$meta_badge_class = 'dsv-badge-tied';
|
||||
$meta_voting_match = false;
|
||||
} else {
|
||||
$meta_badge_class = '';
|
||||
$meta_voting_match = true; // kein Meta = kein Abweichung
|
||||
}
|
||||
|
||||
if (!empty($meta_status)) {
|
||||
$meta_status_display = '<span class="dsv-badge ' . $meta_badge_class . '">' . esc_html($meta_status) . '</span>';
|
||||
} else {
|
||||
$meta_status_display = '<span class="dsv-meta-empty">—</span>';
|
||||
}
|
||||
|
||||
$row_mismatch = !$meta_voting_match;
|
||||
?>
|
||||
<tr data-post-id="<?php echo esc_attr($pid); ?>"<?php if ($row_mismatch): ?> class="dsv-mismatch"<?php endif; ?>>
|
||||
<td>
|
||||
<strong><a href="<?php echo get_edit_post_link($pid); ?>" target="_blank"><?php echo esc_html($post->post_title); ?></a></strong>
|
||||
<br>
|
||||
<small>ID: <?php echo $pid; ?></small>
|
||||
<?php if ($is_disabled): ?>
|
||||
<br><em class="dsv-disabled-label">Voting deaktiviert</em>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="dsv-meta-status-cell">
|
||||
<?php echo $meta_status_display; ?>
|
||||
<div class="dsv-meta-buttons">
|
||||
<button type="button" class="button button-small dsv-meta-set-btn<?php echo ($meta_status_lower === 'geöffnet') ? ' active' : ''; ?>" data-post-id="<?php echo esc_attr($pid); ?>" data-status="geöffnet" title="Geöffnet">🟢</button>
|
||||
<button type="button" class="button button-small dsv-meta-set-btn<?php echo ($meta_status_lower === 'geschlossen') ? ' active' : ''; ?>" data-post-id="<?php echo esc_attr($pid); ?>" data-status="geschlossen" title="Geschlossen">🔴</button>
|
||||
</div>
|
||||
</td>
|
||||
<td><?php echo $status_badge; ?></td>
|
||||
<td class="dsv-count-open"><?php echo $votes['open']; ?></td>
|
||||
<td class="dsv-count-closed"><?php echo $votes['closed']; ?></td>
|
||||
<td class="dsv-count-total"><?php echo $total; ?></td>
|
||||
<td class="dsv-actions-cell">
|
||||
<div class="dsv-action-buttons">
|
||||
<button type="button"
|
||||
class="button button-small dsv-reset-type-btn"
|
||||
data-post-id="<?php echo esc_attr($pid); ?>"
|
||||
data-type="open"
|
||||
title="Alle 'Geöffnet' Stimmen löschen">
|
||||
🟢 Löschen
|
||||
</button>
|
||||
<button type="button"
|
||||
class="button button-small dsv-reset-type-btn"
|
||||
data-post-id="<?php echo esc_attr($pid); ?>"
|
||||
data-type="closed"
|
||||
title="Alle 'Geschlossen' Stimmen löschen">
|
||||
🔴 Löschen
|
||||
</button>
|
||||
<button type="button"
|
||||
class="button button-small dsv-reset-btn"
|
||||
data-post-id="<?php echo esc_attr($pid); ?>"
|
||||
title="Alle Stimmen löschen">
|
||||
Alle löschen
|
||||
</button>
|
||||
<a href="<?php echo get_permalink($pid); ?>"
|
||||
target="_blank"
|
||||
class="button button-small">
|
||||
Ansehen
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Einstellungen speichern
|
||||
*/
|
||||
public function save_settings() {
|
||||
check_ajax_referer('dsv_admin_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error(['message' => 'Keine Berechtigung']);
|
||||
}
|
||||
|
||||
$disabled_posts_raw = sanitize_text_field($_POST['disabled_posts'] ?? '');
|
||||
$disabled_posts = [];
|
||||
|
||||
if (!empty($disabled_posts_raw)) {
|
||||
$ids = explode(',', $disabled_posts_raw);
|
||||
foreach ($ids as $id) {
|
||||
$id = intval(trim($id));
|
||||
if ($id > 0) {
|
||||
$disabled_posts[] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_option('dsv_disabled_posts', $disabled_posts);
|
||||
|
||||
wp_send_json_success(['message' => 'Gespeichert']);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Votes zurücksetzen
|
||||
*/
|
||||
public function reset_votes() {
|
||||
check_ajax_referer('dsv_admin_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error(['message' => 'Keine Berechtigung']);
|
||||
}
|
||||
|
||||
$post_id = intval($_POST['post_id'] ?? 0);
|
||||
|
||||
if (!$post_id) {
|
||||
wp_send_json_error(['message' => 'Ungültige Post ID']);
|
||||
}
|
||||
|
||||
delete_post_meta($post_id, '_dsv_votes');
|
||||
|
||||
wp_send_json_success(['message' => 'Votes zurückgesetzt']);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Votes nach Typ zurücksetzen (nur open oder nur closed)
|
||||
*/
|
||||
public function reset_votes_by_type() {
|
||||
check_ajax_referer('dsv_admin_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error(['message' => 'Keine Berechtigung']);
|
||||
}
|
||||
|
||||
$post_id = intval($_POST['post_id'] ?? 0);
|
||||
$type = sanitize_text_field($_POST['type'] ?? '');
|
||||
|
||||
if (!$post_id || !in_array($type, ['open', 'closed'])) {
|
||||
wp_send_json_error(['message' => 'Ungültige Parameter']);
|
||||
}
|
||||
|
||||
$data = get_post_meta($post_id, '_dsv_votes', true);
|
||||
if (!is_array($data)) {
|
||||
wp_send_json_error(['message' => 'Keine Votes vorhanden']);
|
||||
}
|
||||
|
||||
// Nur Votes des angegebenen Typs entfernen
|
||||
$removed = 0;
|
||||
foreach ($data as $key => $vote) {
|
||||
if ($vote === $type) {
|
||||
unset($data[$key]);
|
||||
$removed++;
|
||||
}
|
||||
}
|
||||
|
||||
update_post_meta($post_id, '_dsv_votes', $data);
|
||||
|
||||
// Neue Zahlen berechnen
|
||||
$votes = $this->get_votes($post_id);
|
||||
|
||||
wp_send_json_success([
|
||||
'message' => $removed . ' Stimmen gelöscht',
|
||||
'votes' => $votes,
|
||||
'removed' => $removed
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: Meta-Status ändern
|
||||
*/
|
||||
public function update_meta_status() {
|
||||
check_ajax_referer('dsv_admin_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json_error(['message' => 'Keine Berechtigung']);
|
||||
}
|
||||
|
||||
$post_id = intval($_POST['post_id'] ?? 0);
|
||||
$status = sanitize_text_field($_POST['status'] ?? '');
|
||||
|
||||
if (!$post_id || !in_array($status, ['geöffnet', 'geschlossen'])) {
|
||||
wp_send_json_error(['message' => 'Ungültige Parameter']);
|
||||
}
|
||||
|
||||
update_post_meta($post_id, 'status', $status);
|
||||
|
||||
wp_send_json_success(['message' => 'Status aktualisiert', 'status' => $status]);
|
||||
}
|
||||
}
|
||||
|
||||
// Plugin initialisieren
|
||||
DoorStatusVoting::get_instance();
|
||||
|
||||
// Aktivierungs-Hook
|
||||
register_activation_hook(__FILE__, function() {
|
||||
add_option('dsv_disabled_posts', []);
|
||||
});
|
||||
|
||||
// Deaktivierungs-Hook
|
||||
register_deactivation_hook(__FILE__, function() {
|
||||
// Optional: Daten behalten oder löschen
|
||||
});
|
||||
Reference in New Issue
Block a user