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(); ?>

Ist das Restaurant noch geöffnet?

15): ?>
15): ?>
Geöffnet (%) Geschlossen (%)
Du hast für "" gestimmt

Besucher haben abgestimmt

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'" ); ?>

🚪 Tür-Status Voting

Shortcode

Füge das Voting-Widget mit folgendem Shortcode ein:

[door_status]

Der Shortcode verwendet automatisch die aktuelle Post-ID. Du kannst ihn in Posts, Seiten oder Page-Builder einfügen.

Voting deaktivieren

Gib Post-IDs ein, für die das Voting deaktiviert werden soll (kommagetrennt):

Der Shortcode wird auf diesen Seiten nichts ausgeben.

Voting Übersicht

Noch keine Votes vorhanden.

get_votes($pid); $total = $votes['open'] + $votes['closed']; $is_disabled = in_array($pid, $disabled_posts); if ($votes['open'] > $votes['closed']) { $status_badge = 'Geöffnet'; } elseif ($votes['closed'] > $votes['open']) { $status_badge = 'Geschlossen'; } else { $status_badge = 'Unklar'; } // 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 = '' . esc_html($meta_status) . ''; } else { $meta_status_display = ''; } $row_mismatch = !$meta_voting_match; ?> class="dsv-mismatch">
Post Meta-Status Voting-Status Geöffnet Geschlossen Gesamt Aktionen
post_title); ?>
ID:
Voting deaktiviert
Ansehen
'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 });