Wenn Sie jemals eine leere Seite gesehen haben Après Nachdem Sie „einen kleinen Ausschnitt aus dem Internet“ eingefügt haben, kennen Sie das eigentliche Thema: Best Practices WordPress Sie sind keine Theorie, sondern ein Sicherheitsnetz.

Das Problem / Der Bedarf

Bei WordPress 6.9.4 (April 2026) rührt der Großteil der von mir behobenen „WordPress-Probleme“ nicht vom Kern der Software her, sondern von zu schnell hinzugefügtem Code: ein Echo im falschen Haken, ein enqueue Schlecht konditionierte Dateien, eine unnötige SQL-Abfrage, ein Formular ohne Nonce oder ein Snippet-Plugin, das geladen wird, bevor WordPress bereit ist.

Das Bedürfnis ist einfach: eine zuverlässige und wiederverwendbare Codebasis zu haben, um „Blogger“-Funktionen (CTA, Einfügungen, Formular, Assets) hinzuzufügen, ohne die Website zu beschädigen, sie zu verlangsamen oder eine Sicherheitslücke zu öffnen.

Am Ende werden Sie wissen, wie Sie ein Mini-„mu-Plugin“ (oder ein klassisches Plugin) einrichten, das bewährte Vorgehensweisen veranschaulicht: bedingtes Laden von Skripten, sicherer Shortcode, geschützter REST-Endpunkt, sauber gespeicherte Optionen, saubere Protokolle und Sicherheitsvorkehrungen (Capabilities, Nonce, Bereinigung/Escaping).

Kurze Zusammenfassung

  • Wir programmieren ein Mini-Plugin (kompatibel mit WordPress 6.9.4+ / PHP 8.1+) fügt einen CTA-Einschub über Shortcode und Builder-Kompatibilitätsblock hinzu.
  • Wir laden CSS/JS korrekt. mit wp_enqueue_scriptsVersionierung und Bedingungen (Vermeidung des Ladens überall).
  • Wir fügen einen REST-Endpunkt hinzu. CTA-Klicks werden mit Berechtigungen und Validierung erfasst.
  • Wir speichern Einstellungen über die API-Einstellungen (Option) und wir maskieren/bereinigen korrekt.
  • Wir stellen Ihnen eine Testcheckliste zur Verfügung. + eine Diagnosetabelle + die häufigsten Fehlerquellen.

Wann sollte diese Lösung verwendet werden?

  • Sie möchten eine einfache „Business“-Funktion (CTA, Banner, leichtes Formular, minimales Tracking) hinzufügen, ohne ein umfangreiches Plugin installieren zu müssen.
  • Sie betreiben mehrere Websites und benötigen portablen, versionierbaren (Git) und einfach zu aktivierenden/deaktivierenden Code.
  • Wenn Sie Divi 5, Elementor oder Avada verwenden: Sie benötigen ein stabiles Rendering über Shortcode (universell) und ein Asset-Laden, das nicht das gesamte Frontend beeinträchtigt.
  • Sie möchten vermeiden, dass Textfragmente über den gesamten Text verstreut sind. functions.php (Ich habe schon oft erlebt, dass Webseiten deswegen nicht mehr zu verwalten sind).

Wann diese Lösung NICHT verwendet werden sollte

  • Sie benötigen ein wirklich umfassendes Analysesystem: Nutzen Sie ein spezialisiertes Tool oder eine DSGVO-konforme Lösung mit Einwilligungsmanagement. Unser REST-Endpunkt ist bewusst minimalistisch gehalten.
  • Wenn Sie ein öffentlich vertriebenes Produkt entwickeln, sollten Sie eine vollständige Architektur wählen (Klassen, Autoloading, Tests, CI, Internationalisierung). Hier streben wir eine professionelle, aber kompakte Grundlage an.
  • Auf der Suche nach einem setzen Bei komplexen Seiten: Formatieren Sie die Seiten im Builder und verwenden Sie das Plugin für die Logik (Daten, Sicherheit, Endpunkte, Optionen).
  • Sie haben keine Kontrolle über den Code (Client-Site gesperrt): Verwenden Sie ein bestehendes, gut gewartetes Plugin, anstatt Code über ein Plugin mit zufälligen Code-Snippets einzufügen.

Voraussetzungen / vor Beginn

  • WordPress : 6.9.4 oder höher.
  • PHP Mindestens Version 8.1 (8.2/8.3 empfohlen, falls Ihr Hosting-Anbieter dies unterstützt).
  • Sauvegarde : Dateien + Datenbank vor jeglicher Änderung (und nicht „später“).
  • Test Umgebung Idealerweise sollte eine Staging-Umgebung verwendet werden. Vermeiden Sie Tests in einer Produktionsumgebung, insbesondere bei der Verwendung von Init-Hooks.
  • Nützliche Hilfsmittel :
    • WP-CLI zum schnellen Überprüfen des Status (wp core version, wp plugin list).
    • Ein Protokollierungs-Plugin (oder WP_DEBUG_LOG) um PHP-Fehler abzufangen, ohne die Anzeige zu beeinträchtigen.
  • Sicherheit Alles, was Eingaben akzeptiert (REST, Formular, Abfragezeichenfolge), muss validiert, bereinigt und durch Berechtigungen geschützt werden.

Offizielle Quellen, die man griffbereit haben sollte:

Der naive Ansatz (und warum man ihn vermeiden sollte)

Das Muster, das ich am häufigsten sehe: Code einfügen in functions.phpEinen Shortcode erstellen, der nicht maskiertes HTML ausgibt, und JS auf allen Seiten laden, „weil es funktioniert“.

Naives Beispiel (sollte vermieden werden)

<?php
// ❌ À NE PAS FAIRE : code non conditionné, sorties non échappées, pas de versioning, pas de sécurité.

add_action('wp_enqueue_scripts', function () {
    wp_enqueue_script('cta', get_stylesheet_directory_uri() . '/cta.js', array('jquery'));
});

add_shortcode('cta', function ($atts) {
    $url  = $atts['url'];   // ❌ non validé
    $text = $atts['text'];  // ❌ non échappé
    return '<a class="cta" href="' . $url . '">' . $text . '</a>';
});

Warum stellt das ein Problem dar?

  • Sicherheit : Der Shortcode akzeptiert nicht validierte Attribute → XSS möglich, wenn eine Rolle Inhalte veröffentlichen kann (oder wenn Inhalte importiert werden).
  • Leistung : JavaScript wird überall geladen, sogar dort, wo der CTA nicht existiert.
  • Wartung : functions.php Das hängt vom Design ab. Sie ändern das Design (oder Sie wechseln zu jour ohne ein kindgerechtes Thema) und man verliert alles.
  • Debugging Eine einfach vergessene Klammer → weißer Bildschirm. Und im Produktivbetrieb, ohne Protokolle, tappt man im Dunkeln.

Die richtige Herangehensweise – eine Schritt-für-Schritt-Anleitung

Schritt 1 – Wählen Sie, wo der Code platziert werden soll (Plugin oder MU-Plugin).

Für eine Blogseite empfehle ich oft eine Mu-Plugin Wenn die Funktionalität unabhängig vom Theme aktiv bleiben soll, dann genügt ein Standard-Plugin vollkommen.

  • Option A (empfohlen) : mu-plugin: wp-content/mu-plugins/bpcab-cta/bpcab-cta.php
  • Option B : klassisches Plugin: wp-content/plugins/bpcab-cta/bpcab-cta.php

Wenn Sie mu-plugin auswählen, erstellen Sie den Ordner mu-plugins falls es nicht existiert.

Schritt 2 – Plugin deklarieren, direkten Zugriff blockieren, Versionsproblem beheben

Das Ziel: die Ausführung außerhalb von WordPress zu vermeiden und eine konstante Version für den Asset-Cache zu haben.

Schritt 3 — Einen sicheren Shortcode hinzufügen (bereinigen + maskieren)

Wir werden erschaffen [bpcab_cta]Es wird ein CTA-Link mit einer Kennung generiert. Diese Kennung wird für das REST-Tracking verwendet.

Schritt 4 – CSS/JS nur laden, falls erforderlich

Zwei zuverlässige Strategien:

  • Einfacher : Auf allen Seiten laden (OK, wenn sehr ressourcenschonend, aber selten optimal).
  • Sauber : Nur laden, wenn der Shortcode im Inhalt vorhanden ist oder wenn ein Builder den Shortcode gerendert hat.

Meiner Erfahrung nach deckt die Erkennung von Shortcodes im Inhalt 80 % der Fälle ab. Für Divi/Elementor/Avada fügen wir ein zusätzliches Sicherheitsnetz hinzu: Wird das Skript explizit über einen Hook angefordert, laden wir es.

Schritt 5 – Erstellen Sie einen geschützten REST-Endpunkt

Wir decken auf /wp-json/bpcab/v1/cta-click wer akzeptiert cta_idWir überprüfen das Format, begrenzen Missbrauchsmöglichkeiten (leichte Drosselung) und speichern einen Zähler als Option (einfach) oder in den Metadaten (Variante).

Schritt 6 – Eine minimalistische Einstellungsseite hinzufügen (optional)

Wir fügen eine Einstellung hinzu: Aktivieren/Deaktivieren des REST-Trackings. Dadurch entfällt das Auskommentieren von Code in der Produktionsumgebung.

Vollständiger Code

Kopieren Sie diese Datei unverändert. Sie ist bewusst monolithisch gestaltet, um die Lesbarkeit zu gewährleisten. Für ein größeres Projekt würde ich sie in Klassen aufteilen.

<?php
/**
 * Plugin Name: BPCAB CTA (bonnes pratiques)
 * Description: Ajoute un shortcode CTA, charge les assets proprement, et propose un endpoint REST sécurisé pour compter les clics.
 * Version: 1.0.0
 * Requires at least: 6.9
 * Requires PHP: 8.1
 * Author: Votre équipe
 *
 * Ce plugin est conçu pour WordPress 6.9.4+ (avril 2026).
 */

declare(strict_types=1);

if (!defined('ABSPATH')) {
	exit; // Empêche l'accès direct au fichier.
}

define('BPCAB_CTA_VERSION', '1.0.0');
define('BPCAB_CTA_SLUG', 'bpcab-cta');
define('BPCAB_CTA_OPT', 'bpcab_cta_options');

/**
 * Retourne les options du plugin avec des valeurs par défaut.
 */
function bpcab_cta_get_options(): array {
	$defaults = array(
		'enable_tracking' => true,
	);

	$opts = get_option(BPCAB_CTA_OPT, array());
	if (!is_array($opts)) {
		$opts = array();
	}

	// Fusion simple, sans surprises.
	return array_merge($defaults, $opts);
}

/**
 * Enregistre le shortcode [bpcab_cta].
 */
function bpcab_cta_register_shortcode(): void {
	add_shortcode('bpcab_cta', 'bpcab_cta_shortcode_render');
}
add_action('init', 'bpcab_cta_register_shortcode');

/**
 * Rend le shortcode.
 *
 * Exemples :
 * [bpcab_cta text="Télécharger le guide" url="https://exemple.com/guide" id="guide-2026" rel="nofollow"]
 *
 * Sécurité :
 * - Validation URL
 * - Escaping HTML
 */
function bpcab_cta_shortcode_render($atts = array(), $content = null, $tag = ''): string {
	$atts = shortcode_atts(
		array(
			'text' => 'En savoir plus',
			'url'  => '',
			'id'   => '',
			'rel'  => 'noopener',
			'target' => '_blank',
			'class' => '',
		),
		(array) $atts,
		'bpcab_cta'
	);

	$text = sanitize_text_field((string) $atts['text']);
	$url  = esc_url_raw((string) $atts['url']);

	// Un identifiant simple (pour tracking). Si absent, on en génère un stable basé sur l'URL.
	$id = sanitize_key((string) $atts['id']);
	if ($id === '' && $url !== '') {
		$id = 'cta-' . substr(md5($url), 0, 10);
	}

	$rel = sanitize_text_field((string) $atts['rel']);
	$target = sanitize_text_field((string) $atts['target']);

	$extra_class = sanitize_html_class((string) $atts['class']);
	$classes = trim('bpcab-cta ' . $extra_class);

	// Si pas d'URL valide, on ne rend rien (évite un lien vide).
	if ($url === '') {
		return '';
	}

	// Marqueur pour permettre le chargement conditionnel des assets.
	$GLOBALS['bpcab_cta_has_cta'] = true;

	// Data attribute pour le JS.
	$data_id_attr = $id !== '' ? ' data-cta-id="' . esc_attr($id) . '"' : '';

	return '<a class="' . esc_attr($classes) . '" href="' . esc_url($url) . '" rel="' . esc_attr($rel) . '" target="' . esc_attr($target) . '"' . $data_id_attr . '>'
		. esc_html($text)
		. '</a>';
}

/**
 * Enqueue des assets, si nécessaire.
 *
 * Notes :
 * - On évite de charger partout.
 * - On ajoute une variable JS localisée avec le nonce REST.
 */
function bpcab_cta_enqueue_assets(): void {
	$should_enqueue = false;

	// 1) Si un shortcode a été rendu (plus fiable que "has_shortcode" quand le contenu est filtré par un builder).
	if (!empty($GLOBALS['bpcab_cta_has_cta'])) {
		$should_enqueue = true;
	}

	// 2) Fallback : si le post courant contient le shortcode (utile si le rendu n'a pas encore eu lieu).
	if (!$should_enqueue && is_singular()) {
		$post = get_post();
		if ($post instanceof WP_Post) {
			// has_shortcode attend du contenu brut, ça marche dans la plupart des cas.
			if (has_shortcode((string) $post->post_content, 'bpcab_cta')) {
				$should_enqueue = true;
			}
		}
	}

	/**
	 * 3) Filtre pour forcer l'enqueue depuis un thème/builder.
	 * Exemple : add_filter('bpcab_cta_force_enqueue', '__return_true');
	 */
	$should_enqueue = (bool) apply_filters('bpcab_cta_force_enqueue', $should_enqueue);

	if (!$should_enqueue) {
		return;
	}

	$base_url = plugin_dir_url(__FILE__);

	wp_enqueue_style(
		'bpcab-cta',
		$base_url . 'assets/cta.css',
		array(),
		BPCAB_CTA_VERSION
	);

	wp_enqueue_script(
		'bpcab-cta',
		$base_url . 'assets/cta.js',
		array(),
		BPCAB_CTA_VERSION,
		true
	);

	$options = bpcab_cta_get_options();

	wp_localize_script(
		'bpcab-cta',
		'BPCAB_CTA',
		array(
			'restUrl' => esc_url_raw(rest_url('bpcab/v1/cta-click')),
			// Nonce REST : côté serveur, on vérifie via check_ajax_referer-like ? Non, pour REST on lit l'en-tête X-WP-Nonce.
			'nonce'   => wp_create_nonce('wp_rest'),
			'enableTracking' => (bool) $options['enable_tracking'],
		)
	);
}
add_action('wp_enqueue_scripts', 'bpcab_cta_enqueue_assets');

/**
 * Déclare la route REST.
 */
function bpcab_cta_register_rest_routes(): void {
	register_rest_route(
		'bpcab/v1',
		'/cta-click',
		array(
			'methods'  => WP_REST_Server::CREATABLE, // POST
			'callback' => 'bpcab_cta_rest_click',
			'permission_callback' => 'bpcab_cta_rest_permissions',
			'args' => array(
				'cta_id' => array(
					'type' => 'string',
					'required' => true,
					'sanitize_callback' => 'sanitize_key',
					'validate_callback' => function ($param) {
						$param = (string) $param;
						// Limite simple : évite les IDs vides et trop longs.
						return $param !== '' && strlen($param) <= 64;
					},
				),
			),
		)
	);
}
add_action('rest_api_init', 'bpcab_cta_register_rest_routes');

/**
 * Permissions REST :
 * - Endpoint public, mais protégé par nonce REST + option d'activation.
 * - On limite aussi le spam via un throttle basique par IP.
 *
 * Attention : si vous voulez du tracking sans nonce (visiteurs non connectés),
 * vous devez gérer le consentement et la protection anti-abus autrement.
 */
function bpcab_cta_rest_permissions(WP_REST_Request $request): bool {
	$options = bpcab_cta_get_options();
	if (empty($options['enable_tracking'])) {
		return false;
	}

	// Vérifie le nonce REST (header X-WP-Nonce).
	$nonce = $request->get_header('x_wp_nonce');
	if (!$nonce || !wp_verify_nonce($nonce, 'wp_rest')) {
		return false;
	}

	// Throttle léger : 1 hit / 2s / IP (approximatif).
	$ip = isset($_SERVER['REMOTE_ADDR']) ? (string) $_SERVER['REMOTE_ADDR'] : '';
	$key = 'bpcab_cta_throttle_' . md5($ip);
	$last = (int) get_transient($key);
	$now = time();
	if ($last > 0 && ($now - $last) < 2) {
		return false;
	}
	set_transient($key, $now, 10);

	return true;
}

/**
 * Callback REST : incrémente un compteur par cta_id.
 * Stockage simple en option (table wp_options).
 */
function bpcab_cta_rest_click(WP_REST_Request $request): WP_REST_Response {
	$cta_id = (string) $request->get_param('cta_id');
	$cta_id = sanitize_key($cta_id);

	$counts = get_option('bpcab_cta_counts', array());
	if (!is_array($counts)) {
		$counts = array();
	}

	$current = isset($counts[$cta_id]) ? (int) $counts[$cta_id] : 0;
	$counts[$cta_id] = $current + 1;

	// Autoload = no pour éviter de gonfler les options chargées sur chaque page.
	update_option('bpcab_cta_counts', $counts, false);

	return new WP_REST_Response(
		array(
			'ok' => true,
			'cta_id' => $cta_id,
			'count' => (int) $counts[$cta_id],
		),
		200
	);
}

/**
 * Ajoute une page de réglages minimaliste (Réglages > BPCAB CTA).
 */
function bpcab_cta_register_settings_page(): void {
	add_options_page(
		'BPCAB CTA',
		'BPCAB CTA',
		'manage_options',
		'bpcab-cta',
		'bpcab_cta_render_settings_page'
	);
}
add_action('admin_menu', 'bpcab_cta_register_settings_page');

/**
 * Enregistre le setting.
 */
function bpcab_cta_register_settings(): void {
	register_setting(
		'bpcab_cta_settings',
		BPCAB_CTA_OPT,
		array(
			'type' => 'array',
			'sanitize_callback' => 'bpcab_cta_sanitize_options',
			'default' => array(
				'enable_tracking' => true,
			),
		)
	);

	add_settings_section(
		'bpcab_cta_main',
		'Réglages',
		function () {
			echo '<p>Réglages simples. Le tracking REST nécessite un nonce (visiteurs connectés).</p>';
		},
		'bpcab-cta'
	);

	add_settings_field(
		'enable_tracking',
		'Activer le tracking des clics (REST)',
		'bpcab_cta_field_enable_tracking',
		'bpcab-cta',
		'bpcab_cta_main'
	);
}
add_action('admin_init', 'bpcab_cta_register_settings');

/**
 * Sanitize des options.
 */
function bpcab_cta_sanitize_options($input): array {
	$input = is_array($input) ? $input : array();

	return array(
		'enable_tracking' => !empty($input['enable_tracking']),
	);
}

/**
 * Champ checkbox.
 */
function bpcab_cta_field_enable_tracking(): void {
	$options = bpcab_cta_get_options();
	$checked = !empty($options['enable_tracking']) ? 'checked' : '';

	echo '<label>';
	echo '<input type="checkbox" name="' . esc_attr(BPCAB_CTA_OPT) . '[enable_tracking]" value="1" ' . $checked . ' /> ';
	echo 'Compter les clics via l’endpoint REST (nonce requis).';
	echo '</label>';
}

/**
 * Render page settings.
 */
function bpcab_cta_render_settings_page(): void {
	if (!current_user_can('manage_options')) {
		return;
	}

	echo '<div class="wrap">';
	echo '<h1>BPCAB CTA</h1>';
	echo '<form method="post" action="options.php">';

	settings_fields('bpcab_cta_settings');
	do_settings_sections('bpcab-cta');
	submit_button();

	echo '</form>';
	echo '</div>';
}

CSS-Datei

schaffen assets/cta.css im selben Ordner wie das Plugin.

.bpcab-cta{
  display:inline-block;
  padding:0.7rem 1rem;
  border-radius:10px;
  background:#111827;
  color:#fff;
  text-decoration:none;
  font-weight:600;
  line-height:1.2;
}
.bpcab-cta:hover,
.bpcab-cta:focus{
  background:#0b1220;
  color:#fff;
}

JS-Datei

schaffen assets/cta.jsDieser JavaScript-Code sendet bei einem Klick eine REST-POST-Anfrage, sofern diese Funktion aktiviert ist.

(function () {
  "use strict";

  function postJson(url, data, nonce) {
    return fetch(url, {
      method: "POST",
      credentials: "same-origin",
      headers: {
        "Content-Type": "application/json",
        "X-WP-Nonce": nonce
      },
      body: JSON.stringify(data)
    });
  }

  document.addEventListener("click", function (e) {
    var a = e.target.closest && e.target.closest("a.bpcab-cta");
    if (!a) return;

    if (typeof window.BPCAB_CTA === "undefined") return;
    if (!window.BPCAB_CTA.enableTracking) return;

    var ctaId = a.getAttribute("data-cta-id");
    if (!ctaId) return;

    // Fire-and-forget : on ne bloque pas la navigation.
    try {
      postJson(window.BPCAB_CTA.restUrl, { cta_id: ctaId }, window.BPCAB_CTA.nonce);
    } catch (err) {
      // Pas de console.error agressif en prod.
    }
  });
})();

Code-Erklärung

Globale Logik (einfach)

  • Der Shortcode sorgt für einen übersichtlichen CTA-Link und setzt ein globales Flag ($GLOBALS['bpcab_cta_has_cta']).
  • Zum Zeitpunkt des Enqueue-Vorgangs wird CSS/JS nur geladen, wenn der CTA (Flagge oder …) aktiv ist. has_shortcode(oder Filter).
  • Das JavaScript sendet beim Klicken eine REST-POST-Anfrage mit einer REST-Nonce.
  • Der Server prüft die Option, die Nonce und drosselt die Geschwindigkeit minimal, bevor er einen Zähler inkrementiert.

Technische Details, die den entscheidenden Unterschied ausmachen

  • Flucht vs. Desinfektion :
    • reinigen reinigt den Eingang (z.B. sanitize_text_field, sanitize_key).
    • Flucht schützt die Ausgabe (z.B.: esc_html, esc_attr, esc_url).
  • REST-Nonce :
    • Wir erzeugen wp_create_nonce('wp_rest') PHP-Seite.
    • Wir versenden es über X-WP-Nonce auf der JS-Seite.
    • Wir prüfen bei wp_verify_nonce in permission_callback.
  • Optionen zum automatischen Laden :
    • Der Zähler wird in einer nicht automatisch geladenen Option gespeichert (update_option(..., false)um Schwellungen zu vermeiden wp_options Wird bei jeder Anfrage neu geladen.
  • Einhaken :
    • init für den Shortcode (WordPress ist bereit, Shortcodes zu speichern).
    • wp_enqueue_scripts für Front-End-Assets.
    • rest_api_init um die REST-Route zu registrieren.
    • admin_init + admin_menu für Einstellungen.

Nützliche Dokumente:

Varianten und Anwendungsfälle

Option 1 — Tracking für nicht angemeldete Besucher deaktivieren (aktuelles Verhalten)

Der Code funktioniert in seiner jetzigen Form primär für eingeloggte Benutzer (Nicht-REST-Benutzer). Für einen öffentlichen Blog ist dies oft die gewünschte Lösung, wenn keine Maßnahmen zur Einwilligungsverwaltung oder zum Missbrauchsschutz vorhanden sind.

Variante 2 – Klicks pro Beitrag (Beitragsmetadaten) speichern, anstatt sie als Option anzubieten

Wenn Ihr Call-to-Action (CTA) mit einem Artikel verlinkt ist, speichern Sie ihn in den Beitragsmetadaten. Vorteil: gezielte Suchanfragen, einfacherer Export pro Beitrag. Nachteil: Sie müssen die post_id und überprüfen Sie, ob es existiert.

<?php
// Exemple partiel : logique de stockage en post meta (à intégrer dans le callback REST).
$post_id = (int) $request->get_param('post_id');
if ($post_id > 0 && get_post_status($post_id)) {
	$key = '_bpcab_cta_clicks_' . $cta_id;
	$current = (int) get_post_meta($post_id, $key, true);
	update_post_meta($post_id, $key, $current + 1);
}

Variante 3 – Erzwingen des Ladens von Assets auf einer bestimmten Builder-Seite

Wenn ein Ersteller den Inhalt „neu zusammensetzt“, has_shortcode könnte den Zug verpassen. Der Filter bpcab_cta_force_enqueue ist dafür da.

<?php
// À placer dans un plugin site-specific ou thème enfant.
add_filter('bpcab_cta_force_enqueue', function ($should) {
	// Exemple : forcer sur une page ID 123.
	if (is_page(123)) {
		return true;
	}
	return $should;
});

Divi 5 / Elementor / Avada-Kompatibilität

Divi 5

Divi stellt Shortcodes in den Modulen „Code“ und „Text“ sehr gut dar. Wichtig: Divi kann die Darstellung zwischenspeichern. Falls Sie Änderungen am CSS/JS vornehmen und keine Änderung sehen, leeren Sie den Cache.

  • Divi > Designoptionen > Builder > Cache (abhängig von der Konfiguration)
  • Ihr Caching-Plugin
  • Browser-Cache

Falls die bedingte Einreihung nicht ausgelöst wird (selten, aber ich habe es bei sehr dynamischen Layouts beobachtet), verwenden Sie den Filter. bpcab_cta_force_enqueue auf der entsprechenden Seite.

Elementor

Elementor verfügt über ein „Shortcode“-Widget. Der Shortcode befindet sich üblicherweise in post_contentDie Erkennung funktioniert also. Bei der Verwendung von Templates und Schleifen kann es vorkommen, dass der CTA über ein Template gerendert wird, selbst wenn der Hauptinhalt den Shortcode nicht enthält. Auch hier ist ein Force-Filter erforderlich.

Avada (Fusion Builder)

Avada unterstützt Shortcodes in seinen Text-/Code-Elementen. Häufig wird CSS nicht angewendet, da Avada Assets kombiniert/minimiert. Testen Sie daher zunächst ohne Avada-Optimierung und aktivieren Sie diese anschließend wieder.

Praktische Empfehlung (Bauherren)

Bei Buildern behalte ich das Rendering (Layout) innerhalb des Builders bei und delegiere den Rest an das Plugin:

  • die Generierung des CTA (Shortcodes),
  • Tracking
  • Sauberes Laden der Assets.

Prüfungen nach der Installation

  • Überprüfen Sie, ob der Shortcode einen Link korrekt darstellt: hinzufügen [bpcab_cta text="Tester" url="https://example.com" id="test"] in einem Artikel.
  • Öffne die Seite und überprüfe Folgendes: assets/cta.css et assets/cta.js werden geladen (Registerkarte Netzwerk).
  • Wenn Sie angemeldet sind, klicken Sie auf den CTA und aktivieren Sie die POST-Anfrage an /wp-json/bpcab/v1/cta-click (Status 200).
  • Gehen Sie im Adminbereich zu Einstellungen > BPCAB CTA, deaktivieren Sie das Tracking und testen Sie dann erneut: Die Anfrage sollte fehlschlagen (403 oder 401, je nach Kontext).

Diagnosetabelle (Symptom → Lösung)

Symptom Mögliche Ursache Überprüfung Lösung
Der Shortcode zeigt Klartext an Shortcode nicht registriert (fehlerhafter Hook / Plugin nicht geladen) Überprüfen Sie, ob das Plugin aktiv ist (oder ob das mu-Plugin richtig positioniert ist). Legen Sie die Datei an den richtigen Ort und überprüfen Sie sie. add_action('init', ...)
Der Handlungsaufruf wird angezeigt, aber ohne jegliche Gestaltung. CSS nicht geladen (Enqueue nicht ausgelöst / Cache) Registerkarte „Netzwerk“: cta.css abwesend Erzwinge das Einreihen per Filter, leere die Caches (Plugin + Builder + Browser)
Fehler REST 403 REST-Nonce fehlt/ist ungültig Enthält die Anfrage X-WP-Nonce ? überprüfen wp_localize_scriptStellen Sie eine Verbindung her und vermeiden Sie einen Cache, der eine Seite ohne Nonce ausliefert.
Der Kilometerzähler steigt nie an Tracking deaktiviert Einstellungen > BPCAB CTA „Tracking aktivieren…“ erneut aktivieren
Nach dem Hinzufügen des Plugins wird eine leere Seite angezeigt. PHP-Fehler (Semikolon, Klammern, PHP < 8.1) Alle Events wp-content/debug.log oder Serverprotokolle Beheben Sie den Fehler, überprüfen Sie die PHP-Version und stellen Sie das System über die Staging-Umgebung bereit.

Wenn es nicht funktioniert

1) Überprüfen Sie den Speicherort des Codes.

  • Mu-Plugin: wp-content/mu-plugins/bpcab-cta/bpcab-cta.php (Die Datei muss von WordPress direkt lesbar sein.)
  • Plugin: wp-content/plugins/bpcab-cta/bpcab-cta.php + Aktivierung im Admin-Panel.

Häufiger Fehler: Erstellen mu-plugins/bpcab-cta.php Die Assets werden jedoch in einem anderen Ordner abgelegt. Hierbei gehen wir davon aus, dass… assets im selben Ordner wie die PHP-Datei.

2) Aktivieren Sie die Protokollierung ordnungsgemäß.

Auf einer Bühne aktivieren:

<?php
// wp-config.php (staging uniquement)
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

Lies dann noch einmal wp-content/debug.log.

3) Überprüfen Sie den Enqueue-Hook.

Ich bin schon oft auf einen eingefügten Textausschnitt gestoßen init Skripte abzufragen. Das funktioniert manchmal, dann aber nicht mehr mit einem Cache oder einem Builder. Hier bleiben wir bei … wp_enqueue_scripts.

4) Leeren Sie die Caches (in der richtigen Reihenfolge).

  1. Cache-Plugin (Seitencache / Objektcache).
  2. Builder-Cache (Divi/Avada).
  3. CDN-Cache, falls vorhanden.
  4. Browser-Cache.

5) Testen Sie den REST-Endpunkt isoliert

Wenn Sie angemeldet sind, testen Sie mit curl (indem Sie eine Nonce von der Seite abrufen oder ein kleines Skript verwenden). Beispiel (Benutzername):

curl -X POST "https://votre-site.tld/wp-json/bpcab/v1/cta-click" 
  -H "Content-Type: application/json" 
  -H "X-WP-Nonce: VOTRE_NONCE" 
  --data '{"cta_id":"test"}'

Häufige Fallstricke und Fehler

Fehler Verursachen Lösung
Kopieren Sie den Code nach functions.php des übergeordneten Themas Theme-Update = Codeverlust Verwenden Sie ein Plugin (oder mu-Plugin) oder ein Child-Theme.
Vergessen eines Semikolons → weißer Bildschirm PHP-Syntaxfehler Lesen Sie die Protokolle, beheben Sie das Problem und testen Sie auf dem Staging-System.
Verwendung des falschen Hooks zum Einreihen init statt wp_enqueue_scripts Umfrage nur in wp_enqueue_scripts / admin_enqueue_scripts
Cache-Konflikt: Ungültige REST-Nonce Eine zwischengespeicherte Seite liefert eine abgelaufene Nonce oder eine von einem anderen Benutzer. Seiten angemeldeter Benutzer vom Cache ausschließen oder öffentliches Tracking deaktivieren
„REST 403“ auch bei bestehender Verbindung Kopfzeile X-WP-Nonce fehlt (JS nicht geladen) Prüfen Sie die bedingte Abfrage, erzwingen Sie sie über den Filter.
Der Shortcode funktioniert im Editor, aber nicht im Builder. Der Builder rendert über template/loop out post_content Die Abfrage auf der Seite erzwingen (Filter) oder global laden, falls sie sehr klein ist
„Aufruf einer nicht definierten Funktion…“ Der Code wurde zu früh ausgeführt (bevor WordPress geladen wurde) oder eine Datei wurde außerhalb des Kontextes eingebunden. überprüfen ABSPATHPlatzieren Sie den Code in einem Plugin, verwenden Sie Hooks
Fehler „Ihre PHP-Version ist zu alt“ PHP-Hosting < 8.1 Aktualisieren Sie PHP auf dem Hosting-Server (oder passen Sie den Code an, dies wird jedoch nicht empfohlen).
CSS/JS wird nicht geladen Falscher Weg plugin_dir_url(__FILE__) wenn Vermögenswerte verlegt werden Beachten Sie die Verzeichnisstruktur und prüfen Sie im Netzwerk-Tab auf 404-Fehler.

Sicherheits-, Leistungs- und Wartungstipps

Sicherheit

  • Unmaskiertes HTML niemals rendern Inhalte werden über einen Shortcode kopiert, importiert und manchmal auch von anderen Rollen bearbeitet, selbst wenn dieser nur von Administratoren verwendet wird.
  • REST öffentlich = AngriffsflächeHier wurde bewusst eine REST-Nonce verlangt, um die Nutzung auf verbundene Sitzungen zu beschränken. Für öffentliches Tracking ist eine umfassende Strategie erforderlich (Einwilligung + Missbrauchsschutz + Speicherung).
  • Berechtigungen Für eine Route, die sensible Daten verändert, verwenden Sie Berechtigungen. Hier erhöhen wir einen Zähler, begrenzen ihn aber dennoch.

Leistung

  • Assets nur laden, wenn nötigDies wirkt sich direkt positiv auf die Core Web Vitals aus, wenn Ihre Website viele Seiten hat.
  • Vermeiden Sie das Aufblasen wp_options AutoloadAutomatisch geladene Optionen werden (fast) bei jeder Anfrage geladen. Große Zähler müssen Autoload=Nein oder an anderer Stelle gespeichert.
  • Vorsicht vor optionalem Speicherplatz! Wenn Sie Hunderte von CTAs haben, ist die Option bpcab_cta_counts Es kann wachsen. In diesem Fall sollten Sie auf eine separate Tabelle oder Beitragsmetadaten umsteigen.

Wartung

  • Version Dieses Plugin (Git). Ein nicht versionierter Code-Schnipsel wird bei einer Neugestaltung schnell zu einem „Rätsel“.
  • Dokumentieren Sie die Filter die Sie hier präsentieren bpcab_cta_force_enqueueDas sind Details, die einem nützen, wenn ein Bauherr seine Darstellung ändert.
  • Vermeide alte Tutorials Viele Codebeispiele vor PHP 8.1 verwenden unsichere Muster (unkontrollierte globale Variablen, veraltete Funktionen, Inline-JavaScript). Bei WordPress 6.9.4 sollten Sie sich an die offiziellen APIs halten.

Ressourcen

FAQ

Warum ein Plugin statt functions.php ?

Weil der Code nicht vom Theme abhängen soll. Ein Plugin übersteht Theme-Änderungen und deaktiviert sich ordnungsgemäß, um einen Fehler zu isolieren.

Warum benötigt REST-Tracking eine Nonce?

Andernfalls wird Ihr Endpunkt zu einem einfachen Einfallstor für Spam. Mit einer REST-Nonce beschränken Sie den Zugriff (standardmäßig) auf angemeldete Benutzer. Für öffentliches Tracking ist ein anderes Design erforderlich.

Ich möchte die Klicks von Besuchern zählen, die nicht angemeldet sind. Wie mache ich das?

Technisch gesehen: Sie können den Zugriff ohne Nonce erlauben und robustere Missbrauchsschutzmaßnahmen implementieren (Ratenbegrenzung, Signaturen, serverseitige Speicherung). Rechtlich gesehen: Sie müssen die Einwilligung gemäß Ihrem spezifischen Kontext (DSGVO) verwalten. Ich rate davon ab, einfach „die Tür zu öffnen“.

Warum verwenden? update_option(..., false) ?

Die dritte Parameterkraft Autoload=NeinEin Zähler kann wachsen; man möchte nicht, dass er auf jeder Seite geladen wird.

Der Shortcode löst in meinem Builder keine Einreihung aus, was soll ich tun?

Verwenden Sie den Filter bpcab_cta_force_enqueue auf der entsprechenden Seite oder global laden, wenn Ihr CSS/JS-Code sehr klein ist. Bei einigen Schleifenvorlagen has_shortcode Er sieht nichts.

Warum eine „globale Flagge“? $GLOBALS['bpcab_cta_has_cta'] ?

Denn es ist eine einfache und zuverlässige Methode, um festzustellen, ob ein Call-to-Action (CTA) gerendert wurde, selbst wenn der Inhalt durch komplexe Filter transformiert wurde. Es ist ein alter Trick, aber effektiv, wenn er sparsam eingesetzt wird.

Ist es mit mehreren Websites kompatibel?

Ja, grundsätzlich gilt: Optionen und Transienten sind standortspezifisch. Für Netzwerkberichte müssen die Daten entweder auf Netzwerkebene (Standortoptionen) gespeichert oder zentral an anderer Stelle verwaltet werden.

Entspricht es den WordPress-Standards?

Wir verwenden Standard-APIs (Shortcode, Enqueue, REST, Einstellungen). Um die Funktionalität weiter zu verbessern: Aufteilung in Klassen, Hinzufügen von Tests und detailliertere Dokumentation der Filter/Aktionen.

Wie kann ich die Zähler im Admin-Panel anzeigen lassen?

Die einfachste Lösung: eine spezielle Admin-Seite mit folgendem Inhalt: get_option('bpcab_cta_counts') und zeigt eine Tabelle an. Bei einer großen Anzahl von IDs sollten Sie eine Paginierung und Datenbereinigung einplanen.

Was soll ich tun, wenn ich die Fehlermeldung „REST-Cookie ist ungültige Nonce“ erhalte?

Dies tritt häufig bei einem aggressiven Cache für angemeldete Benutzer oder einem Sicherheits-Plugin auf, das Cookies verändert. Deaktivieren Sie vorübergehend den Cache für angemeldete Benutzer und testen Sie erneut. Überprüfen Sie auch den Header. X-WP-Nonce Es wurde korrekt gesendet.

Kann ich ersetzen wp_localize_script ?

Ja, das können Sie verwenden. wp_add_inline_script um ein JSON-Objekt einzufügen. wp_localize_script bleibt sehr praktisch und wird häufig für die Datenübertragung an JS verwendet.