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(); ?>
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'" ); ?>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.
Gib Post-IDs ein, für die das Voting deaktiviert werden soll (kommagetrennt):
Noch keine Votes vorhanden.
| Post | Meta-Status | Voting-Status | Geöffnet | Geschlossen | Gesamt | Aktionen |
|---|---|---|---|---|---|---|
|
post_title); ?>
ID: Voting deaktiviert |