{"id":340444,"date":"2026-08-17T11:03:47","date_gmt":"2026-08-17T11:03:47","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/anni-marketing\/"},"modified":"2026-10-20T18:13:21","modified_gmt":"2026-10-20T18:13:21","slug":"anni-marketing","status":"publish","type":"plugin","link":"https:\/\/th.wordpress.org\/plugins\/anni-marketing\/","author":23532573,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.4.3","stable_tag":"1.4.3","tested":"7.1.3","requires":"5.9","requires_php":"7.4","requires_plugins":null,"header_name":"Anni Marketing","header_author":"Anni Marketing","header_description":"Verbindet deine Website mit Anni (anni-marketing.ch): Statistik-Messcode und Status-Kanal. Keine Daten an Dritte, kein Tracking durch das Plugin selbst.","assets_banners_color":"","last_updated":"2026-10-20 18:13:21","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/anni-marketing.ch","header_author_uri":"https:\/\/digitalerakete.ch","rating":0,"author_block_rating":0,"active_installs":0,"downloads":438,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.4":{"tag":"1.1.4","author":"annimarketing","date":"2026-08-17 11:03:21","revision":3650983},"1.1.6":{"tag":"1.1.6","author":"annimarketing","date":"2026-09-15 15:32:41","revision":3697282},"1.2.0":{"tag":"1.2.0","author":"annimarketing","date":"2026-09-28 08:30:46","revision":3716645},"1.4.0":{"tag":"1.4.0","author":"annimarketing","date":"2026-10-14 04:33:00","revision":3745272},"1.4.1":{"tag":"1.4.1","author":"annimarketing","date":"2026-10-20 14:32:27","revision":3756924},"1.4.3":{"tag":"1.4.3","author":"annimarketing","date":"2026-10-20 18:13:21","revision":3757258}},"upgrade_notice":[],"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.4","1.1.6","1.2.0","1.4.0","1.4.1","1.4.3"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[232,1005,597,127115,34283],"plugin_category":[36],"plugin_contributors":[276092],"plugin_business_model":[],"class_list":["post-340444","plugin","type-plugin","status-publish","hentry","plugin_tags-analytics","plugin_tags-google-analytics","plugin_tags-integration","plugin_tags-search-console","plugin_tags-site-verification","plugin_category-analytics","plugin_contributors-annimarketing","plugin_committers-annimarketing"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/anni-marketing.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Anni is a marketing assistant for small businesses in Switzerland (anni-marketing.ch). This companion plugin lets Anni finish your Google setup automatically after you connect your WordPress site:<\/p>\n\n<ul>\n<li>Outputs the <strong>Google Analytics 4<\/strong> tag (gtag.js) in your site's head \u2014 only if you (or Anni, with your permission) configure a measurement ID.<\/li>\n<li>Outputs the <strong>Google Search Console<\/strong> site-verification meta tag \u2014 only if a verification token is configured.<\/li>\n<li>Provides a small authenticated REST endpoint (<code>anni\/v1<\/code>) so the Anni app can read plugin status and set the two values above. All endpoints require the <code>manage_options<\/code> capability (administrators). Requests are authenticated with WordPress Application Passwords.<\/li>\n<\/ul>\n\n<p>The plugin itself does <strong>not<\/strong> track visitors, does not send data anywhere, and stores only two options (<code>anni_ga4_id<\/code>, <code>anni_gsc_verification<\/code>). The Google Analytics tag is only loaded if a measurement ID has been explicitly configured; in that case Google's terms for Analytics apply.<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin connects your site to the Anni marketing platform (https:\/\/anni-marketing.ch), operated by\ndigitale rakete GmbH (https:\/\/digitalerakete.ch), so that Anni can complete your Google setup for you.<\/p>\n\n<p>What the plugin itself sends: nothing. The plugin does not initiate any outbound request. It only\n<em>receives<\/em> authenticated REST requests from the Anni app and stores\/prints two values on your site.<\/p>\n\n<p>When your site is contacted: only after you connect your website inside your own Anni account and\ncreate a WordPress Application Password for it. The Anni app then calls the endpoints below using\nthat password:<\/p>\n\n<ul>\n<li><code>GET \/wp-json\/anni\/v1\/status<\/code> \u2014 reads whether the plugin is active and which values are set\n(requires the <code>manage_options<\/code> capability).<\/li>\n<li><code>POST \/wp-json\/anni\/v1\/ga4<\/code> \u2014 stores your Google Analytics 4 measurement ID (requires <code>manage_options<\/code>).<\/li>\n<li><code>POST \/wp-json\/anni\/v1\/gsc<\/code> \u2014 stores your Google Search Console verification token (requires <code>manage_options<\/code>).<\/li>\n<\/ul>\n\n<p>Data involved: your GA4 measurement ID and your Search Console verification token. No visitor data,\nno personal data and no site content is transmitted by this plugin.<\/p>\n\n<p>Google Analytics: if \u2014 and only if \u2014 a measurement ID is configured, the plugin prints Google's\nstandard gtag.js snippet, which loads https:\/\/www.googletagmanager.com\/gtag\/js in visitors' browsers.\nThis is Google's service, used under your own Google Analytics property. Google's terms and privacy\npolicy apply: https:\/\/policies.google.com\/terms and https:\/\/policies.google.com\/privacy<\/p>\n\n<p>Anni platform terms and privacy policy: https:\/\/anni-marketing.ch\/nutzungsbedingungen and\nhttps:\/\/anni-marketing.ch\/datenschutz<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate the plugin.<\/li>\n<li>Connect your website in your Anni account (anni-marketing.ch) \u2014 Anni configures statistics and Search Console automatically.<\/li>\n<li>Alternatively, set the options manually via WP-CLI or the REST endpoint.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20track%20my%20visitors%3F\"><h3>Does this plugin track my visitors?<\/h3><\/dt>\n<dd><p>No. It only prints the Google Analytics tag if you configure a measurement ID. Without configuration it outputs nothing.<\/p><\/dd>\n<dt id=\"who%20can%20change%20the%20settings%3F\"><h3>Who can change the settings?<\/h3><\/dt>\n<dd><p>Only authenticated WordPress administrators (<code>manage_options<\/code>), typically via an Application Password issued by you. All <code>anni\/v1<\/code> endpoints require this \u2014 including reading the plugin status; page edits additionally require the right to edit that page (<code>edit_post<\/code>).<\/p><\/dd>\n<dt id=\"does%20it%20work%20without%20an%20anni%20account%3F\"><h3>Does it work without an Anni account?<\/h3><\/dt>\n<dd><p>Yes \u2014 you can set the GA4 ID and the Search Console token yourself; the plugin is a minimal, dependency-free head-injector.<\/p><\/dd>\n<dt id=\"why%20does%20this%20plugin%20re-enable%20application%20passwords%3F\"><h3>Why does this plugin re-enable Application Passwords?<\/h3><\/dt>\n<dd><p>Anni connects to your site exclusively through WordPress Application Passwords (the built-in\n    authorize-application.php flow \u2014 you approve the connection yourself, no password typing).\nSome security plugins disable Application Passwords globally, which silently breaks that\nconnection. If you install this plugin, you explicitly want the Anni connection, so it makes\nthe feature available again \u2014 but only for Anni: authorization requests from any other\napplication keep whatever policy your security plugin enforces. WordPress' own HTTPS\nrequirement for Application Passwords stays untouched.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.4.3<\/h4>\n\n<ul>\n<li>\/llms.txt follows llmstxt.org more closely: legal pages (imprint, privacy policy, terms, cookie policy) move to an\n\"Optional\" section, matched by their exact address or title only, so pages like \"Legal Tech\" or \"Cookie recipes\" stay\nin the main list. Posts carry their manual excerpt as a short description. Pages set to noindex in Yoast or\nRank Math are left out.<\/li>\n<\/ul>\n\n<h4>1.4.2<\/h4>\n\n<ul>\n<li>AI search access in robots.txt now also covers DuckAssistBot, MistralAI-User, Meta-WebIndexer, Amzn-SearchBot\nand Amzn-User (answer and retrieval bots that, per their operators, do not train models). Your training setting\nnow also applies to Applebot-Extended, Meta-ExternalAgent and Amazonbot.<\/li>\n<\/ul>\n\n<h4>1.4.1<\/h4>\n\n<ul>\n<li>Maintenance release: no change to how the plugin behaves on your website. The cookie notice script gains\noptional layout variants that are used only on Anni's own pages; without them the notice looks and works\nexactly as in 1.4.0.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>New setting \"Anni may adjust website technology\" (Settings &gt; Anni, on by default). When off, the plugin\noutputs none of the items below and makes no further changes; undo stays available.<\/li>\n<li>AI search access in robots.txt: AI search crawlers (OAI-SearchBot, ChatGPT-User, PerplexityBot,\nPerplexity-User, Claude-SearchBot, Claude-User) are no longer blocked; training crawlers (GPTBot,\nGoogle-Extended, ClaudeBot, CCBot) follow your setting. Works through the robots_txt filter; if a physical\nrobots.txt exists and is writable, the plugin updates that file and keeps the previous content for undo.<\/li>\n<li>Business schema (Organization\/LocalBusiness) on the front page. If Rank Math or Yoast already output an\norganization, the plugin completes their node through their schema filters instead of adding a second one;\nif the theme outputs one, the plugin adds nothing.<\/li>\n<li>FAQPage schema for posts and pages with question headings (at least two), skipped when the page already has\nFAQ schema (for example from an SEO plugin's FAQ block).<\/li>\n<li>\/llms.txt with your pages and recent posts (not linked anywhere, only when the site is public).<\/li>\n<li>Business details correction (name, address, phone) after your approval: exact text in page content\n(block editor, classic, Elementor incl. header\/footer templates), widgets and Customizer settings, plus an\noptional output rule for text built into the theme (text only, never attributes or scripts).<\/li>\n<li>Search engine visibility can be switched on after your approval.<\/li>\n<li>Every change is recorded in the Anni history (<code>{prefix}anni_changes<\/code>) and can be undone, with a conflict check.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Page editing for Elementor (classic widgets, 10Web widgets, header\/footer templates): Anni changes only\nfields an element really has (checked against the widget's own controls), validates values, cleans text\nwith wp_kses_post and saves through Elementor's own document API. Every change is recorded in an own\ntable (<code>{prefix}anni_changes<\/code>) and can be undone, with a conflict check if the page changed meanwhile.<\/li>\n<li>Style per device (typography, colours, spacing, borders, background, animation) from an allow-list of\nstyle sections; global kit colours and fonts of the active kit (existing entries only).<\/li>\n<li>Structure: duplicate, move, hide per device; deleting a section needs a one-time confirmation token.<\/li>\n<li>Images: swap an image in a widget, compress an image under the same media ID with a private backup of\nthe original and a restore endpoint. Images are processed on your server; nothing is sent elsewhere.<\/li>\n<li>SEO title\/description\/focus keyword for Rank Math and Yoast are exposed to the WordPress REST API for\nusers who can edit the post.<\/li>\n<li>Optional load-time switches for images (fetchpriority for the largest image, lazy loading below the\nfold, decoding=\"async\"), each one can be turned off again.<\/li>\n<li>Hardening: write requests to <code>anni\/v1<\/code> are limited per user (120 per minute, image optimisation 20 per\nminute, HTTP 429 above), requests larger than 2 MB are rejected (HTTP 413), invalid values are rejected\nwith a real HTTP error instead of being adjusted silently.<\/li>\n<li>New endpoints require <code>manage_options<\/code> and, for a page, <code>edit_post<\/code>. Uninstalling removes the table and\nthe plugin's options. The plugin still makes no outbound requests.<\/li>\n<\/ul>\n\n<h4>1.2.1<\/h4>\n\n<ul>\n<li>Elementor editing: Anni can now target a specific text field (icon boxes, image boxes, icon lists, call-to-action, testimonials, animated headlines, header\/footer templates). Only existing text fields are written; the text is passed through wp_kses_post.<\/li>\n<li>The \"Zu Anni\" link in the activation notice now points to the Anni environment this site is connected to (taken from the consent configuration), instead of always to app.anni-marketing.ch.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Consent banner built in: the plugin now shows a bottom notice (\"Alle akzeptieren\" \/ \"Nur notwendige\" \/\n\"Einstellungen anpassen\" with categories) before Google Analytics loads. Until now the plugin only set\nConsent Mode to \"denied\" and never asked, so nothing was measured. Texts, colours, privacy link and\nmode (basic = no Google contact before consent, advanced = cookieless pings) come from Anni via the new\nREST endpoint <code>anni\/v1\/consent<\/code>; without it, built-in defaults with the site name and WordPress privacy\npage apply. Choice stored as a first-party cookie for 182 days, footer link \"Cookie-Einstellungen\" to\nchange it. No data is sent to Anni except an anonymous accept\/decline count when configured.<\/li>\n<\/ul>\n\n<h4>1.1.8<\/h4>\n\n<ul>\n<li>Elementor editing: new REST endpoints <code>anni\/v1\/elementor\/{id}<\/code> (GET the widget tree, POST\nsurgical text edits by stable element id) via Elementor's own Document::save() \u2014 correct CSS\nregeneration, native revision for undo, per-page locking. Only active when Elementor is installed.<\/li>\n<\/ul>\n\n<h4>1.1.7<\/h4>\n\n<ul>\n<li>GA4 now respects visitor consent: Consent Mode v2 defaults to \"denied\" before the config call,\nso no analytics or advertising storage is used until a consent tool on the site grants it. Sites\nwithout a consent banner therefore no longer measure without consent (GDPR\/Swiss DPA compliant).<\/li>\n<\/ul>\n\n<h4>1.1.6<\/h4>\n\n<ul>\n<li>Application Passwords availability is now restored surgically instead of globally:\nauthorization requests whose application name does not start with \"Anni\" keep the policy\nenforced by your security plugin (both availability filters plus the\n  wp_authorize_application_password_request_errors hook, scoped the same way).<\/li>\n<li>Added a dismissible admin notice after activation pointing back to Anni (no redirect).<\/li>\n<li>Added a FAQ entry explaining why and how the plugin re-enables Application Passwords.<\/li>\n<\/ul>\n\n<h4>1.1.5<\/h4>\n\n<ul>\n<li>Restore Application Passwords availability via the <code>wp_is_application_passwords_available<\/code>\nfilter (latest priority) \u2014 some security plugins disable the feature globally, which breaks\nthe Anni connection entirely. WordPress' HTTPS requirement stays untouched.<\/li>\n<\/ul>\n\n<h4>1.1.4<\/h4>\n\n<ul>\n<li>Author URI auf https:\/\/digitalerakete.ch umgestellt (die alte Adresse hatte kein\ngueltiges Zertifikat und wurde vom Review geruegt).<\/li>\n<li>Firmenname in readme.txt an das Impressum angeglichen: digitale rakete GmbH.<\/li>\n<\/ul>\n\n<h4>1.1.3<\/h4>\n\n<ul>\n<li>Tightened the <code>\/status<\/code> REST endpoint to require <code>manage_options<\/code> (was <code>edit_posts<\/code>), matching the other two endpoints and this readme's own description.<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Added the required \"External services\" documentation.<\/li>\n<li>Corrected the documented capabilities to match the code (status: edit_posts, writes: manage_options).<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Search Console verification meta support (<code>anni\/v1\/gsc<\/code>).<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release: GA4 tag output + status endpoint.<\/li>\n<\/ul>","raw_excerpt":"Connects your site to Anni (anni-marketing.ch): adds your own GA4 tag and Search Console verification. No tracking by the plugin itself.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/340444","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=340444"}],"author":[{"embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/annimarketing"}],"wp:attachment":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=340444"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=340444"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=340444"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=340444"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=340444"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=340444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}