{"id":278012,"date":"2026-02-03T17:16:55","date_gmt":"2026-02-03T17:16:55","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/a1-tools\/"},"modified":"2026-08-14T14:56:20","modified_gmt":"2026-08-14T14:56:20","slug":"a1-tools","status":"publish","type":"plugin","link":"https:\/\/ky.wordpress.org\/plugins\/a1-tools\/","author":23444128,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"3.3.5","stable_tag":"3.3.5","tested":"6.9.7","requires":"5.0","requires_php":"7.4","requires_plugins":null,"header_name":"A1 Tools","header_author":"A1 Chimney","header_description":"Connects your WordPress site to the A1 Tools platform for centralized management of contact information, social media links, and business details.","assets_banners_color":"825b2d","last_updated":"2026-08-14 14:56:20","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/app.a-1chimney.com","header_author_uri":"https:\/\/a-1chimney.com","rating":0,"author_block_rating":0,"active_installs":100,"downloads":5589,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.10.0":{"tag":"1.10.0","author":"a1tools","date":"2026-03-09 15:03:13"},"1.3.2":{"tag":"1.3.2","author":"a1tools","date":"2026-02-03 17:24:12"},"1.4.0":{"tag":"1.4.0","author":"a1tools","date":"2026-02-03 17:25:21"},"1.4.1":{"tag":"1.4.1","author":"a1tools","date":"2026-02-03 17:40:13"},"1.4.10":{"tag":"1.4.10","author":"a1tools","date":"2026-02-10 16:11:21"},"1.4.11":{"tag":"1.4.11","author":"a1tools","date":"2026-02-16 17:37:16"},"1.4.12":{"tag":"1.4.12","author":"a1tools","date":"2026-02-16 20:06:07"},"1.4.13":{"tag":"1.4.13","author":"a1tools","date":"2026-02-20 17:56:41"},"1.4.14":{"tag":"1.4.14","author":"a1tools","date":"2026-02-23 15:51:48"},"1.4.2":{"tag":"1.4.2","author":"a1tools","date":"2026-02-04 15:57:56"},"1.4.3":{"tag":"1.4.3","author":"a1tools","date":"2026-02-04 20:46:16"},"1.4.4":{"tag":"1.4.4","author":"a1tools","date":"2026-02-09 18:00:42"},"1.4.5":{"tag":"1.4.5","author":"a1tools","date":"2026-02-09 18:16:44"},"1.4.6":{"tag":"1.4.6","author":"a1tools","date":"2026-02-10 15:46:54"},"1.4.7":{"tag":"1.4.7","author":"a1tools","date":"2026-02-10 15:49:54"},"1.4.8":{"tag":"1.4.8","author":"a1tools","date":"2026-02-10 16:00:35"},"1.4.9":{"tag":"1.4.9","author":"a1tools","date":"2026-02-10 16:05:44"},"1.5.0":{"tag":"1.5.0","author":"a1tools","date":"2026-02-23 15:52:56"},"1.5.1":{"tag":"1.5.1","author":"a1tools","date":"2026-02-23 17:03:16"},"1.5.2":{"tag":"1.5.2","author":"a1tools","date":"2026-02-24 17:11:54"},"1.5.3":{"tag":"1.5.3","author":"a1tools","date":"2026-02-24 17:52:42"},"1.5.4":{"tag":"1.5.4","author":"a1tools","date":"2026-02-24 17:58:29"},"1.5.5":{"tag":"1.5.5","author":"a1tools","date":"2026-02-27 15:45:15"},"1.5.6":{"tag":"1.5.6","author":"a1tools","date":"2026-02-27 16:03:10"},"1.5.7":{"tag":"1.5.7","author":"a1tools","date":"2026-02-27 16:18:25"},"1.5.8":{"tag":"1.5.8","author":"a1tools","date":"2026-02-27 16:28:37"},"1.5.9":{"tag":"1.5.9","author":"a1tools","date":"2026-02-27 16:39:05"},"1.6.0":{"tag":"1.6.0","author":"a1tools","date":"2026-02-27 16:53:29"},"1.6.1":{"tag":"1.6.1","author":"a1tools","date":"2026-02-27 17:03:50"},"1.6.2":{"tag":"1.6.2","author":"a1tools","date":"2026-02-27 17:24:39"},"1.6.3":{"tag":"1.6.3","author":"a1tools","date":"2026-02-27 17:45:25"},"1.6.4":{"tag":"1.6.4","author":"a1tools","date":"2026-02-27 20:53:11"},"1.6.5":{"tag":"1.6.5","author":"a1tools","date":"2026-03-02 18:48:04"},"1.6.6":{"tag":"1.6.6","author":"a1tools","date":"2026-03-02 19:35:33"},"1.6.7":{"tag":"1.6.7","author":"a1tools","date":"2026-03-02 19:43:09"},"1.6.8":{"tag":"1.6.8","author":"a1tools","date":"2026-03-02 19:47:07"},"1.6.9":{"tag":"1.6.9","author":"a1tools","date":"2026-03-02 19:54:53"},"1.7.0":{"tag":"1.7.0","author":"a1tools","date":"2026-03-03 13:02:35"},"1.7.1":{"tag":"1.7.1","author":"a1tools","date":"2026-03-03 16:20:27"},"1.7.2":{"tag":"1.7.2","author":"a1tools","date":"2026-03-03 16:29:51"},"1.7.3":{"tag":"1.7.3","author":"a1tools","date":"2026-03-03 16:50:49"},"1.7.4":{"tag":"1.7.4","author":"a1tools","date":"2026-03-03 17:06:19"},"1.7.5":{"tag":"1.7.5","author":"a1tools","date":"2026-03-03 19:51:42"},"1.7.6":{"tag":"1.7.6","author":"a1tools","date":"2026-03-03 20:20:51"},"1.7.7":{"tag":"1.7.7","author":"a1tools","date":"2026-03-03 20:42:19"},"1.7.8":{"tag":"1.7.8","author":"a1tools","date":"2026-03-03 20:53:24"},"1.7.9":{"tag":"1.7.9","author":"a1tools","date":"2026-03-04 17:00:58"},"1.8.0":{"tag":"1.8.0","author":"a1tools","date":"2026-03-04 17:04:28"},"1.8.1":{"tag":"1.8.1","author":"a1tools","date":"2026-03-04 18:14:16"},"1.8.2":{"tag":"1.8.2","author":"a1tools","date":"2026-03-04 18:54:01"},"1.8.3":{"tag":"1.8.3","author":"a1tools","date":"2026-03-04 18:58:06"},"1.8.4":{"tag":"1.8.4","author":"a1tools","date":"2026-03-04 19:29:43"},"1.8.5":{"tag":"1.8.5","author":"a1tools","date":"2026-03-04 19:44:22"},"1.8.6":{"tag":"1.8.6","author":"a1tools","date":"2026-03-04 19:57:58"},"1.9.0":{"tag":"1.9.0","author":"a1tools","date":"2026-03-05 14:27:39"},"1.9.1":{"tag":"1.9.1","author":"a1tools","date":"2026-03-05 14:37:58"},"1.9.2":{"tag":"1.9.2","author":"a1tools","date":"2026-03-06 18:48:23"},"1.9.3":{"tag":"1.9.3","author":"a1tools","date":"2026-03-06 20:19:02"},"1.9.4":{"tag":"1.9.4","author":"a1tools","date":"2026-03-09 14:01:25"},"1.9.5":{"tag":"1.9.5","author":"a1tools","date":"2026-03-09 14:02:55"},"1.9.6":{"tag":"1.9.6","author":"a1tools","date":"2026-03-09 14:14:20"},"1.9.7":{"tag":"1.9.7","author":"a1tools","date":"2026-03-09 14:30:38"},"1.9.8":{"tag":"1.9.8","author":"a1tools","date":"2026-03-09 14:47:56"},"1.9.9":{"tag":"1.9.9","author":"a1tools","date":"2026-03-09 14:55:31"},"2.0.0":{"tag":"2.0.0","author":"a1tools","date":"2026-03-09 15:07:11"},"2.0.1":{"tag":"2.0.1","author":"a1tools","date":"2026-03-09 15:17:22"},"2.0.2":{"tag":"2.0.2","author":"a1tools","date":"2026-03-09 17:02:31"},"2.0.4":{"tag":"2.0.4","author":"a1tools","date":"2026-03-10 12:43:56"},"2.0.5":{"tag":"2.0.5","author":"a1tools","date":"2026-03-13 13:33:23"},"2.0.6":{"tag":"2.0.6","author":"a1tools","date":"2026-03-13 15:13:40"},"2.0.7":{"tag":"2.0.7","author":"a1tools","date":"2026-03-13 16:09:56"},"2.1.5":{"tag":"2.1.5","author":"a1tools","date":"2026-03-23 16:50:50"},"2.1.6":{"tag":"2.1.6","author":"a1tools","date":"2026-03-24 13:41:45"},"2.2.0":{"tag":"2.2.0","author":"a1tools","date":"2026-03-24 17:07:35"},"2.3.0":{"tag":"2.3.0","author":"a1tools","date":"2026-04-01 18:25:34"},"2.4.0":{"tag":"2.4.0","author":"a1tools","date":"2026-04-30 13:51:04"},"2.4.1":{"tag":"2.4.1","author":"a1tools","date":"2026-04-30 13:55:49"},"2.4.2":{"tag":"2.4.2","author":"a1tools","date":"2026-05-06 17:06:44"},"2.4.3":{"tag":"2.4.3","author":"a1tools","date":"2026-05-06 17:50:26"},"2.5.0":{"tag":"2.5.0","author":"a1tools","date":"2026-05-12 17:33:59"},"2.5.10":{"tag":"2.5.10","author":"a1tools","date":"2026-05-13 18:59:22"},"2.5.2":{"tag":"2.5.2","author":"a1tools","date":"2026-05-12 19:48:48"},"2.5.20":{"tag":"2.5.20","author":"a1tools","date":"2026-05-14 13:53:05"},"2.5.26":{"tag":"2.5.26","author":"a1tools","date":"2026-05-26 12:58:20"},"2.5.3":{"tag":"2.5.3","author":"a1tools","date":"2026-05-13 12:45:55"},"2.5.4":{"tag":"2.5.4","author":"a1tools","date":"2026-05-13 13:24:14"},"2.5.5":{"tag":"2.5.5","author":"a1tools","date":"2026-05-13 13:24:14"},"2.5.6":{"tag":"2.5.6","author":"a1tools","date":"2026-05-13 16:24:57"},"2.5.7":{"tag":"2.5.7","author":"a1tools","date":"2026-05-13 16:34:18"},"2.5.8":{"tag":"2.5.8","author":"a1tools","date":"2026-05-13 16:56:36"},"2.5.9":{"tag":"2.5.9","author":"a1tools","date":"2026-05-13 17:06:49"},"2.6.0":{"tag":"2.6.0","author":"a1tools","date":"2026-06-01 18:30:13"},"2.6.1":{"tag":"2.6.1","author":"a1tools","date":"2026-06-02 15:05:23"},"3.2.0":{"tag":"3.2.0","author":"a1tools","date":"2026-07-08 12:49:14"},"3.2.11":{"tag":"3.2.11","author":"a1tools","date":"2026-08-04 17:58:44"},"3.2.12":{"tag":"3.2.12","author":"a1tools","date":"2026-08-04 19:02:30"},"3.2.8":{"tag":"3.2.8","author":"a1tools","date":"2026-07-16 17:00:44"},"3.3.0":{"tag":"3.3.0","author":"a1tools","date":"2026-08-05 19:22:04"},"3.3.2":{"tag":"3.3.2","author":"a1tools","date":"2026-08-12 12:39:20"},"3.3.3":{"tag":"3.3.3","author":"a1tools","date":"2026-08-13 13:46:38"},"3.3.4":{"tag":"3.3.4","author":"a1tools","date":"2026-08-13 15:14:31"},"3.3.5":{"tag":"3.3.5","author":"a1tools","date":"2026-08-14 14:56:20"}},"upgrade_notice":{"2.6.0":"<p>Adds the A1 Review Funnel (star-rating widget, shortcode, and optional floating button) plus a Review Link site variable. Collected feedback appears in the A1 Tools CRM under Customer Experience.<\/p>","2.5.2":"<p>Major upgrade for both A1 Web Form and A1 Live Chat widgets. The form widget gains full visual styling controls, a standard-fields repeater (toggle\/relabel\/reorder the 10 CRM fields), a custom-fields repeater (add arbitrary fields of any type), an SMS-consent block with TCPA-friendly legal-trail storage, and an optional &quot;I&#039;m not a robot&quot; checkbox. The chat widget gains pre-chat form configurability and full window-container styling. The CRM client renders all of the new data in the dispatcher detail panel. Requires A1 Tools 5.3.166 or later on the server side (the DB schema adds three new columns).<\/p>","2.5.1":"<p>Critical fix for 2.5.0: the Web Form + Live Chat widgets were reading the wrong WordPress option for the CRM company ID, so on sites that already had the legacy form integration configured, the new widgets rendered with company_id=0 and the chat button was clickable but unresponsive. Update immediately if you&#039;ve placed the new widgets on any live page.<\/p>","2.5.0":"<p>Adds two new Elementor widgets: A1 Web Form (structured lead intake) and A1 Web Chat (live chat with floating + inline modes that share one conversation). Submissions and chats flow into the reworked Web Leads tab in the CRM. Requires A1 Tools 5.3.160 or later on the server side.<\/p>","2.4.3":"<p>Franchise widget now uses stored coordinates correctly and aligns cards in the grid even when titles wrap to a second line.<\/p>","2.4.2":"<p>Fixes a transient TTL bug where &quot;No caching&quot; stored a permanent transient and every other duration was 60\u00d7 too long. Cached payloads (city pages, site variables, franchises, etc.) are flushed automatically on upgrade.<\/p>","1.4.0":"<p>Added auto-updates support for WordPress.<\/p>","1.3.2":"<p>Fixed WordPress.org compliance issues with inline styles and added Google Maps documentation.<\/p>","1.3.1":"<p>Fixed Plugin Check errors. Font Awesome is no longer auto-loaded - ensure your theme includes it or install a Font Awesome plugin.<\/p>","1.3.0":"<p><strong>Important:<\/strong> All shortcode names have changed from <code>[a1_*]<\/code> to <code>[a1tools_*]<\/code>. Please update your shortcodes after upgrading. Example: <code>[a1_var]<\/code> is now <code>[a1tools_var]<\/code>.<\/p>","1.2.0":"<p>New Social Icons Widget with full styling customization. Enhanced shortcode with style, shape, size, and hover effect options.<\/p>","1.1.0":"<p>Added 6 new social media platforms: Pinterest, BBB, Nextdoor, Houzz, Angi, Thumbtack.<\/p>","1.0.9":"<p>Added settings page with configurable cache duration and manual cache clear button. Default cache reduced to 5 minutes.<\/p>","1.0.8":"<p>Added city name, state, and Google Maps location fields with new shortcodes.<\/p>","1.0.0":"<p>Initial release of A1 Tools plugin.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3453106,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3453106,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-772x250.png":{"filename":"banner-772x250.png","revision":3453106,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.10.0","1.3.2","1.4.0","1.4.1","1.4.10","1.4.11","1.4.12","1.4.13","1.4.14","1.4.2","1.4.3","1.4.4","1.4.5","1.4.6","1.4.7","1.4.8","1.4.9","1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.5.5","1.5.6","1.5.7","1.5.8","1.5.9","1.6.0","1.6.1","1.6.2","1.6.3","1.6.4","1.6.5","1.6.6","1.6.7","1.6.8","1.6.9","1.7.0","1.7.1","1.7.2","1.7.3","1.7.4","1.7.5","1.7.6","1.7.7","1.7.8","1.7.9","1.8.0","1.8.1","1.8.2","1.8.3","1.8.4","1.8.5","1.8.6","1.9.0","1.9.1","1.9.2","1.9.3","1.9.4","1.9.5","1.9.6","1.9.7","1.9.8","1.9.9","2.0.0","2.0.1","2.0.2","2.0.4","2.0.5","2.0.6","2.0.7","2.1.5","2.1.6","2.2.0","2.3.0","2.4.0","2.4.1","2.4.2","2.4.3","2.5.0","2.5.10","2.5.2","2.5.20","2.5.26","2.5.3","2.5.4","2.5.5","2.5.6","2.5.7","2.5.8","2.5.9","2.6.0","2.6.1","3.2.0","3.2.11","3.2.12","3.2.8","3.3.0","3.3.2","3.3.3","3.3.4","3.3.5"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"Site Variables management in A1 Tools dashboard","2":"Using shortcodes in the WordPress editor","3":"Elementor dynamic tags integration"}},"plugin_section":[],"plugin_tags":[25998,1092,2686,357,255157],"plugin_category":[43,51],"plugin_contributors":[255158],"plugin_business_model":[],"class_list":["post-278012","plugin","type-plugin","status-publish","hentry","plugin_tags-business-information","plugin_tags-contact-info","plugin_tags-multi-site","plugin_tags-shortcodes","plugin_tags-site-variables","plugin_category-customization","plugin_category-multisite","plugin_contributors-a1tools","plugin_committers-a1tools"],"banners":{"banner":"https:\/\/ps.w.org\/a1-tools\/assets\/banner-772x250.png?rev=3453106","banner_2x":false,"banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/a1-tools\/assets\/icon-128x128.png?rev=3453106","icon_2x":"https:\/\/ps.w.org\/a1-tools\/assets\/icon-256x256.png?rev=3453106","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>A1 Tools connects your WordPress site to the A1 Tools platform, enabling centralized management of business information that can be displayed anywhere on your site using simple shortcodes.<\/p>\n\n<p><strong>Perfect for businesses with multiple websites<\/strong> - update your phone number, address, or social media links once in the A1 Tools dashboard, and all your connected sites update automatically.<\/p>\n\n<h4>Features<\/h4>\n\n<ul>\n<li><strong>Centralized Management<\/strong> - Manage all your site variables from one dashboard<\/li>\n<li><strong>Simple Shortcodes<\/strong> - Display any variable with <code>[a1tools_var key=\"phone_primary\"]<\/code><\/li>\n<li><strong>Address Formatting<\/strong> - Multiple address display formats available<\/li>\n<li><strong>Operating Hours<\/strong> - Display business hours as tables or lists<\/li>\n<li><strong>Social Media Links<\/strong> - Output all social icons with one shortcode or widget<\/li>\n<li><strong>Social Icons Widget<\/strong> - Customizable widget with style, shape, size, and hover effects<\/li>\n<li><strong>Elementor Support<\/strong> - Dynamic tags for Elementor page builder<\/li>\n<li><strong>Performance Optimized<\/strong> - Configurable caching (default 5 minutes)<\/li>\n<li><strong>Developer Friendly<\/strong> - PHP functions available for theme developers<\/li>\n<\/ul>\n\n<h4>Available Variables<\/h4>\n\n<ul>\n<li>Business name, city name, state\/location name, tagline<\/li>\n<li>Google Maps URL for location<\/li>\n<li>Primary and secondary phone numbers<\/li>\n<li>Primary and secondary email addresses<\/li>\n<li>Full address (line 1, line 2, city, state, ZIP, country)<\/li>\n<li>Social media URLs (Facebook, Instagram, YouTube, Twitter, LinkedIn, TikTok, Yelp, Google Business)<\/li>\n<li>Operating hours for each day of the week<\/li>\n<\/ul>\n\n<h4>Shortcode Examples<\/h4>\n\n<pre><code>[a1tools_var key=\"phone_primary\"] - Display primary phone number\n\n[a1tools_var key=\"facebook_url\" link=\"true\"] - Display Facebook URL as clickable link\n\n[a1tools_address format=\"full\"] - Display complete formatted address (multi-line)\n\n[a1tools_full_address] - Display full address in a single line (e.g., \"123 Main St, Suite 101, Miami, FL 30001\")\n\n[a1tools_hours format=\"table\"] - Display operating hours as a table\n\n[a1tools_social_links] - Display all configured social media icons\n\n[a1tools_social_links style=\"default\" shape=\"circle\" size=\"50\"] - Styled social icons\n\n[a1tools_city_name] - Display the city name for geo-targeting\n\n[a1tools_state] - Display the state name for geo-targeting\n\n[a1tools_google_map type=\"link\"] - Display Google Maps link\n\n[a1tools_google_map type=\"embed\" width=\"100%\" height=\"400\"] - Embed Google Maps iframe\n<\/code><\/pre>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>Your WordPress site must be registered in the A1 Tools platform<\/li>\n<li>An active A1 Tools account with site variables configured<\/li>\n<li>Font Awesome 6 for social icons (most themes include this; if not, use a Font Awesome plugin)<\/li>\n<\/ul>\n\n<h3>External Services<\/h3>\n\n<p>This plugin relies on a third-party service to retrieve site variables (business information, contact details, social media URLs, etc.) that you configure in the A1 Tools dashboard.<\/p>\n\n<h4>A1 Tools API<\/h4>\n\n<p><strong>What it is:<\/strong> A1 Tools is a business management platform operated by A1 Chimney Service that allows businesses to centrally manage their contact information, addresses, operating hours, and social media links across multiple websites.<\/p>\n\n<p><strong>What data is sent:<\/strong> When this plugin is activated and the site loads (or when a shortcode is used), the plugin sends your WordPress site URL to the A1 Tools API to retrieve the site variables you have configured for that specific site.<\/p>\n\n<p><strong>When data is sent:<\/strong>\n- When a page containing A1 Tools shortcodes is loaded\n- When the plugin's admin settings page is accessed\n- When the cache expires and fresh data is needed (configurable, default 5 minutes)<\/p>\n\n<p><strong>What data is received:<\/strong> The plugin receives only the site variables you have configured in your A1 Tools dashboard, such as business name, phone numbers, email addresses, physical address, operating hours, and social media URLs.<\/p>\n\n<p><strong>Service Provider:<\/strong> A1 Chimney Service\n<strong>API Endpoint:<\/strong> https:\/\/app.a-1chimney.com\/api\/website_variables.php\n<strong>Terms of Service:<\/strong> https:\/\/a-1chimney.com\/terms-of-service\/\n<strong>Privacy Policy:<\/strong> https:\/\/a-1chimney.com\/privacy-policy\/<\/p>\n\n<h4>Google Maps Embed API<\/h4>\n\n<p><strong>What it is:<\/strong> Google Maps is a web mapping service developed by Google. This plugin can embed Google Maps iframes to display your business location.<\/p>\n\n<p><strong>What data is sent:<\/strong> When using the <code>[a1tools_google_map type=\"embed\"]<\/code> shortcode, your visitor's browser loads an iframe from Google Maps containing your business address or place ID that you configured in the A1 Tools dashboard.<\/p>\n\n<p><strong>When data is sent:<\/strong>\n- Only when a page containing the <code>[a1tools_google_map type=\"embed\"]<\/code> shortcode is loaded\n- The embed is loaded client-side by the visitor's browser directly from Google<\/p>\n\n<p><strong>What data is received:<\/strong> Google Maps returns the embedded map showing your business location. Google may collect visitor data according to their privacy policy.<\/p>\n\n<p><strong>Service Provider:<\/strong> Google LLC\n<strong>Embed URL:<\/strong> https:\/\/www.google.com\/maps\/embed\/v1\/place\n<strong>Terms of Service:<\/strong> https:\/\/www.google.com\/intl\/en_us\/help\/terms_maps\/\n<strong>Privacy Policy:<\/strong> https:\/\/policies.google.com\/privacy<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>a1-tools<\/code> folder to the <code>\/wp-content\/plugins\/<\/code> directory<\/li>\n<li>Activate the plugin through the 'Plugins' menu in WordPress<\/li>\n<li>Ensure your site is registered in your A1 Tools dashboard under Integrations &gt; WordPress Sites<\/li>\n<li>Configure your site variables in A1 Tools under Marketing Tools &gt; Web Management &gt; Site Variables<\/li>\n<li>Use the shortcodes in your pages, posts, or widgets<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"how%20do%20i%20get%20an%20a1%20tools%20account%3F\"><h3>How do I get an A1 Tools account?<\/h3><\/dt>\n<dd><p>A1 Tools is a business management platform. Contact A1 Chimney Service for access information.<\/p><\/dd>\n<dt id=\"why%20are%20my%20variables%20not%20showing%3F\"><h3>Why are my variables not showing?<\/h3><\/dt>\n<dd><ol>\n<li>Verify your site URL in A1 Tools matches your WordPress site URL exactly (including https:\/\/)<\/li>\n<li>Check that you have saved variables for this site in A1 Tools<\/li>\n<li>Go to A1 Tools in your admin menu and click \"Clear Cache Now\" to fetch fresh data<\/li>\n<\/ol><\/dd>\n<dt id=\"how%20often%20do%20variables%20update%3F\"><h3>How often do variables update?<\/h3><\/dt>\n<dd><p>Variables are cached based on your settings (default 5 minutes). You can configure the cache duration or disable caching entirely in the A1 Tools settings page. To force an immediate update, use the \"Clear Cache Now\" button on the settings page.<\/p><\/dd>\n<dt id=\"can%20i%20use%20this%20with%20elementor%3F\"><h3>Can I use this with Elementor?<\/h3><\/dt>\n<dd><p>Yes! The plugin registers dynamic tags that appear under the \"A1 Tools\" group in Elementor. You can also use the Shortcode widget with any of the available shortcodes.<\/p><\/dd>\n<dt id=\"is%20this%20plugin%20free%3F\"><h3>Is this plugin free?<\/h3><\/dt>\n<dd><p>The plugin is free and open source. However, it requires an A1 Tools account to function, as it retrieves data from the A1 Tools platform.<\/p><\/dd>\n<dt id=\"what%20data%20does%20this%20plugin%20send%20to%20external%20services%3F\"><h3>What data does this plugin send to external services?<\/h3><\/dt>\n<dd><p>See the \"External Services\" section above for complete details. In summary, the plugin sends your site URL to the A1 Tools API to retrieve the site variables you have configured. No personal user data from your visitors is collected or transmitted.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>3.3.5<\/h4>\n\n<ul>\n<li>A1 Contact Info: business hours now fit whatever space they are given, instead of forcing a sideways scrollbar. When there is room, a day and its time sit on one line. When there is not, the whole time range drops onto its own line directly under that day \u2014 never beside it, never under the next day, and never split in the middle of a time. If even that is too tight, only the hours text shrinks, down to a readable floor, leaving your phone, email, address, titles and icons at their normal size. This adapts to how wide the widget itself is, not how wide the screen is, so hours placed in a narrow column behave correctly on a large monitor. Your saved Day and Time typography stays the normal size and is never overwritten.<\/li>\n<li>A1 Contact Info: removed the colon after each day name, so rows read \"Monday 8:00 AM - 10:00 PM\".<\/li>\n<\/ul>\n\n<h4>3.3.4<\/h4>\n\n<ul>\n<li>A1 Web Chat: the widget now tells A1 Tools when a visitor closes the chat or leaves the page, so the dispatcher answering them can see whether anyone is still on the other end. A live chat has no hangup \u2014 a visitor who shuts the tab leaves a conversation that looks exactly like one where they are still waiting, and dispatchers were composing careful replies to people who had left hours earlier. Uses the browser's beacon API, which costs nothing on the page and does not delay it unloading. Nothing to configure, and the chat behaves exactly as before for the visitor.<\/li>\n<\/ul>\n\n<h4>3.3.3<\/h4>\n\n<ul>\n<li>A1 Gallery: the <strong>View Our Projects<\/strong> button now sits below the Our Work pagination instead of above the grid, and <strong>Back to Our Work<\/strong> likewise sits at the bottom of the Projects view. Both are centered at every screen size, and both got the same larger treatment \u2014 bigger bold text, roomier padding, square corners, yellow with black text, turning orange on hover and on keyboard focus. Switching views, filtering, search, the lightbox, and pagination all work exactly as before.<\/li>\n<li>A1 Contact Info: business hours now read as one compact line per day \u2014 <code>Monday: 8:00 AM - 10:00 PM<\/code> \u2014 instead of a day column separated from the time by a large gap. A time can no longer wrap onto a second line. The old <strong>Day Column Width<\/strong> slider is gone, since it was the control that created that gap; existing widgets pick up the new layout with nothing to re-save.<\/li>\n<li>A1 Contact Info: Phone, Email, and Location each gained an <strong>Additional \u2026<\/strong> repeater, so a site can list several numbers, addresses, or offices under one icon and heading. Each entry takes an optional label (\"Sales\", \"Warehouse\") and its own click-to-call \/ mailto \/ Google Maps toggle. The value from A1 Tools stays the first entry; extras stack underneath it in the order you set and inherit the widget's existing typography, colors, and link styling. A new <strong>Value Spacing<\/strong> control in the Layout section sets the gap. Widgets with no extra entries render exactly as before.<\/li>\n<li>A1 Team: bios reliably appear when <strong>Show Bio<\/strong> is on. Sites still holding a team payload cached from before bios were served showed none of them, which looked like the switch was broken; this update refreshes that cache on upgrade.<\/li>\n<li>Fix: the plugin's internal version constant said 3.3.1 while the plugin header said 3.3.2, so WordPress and the plugin disagreed about which version was installed and the upgrade routine re-ran on every page load. Both now read the same value.<\/li>\n<\/ul>\n\n<h4>3.3.2<\/h4>\n\n<ul>\n<li>A1 Tools moved to a new address. Every endpoint this plugin calls now points at app.a-1chimney.com instead of tools.a-1chimney.com. Nothing changes on your site and no settings need updating \u2014 the old address still forwards, but this update means your site stops depending on that forward.<\/li>\n<\/ul>\n\n<h4>3.3.1<\/h4>\n\n<ul>\n<li>Fix: Edits made in A1 Tools now reach the live site immediately instead of being delayed by up to 5 minutes. The API serves its public endpoints with a 5-minute edge cache (deliberately \u2014 it keeps every page render across the fleet off PHP-FPM), which meant clearing the plugin's own transient just refetched the same URL and got the same stale JSON straight back. The plugin now carries a cache epoch in the request URL that moves only when the platform invalidates data, so the edge misses exactly once per real change and then caches normally again. Steady-state request volume is unchanged \u2014 this is not a per-request cache buster.<\/li>\n<li>Fix: Clearing the cache now also purges the HOST page cache (SiteGround Optimizer, plus WP Rocket \/ LiteSpeed \/ W3TC \/ WP Super Cache), not just the plugin's own transients. Previously the plugin refetched fresh data but the server kept serving already-rendered HTML, so a changed phone number or address did not appear on the live site until that cache expired on its own \u2014 making \"Refresh live cache\" in A1 Tools look like it had done nothing. This applies to both the manual refresh and the automatic invalidation that fires on every save, so edits now reach the live site without anyone opening Site Tools. Every third-party call is guarded, so a site with no caching plugin is unaffected.<\/li>\n<\/ul>\n\n<h4>3.3.0<\/h4>\n\n<ul>\n<li>Feature: Phone numbers now resolve through a three-tier cascade instead of two. A site can set one number for ALL city pages and another for ALL location pages (Information tab in A1 Tools), sitting between the individual page's own phone and the site's Primary Phone. Order: the page's own phone -&gt; the all-cities \/ all-locations default -&gt; Primary Phone, with every blank tier skipped. This lets a site route every city page to a single tracking number without editing each city, while any individual city can still claim its own. Every consumer inherits it \u2014 [a1tools_phone], [a1tools_city_phone], [a1tools_location_phone], the Elementor dynamic tag, and the Contact Info \/ Info Box \/ CTA widgets. Fully additive: a site that sets neither default behaves exactly as before.<\/li>\n<li>Fix: A1 Info Box no longer prints \"(Not configured)\" on the live site when its variable is empty \u2014 an unconfigured value now renders nothing at all (no icon, no title, no wrapper). Previously a site with, for example, no state set displayed that placeholder to visitors, leaking the CMS's internal state. The Elementor editor still shows the placeholder so the widget stays selectable while building a page.<\/li>\n<\/ul>\n\n<h4>3.2.12<\/h4>\n\n<ul>\n<li>Improvement: A1 Gallery \u2014 the \"Our Work\" landing tiles now have a controllable height. New \"Our Work Image Height\" responsive slider (default 360px desktop \/ 300 tablet \/ 240 mobile) drives the work-item height, with CSS defaults so existing galleries render at a consistent 360px cover-fit until adjusted. Completes the two-view Our Work \/ Our Projects reference. Fully additive; no existing setting changes. (#142, Toula)<\/li>\n<\/ul>\n\n<h4>3.2.11<\/h4>\n\n<ul>\n<li>Improvement: A1 Gallery widget now supports an optional \"Our Work\" landing gallery in addition to the existing Projects gallery, giving the widget two views. New \"Our Work Landing Gallery\" Elementor section adds an Our Work Images gallery (shown first, no search\/filters), an Our Work images-per-page count, and customizable Projects\/Back button labels. Visitors land on Our Work, tap \"View Our Projects\" to reach the existing search\/category\/before-after Projects view, and return with \"Back to Our Work\". Both views use compact pagination (first\/last + neighbors with ellipses) instead of listing every page. Fully additive \u2014 the widget, its name, and every existing setting (Images, Bulk Add by Category, layout, search\/filter, lightbox, pagination) are unchanged, so with no Our Work images selected the gallery renders exactly as before. (#141, Toula)<\/li>\n<\/ul>\n\n<h4>3.2.10<\/h4>\n\n<ul>\n<li>Improvement: review-URL fallback chain in a1tools_resolve_review_url() (shared by the A1 Review Funnel and A1 Smiley Reviews). Resolution is now: widget override \u2192 site review_url variable \u2192 google_business_url variable \u2192 new a1tools_fallback_review_url option \u2192 (a-1chimney.com hosts only, host-gated) the main A-1 Chimney Google review link. Sites without their own Google listing always render the \"Leave a Review on Google\" button instead of a bare thank-you; non-chimney brands are unaffected (the last step matches the exact apex or a real subdomain only). Folds the fleet-deployed 3.2.9 behaviour into the canonical source. (3.2.9 was a fleet-only roll of this code with no other changes.)<\/li>\n<\/ul>\n\n<h4>3.2.8<\/h4>\n\n<ul>\n<li>New: A1 Smiley Reviews Elementor widget \u2014 a happy-face \/ sad-face review gate. Happy face reveals a positive panel (\"So glad we hit the mark!\" + a Leave-a-Review-on-Google button using the same review-URL resolution as the A1 Review Funnel); sad face reveals the private feedback form (name\/phone\/email\/feedback) that POSTs to the same REST proxy with rating=1 \/ outcome=private_feedback, landing in the A1 Tools CRM. After private feedback the public review link is still offered (FTC \/ Google review-gating compliant). Classic outlined SVG smileys (green\/red, currentColor) or emoji, sad-left\/happy-right default with a swap toggle, perfect-circle disc construction, full Elementor style controls, honeypot + minimum-fill-time spam guards. Own namespace\/assets \u2014 the Review Funnel is untouched. Folds the cle-tested 3.2.7 widget into the canonical source so wordpress.org auto-updates ship it fleet-wide.<\/li>\n<\/ul>\n\n<h4>3.2.2<\/h4>\n\n<ul>\n<li>New: A1 Gallery Elementor widget \u2014 a searchable, filterable image grid. Two inputs feed one grid: a per-image repeater (image + category + optional before\/after split) and a \"Bulk Add by Category\" repeater (multi-select gallery, drop many images at once per category). Frontend: a live search box + an auto-populated category dropdown (apply together), responsive columns, pagination, category hover-highlight, image hover zoom, and click-to-enlarge lightbox. Independent Style sections for the Search vs Filter bar (Normal\/Hover\/Active states + responsive width). All client-side (no AJAX), no jQuery, Elementor Free and Pro. Folds the cle-tested widget into the canonical source so wordpress.org auto-updates ship it fleet-wide.<\/li>\n<\/ul>\n\n<h4>3.2.0<\/h4>\n\n<ul>\n<li>New: A1 Video Carousel Elementor widget \u2014 a self-contained, dependency-free vertical (9:16) YouTube Shorts carousel. Real YouTube IFrame players (overlay visible, one-video-at-a-time playback coordination), responsive slides-per-view, arrows\/dots\/drag, autoplay, custom thumbnails with an auto-filled YouTube-style title bar (title\/channel\/avatar via oEmbed, no API key). Folds the previously hand-deployed 2.7.x widget into the canonical source so wordpress.org auto-updates no longer drop it.<\/li>\n<\/ul>\n\n<h4>3.1.0<\/h4>\n\n<ul>\n<li>New: reusable content blocks. Author a named snippet in the SEO app's Content tab and print it on any page with [a1tools_content key=\"\"]. Rich text \/ safe HTML (wp_kses_post), nested shortcodes supported, optional wpautop=\"no\". Fetched from site_content_blocks.php and cached like other entities; cleared on cache invalidation.<\/li>\n<\/ul>\n\n<h4>3.0.1<\/h4>\n\n<ul>\n<li>A1 Contact Info widget: added an optional License item (icon + title + license number), pulling the same value as [a1tools_licence]. Shown by default; toggle off per instance.<\/li>\n<\/ul>\n\n<h4>3.0.0<\/h4>\n\n<ul>\n<li>Major version rollup \u2014 no functional change over 2.8.0. Consolidates the SEO shortcode release: per-field franchise\/service shortcodes (2.7.0) and context-aware base widgets that show a City\/Location page's own value with fallback to the main-phase value (2.8.0).<\/li>\n<\/ul>\n\n<h4>2.8.0<\/h4>\n\n<ul>\n<li>New: Context-aware base widgets\/shortcodes. On a City or Location page that has its own value assigned, base widgets now display THAT page's value instead of the main-phase value, and fall back to the main value where the page leaves a field blank. Example: [a1tools_phone] (and the A1 Phone \/ Contact Info \/ Info Box widgets and the \"A1 Site Variable\" dynamic tag) shows Stamford's phone on the Stamford page, but the company's main phone everywhere else \u2014 no per-page shortcode swap needed.<\/li>\n<li>Applies to every base field that has a City\/Location equivalent: phone (phone_primary), full address (full_address + address_line1\/line2\/city\/state\/zip), city, and state. A page is always exclusively a City page OR a Location page (distinct author accounts), so there is never any ambiguity about which record supplies the value.<\/li>\n<li>Unchanged: the WordPress admin preview and the \/site-variables REST endpoint still return the site-global (main-phase) values.<\/li>\n<\/ul>\n\n<h4>2.7.0<\/h4>\n\n<ul>\n<li>New: Per-field shortcodes for Franchise and Service data, so every editable field in the A1 Tools Web Management SEO tabs has a matching shortcode (surfaced inline with a copy button next to each field).<\/li>\n<li>New (Franchise, id-keyed \u2014 franchises render as cards with no dedicated page): [a1tools_franchise_name], [a1tools_franchise_phone] (link=\"yes\" = tel:), [a1tools_franchise_address] (full multi-line), [a1tools_franchise_address_line1], [a1tools_franchise_address_line2], [a1tools_franchise_city], [a1tools_franchise_state], [a1tools_franchise_zip], [a1tools_franchise_country], [a1tools_franchise_maps_url] (link=\"yes\" = Get Directions), [a1tools_franchise_latitude], [a1tools_franchise_longitude]. All require id=\"X\" (the franchise record id) and accept default and class.<\/li>\n<li>New (Service, auto-detecting like [a1tools_city_<em>]\/[a1tools_location_<\/em>] \u2014 service pages are WordPress pages): [a1tools_service_title], [a1tools_service_description], [a1tools_service_phone] (link=\"yes\" = tel:), [a1tools_service_icon], [a1tools_service_image]. Detect the current page via get_the_ID(); optional page_id=\"X\" targets a specific service page. Accept default and class.<\/li>\n<\/ul>\n\n<h4>2.6.9<\/h4>\n\n<ul>\n<li>New: Seven value-shortcodes for served SEO data \u2014 [a1tools_business_name] (business_name), [a1tools_tagline] (tagline), [a1tools_phone] (phone_primary), [a1tools_phone_secondary] (phone_secondary), [a1tools_email] (email_primary), [a1tools_email_secondary] (email_secondary), and [a1tools_review_link] (review_url). Phones support link=\"yes\" (tel:), emails support link=\"yes\" (mailto:, scraper-obfuscated), and [a1tools_review_link] supports link=\"yes\" with an optional text=\"...\" label. All accept default and (text shortcodes) class attributes and output nothing when the value is empty.<\/li>\n<\/ul>\n\n<h4>2.6.8<\/h4>\n\n<ul>\n<li>Fix: A1 Team widget - \"Center Rows\" was forcing every group to 3 columns regardless of the Columns setting. The centered (flex) layout reads the <code>--a1-team-cols<\/code> CSS variable, but in Elementor that variable was never emitted (Elementor doesn't reliably output per-element custom properties), so it fell back to the hard-coded default of 3. The variable is now set inline in the rendered markup as the single source of truth, so 4 (or any value) is honored. Also added responsive breakpoints to the centered layout (2 columns on tablet, 1 on phones), which it previously lacked entirely. Supersedes the incomplete 2.6.6 attempt.<\/li>\n<\/ul>\n\n<h4>2.6.7<\/h4>\n\n<ul>\n<li>Fix (compliance): Review funnel no longer gates by rating. Low (1-3) ratings keep the private \"make it right\" feedback form, and on submit are ALSO offered the public Google review \u2014 the public option is never hidden based on rating. Removes the review-gating pattern targeted by the FTC's 2024 Consumer Review Rule and FTC Act Section 5.<\/li>\n<\/ul>\n\n<h4>2.6.6<\/h4>\n\n<ul>\n<li>Fix: A1 Team widget - \"Center Rows\" now shows the full column count (was 1 short). Responsive Columns now apply correctly on tablet\/mobile (were collapsing to 1 column). Added a Width (%\/px) control for square photos, so photo width is settable in % on either shape.<\/li>\n<\/ul>\n\n<h4>2.6.5<\/h4>\n\n<ul>\n<li>New: A1 Team widget - Photo Size now supports % width (stays circular via aspect-ratio). Columns now default to responsive 4 \/ 2 \/ 1 (desktop \/ tablet \/ mobile). New \"Center Rows\" toggle centers an incomplete last row (e.g. 3 cards under 4 columns).<\/li>\n<\/ul>\n\n<h4>2.6.4<\/h4>\n\n<ul>\n<li>Improve: Review funnel (4-5\u2605) \u2014 submitting the positive form now <em>replaces<\/em> it with a clean \"Thank you! \ud83c\udf89 \/ Leave a review in Google\" step instead of showing the prompt below the form. Removed the duplicated message; the pre-submit form now has its own \"So glad we hit the mark!\" header.<\/li>\n<\/ul>\n\n<h4>2.6.3<\/h4>\n\n<ul>\n<li>Change: A1 Review Funnel \u2014 the positive (4-5) \"Send\" no longer auto-opens Google. After submitting, a thank-you shows with an optional \"Leave a review\" button the visitor clicks to open Google (their note is still copied so they can paste it).<\/li>\n<li>Change: A1 Review Funnel \u2014 a CRM row is now created only when the form is submitted, not on the star tap. Abandoned star taps no longer create \"Anonymous\" rating-only rows; submitting saves the rating + contact + comment in one step.<\/li>\n<\/ul>\n\n<h4>2.6.2<\/h4>\n\n<ul>\n<li>New: A1 Review Funnel \u2014 high ratings (4-5) now open a short form (name, phone, email, comment) too. On submit the details are saved to the CRM (Customer Experience) and the visitor is taken to Google to post their review; their comment is copied to the clipboard to paste in. (Google does not allow pre-filling the star rating or review text via a link, so they pick their stars and paste on Google.)<\/li>\n<li>Change: A1 Review Funnel \u2014 every field on both the positive and negative forms is now required.<\/li>\n<li>Change: A1 Review Funnel \u2014 the \"Or leave a public review\" link no longer appears on the low-rating (1-3 star) feedback form. The public-review link now shows only on high ratings (4-5); low ratings see the private feedback form only. (Note: routing only happy customers to public reviews is \"review gating\", which can conflict with Google's review policy and the FTC's 2024 review rule \u2014 this is an intentional change at the site owner's request.) Also removed the now-unused \"Show public-review link on low ratings\" toggle, the secondary-link text control, and its style control + CSS.<\/li>\n<\/ul>\n\n<h4>2.6.1<\/h4>\n\n<ul>\n<li>Fix: A1 Review Funnel - the rating stars rendered as padded yellow buttons and sat left of center on Elementor sites. The active theme's Elementor global-kit button styling out-specified the widget's star reset (<code>.elementor-kit-N button<\/code> beats a bare <code>.a1tools-review__star<\/code>), so each star inherited the theme button's background and 15px 50px padding, which also pushed the star row wider than its container and broke the centering. The star rules are now scoped under <code>.a1tools-review<\/code> so they win on specificity alone (no !important needed), with a full button-property reset - stars render as clean glyphs and center correctly across themes.<\/li>\n<\/ul>\n\n<h4>2.6.0<\/h4>\n\n<ul>\n<li>New: A1 Review Funnel \u2014 a star-rating widget that turns happy customers into public reviews and unhappy ones into private feedback. Visitors pick 1-5 stars; high ratings get a thank-you with a button to your public review link, while low ratings open a private feedback form (name \/ phone \/ email \/ comment) that lands in the A1 Tools CRM under the new \"Customer Experience\" tab.<\/li>\n<li>New: Available as the \"A1 Review Funnel\" Elementor widget (full styling controls \u2014 stars, panels, inputs, buttons, colors, typography) and the [a1tools_review_widget] shortcode.<\/li>\n<li>New: Optional site-wide floating \"Rate us\" button (A1 Tools \u2192 Reviews) that opens the funnel in a popup on every page \u2014 no page editing required. Configurable position, label, prompt, and threshold.<\/li>\n<li>New: Review Link (review_url) site variable (Site Variables \u2192 Social Media) for the public review destination, with automatic fallback to the Google Business URL.<\/li>\n<li>Compliance: the funnel never blocks unhappy customers from leaving a public review \u2014 low ratings always keep a secondary public-review link. Hiding it (\"review gating\") violates Google's review policies and the FTC's 2024 review-suppression rule, so the option to do so is intentionally not provided.<\/li>\n<li>Privacy\/anti-spam: submissions are signed server-side (HMAC) via a REST proxy, with an in-form honeypot and minimum-fill-time guard. No third-party review service is used.<\/li>\n<\/ul>\n\n<h4>2.5.31<\/h4>\n\n<ul>\n<li>Fix: Live Chat widget \u2014 visitors no longer see \"no chat button\" on pages cached during off-hours. Earlier versions (2.5.12 \u2013 2.5.30) had PHP render zero HTML outside business hours so the widget never appeared; SiteGround SuperCacher \/ Cloudflare \/ WP Rocket would cache that empty version and re-serve it to business-hours visitors, who saw nothing. The JS-side gate added in 2.5.27 couldn't rescue it \u2014 it can only hide existing widget HTML, not materialise widget HTML PHP never rendered. New architecture: PHP ALWAYS renders the widget HTML (cache-safe), styled <code>display:none<\/code> initially with a <code>data-bh-gate=\"1\"<\/code> attribute. The JS at init checks the visitor's clock (converted to Miami time via <code>Intl.DateTimeFormat<\/code> with <code>timeZone: 'America\/New_York'<\/code>), and either reveals the placement (within hours) or removes it from the DOM (outside hours \/ weekend). Elementor editor and preview modes bypass the gate so admins can always style the widget regardless of the current hour.<\/li>\n<li>Change: Live Chat business-hours cutoff rolled back to 4 PM Miami time (was extended to 5 PM in 2.5.13 at user's earlier request, now reverted per current user request). Schedule is now Monday \u2013 Friday, 9:00 AM \u2013 3:59 PM America\/New_York. At 4:00 PM the widget disappears.<\/li>\n<\/ul>\n\n<h4>2.5.30<\/h4>\n\n<ul>\n<li>Fix: Web Chat widget continued polling after the dispatcher resolved\/abandoned a session. <code>handleSessionClosed<\/code> aborted the in-flight fetch, but <code>state.sessionId<\/code> was never nulled, so the <code>while (state.sessionId &amp;&amp; state.windowOpen)<\/code> loop re-entered immediately, fetched again, got back <code>status=abandoned<\/code>, sleep, repeat \u2014 the actual driver of the 255k-request runaway under 2.5.28. Nulling <code>state.sessionId<\/code> in <code>handleSessionClosed<\/code> flips the loop condition false on the next iteration and the loop exits cleanly. The 2.5.29 poll-interval is still in place as defense in depth.<\/li>\n<\/ul>\n\n<h4>2.5.29<\/h4>\n\n<ul>\n<li>Fix: Web Chat widget poll loop had no sleep between successful iterations \u2014 once a visitor opened the chat the browser hammered <code>?action=poll<\/code> ~3 times per second forever (one customer logged 255,033 requests in 24 hours before SiteGround's WAF served the anti-bot challenge to the whole host). Added a 3-second interval between successful polls + made the sleep abort-aware so closing the chat tears down immediately instead of waiting the full interval.<\/li>\n<\/ul>\n\n<h4>2.5.28<\/h4>\n\n<ul>\n<li>Improve: Web Form widget \u2014 custom fields of type \"Date\" or \"Time\" now render with a proper popup picker (powered by the bundled flatpickr 4.6.13 library, MIT) instead of the native HTML5 input. The browser-native time input puts AM\/PM as a hidden third tab-stop that visitors don't realise they need to focus, so they type a time, hit submit, and the form carries an ambiguous meridian. Flatpickr renders AM\/PM as a clearly labeled toggle pill inside a popup \u2014 impossible to miss. Date inputs get a clean month calendar. Both pickers work consistently across browsers and mobile devices. Fails open: if the flatpickr JS doesn't load for any reason (CSP, slow network, etc.), the native HTML5 input keeps working as the fallback.<\/li>\n<\/ul>\n\n<h4>2.5.27<\/h4>\n\n<ul>\n<li>Fix: Live Chat business-hours gate now also closes on Saturday and Sunday. The 2.5.12 implementation only checked the 9 AM \u2013 5 PM hour window and ignored day-of-week, so the chat rendered on weekends as long as the hour fell inside the staffed window. Now Monday \u2013 Friday, 9 AM \u2013 5 PM Miami time (America\/New_York, automatically tracking EST\/EDT).<\/li>\n<li>Fix: Live Chat business-hours gate now survives page caching. The PHP gate alone was being bypassed on every site running SiteGround SuperCacher \/ WP Rocket \/ Cloudflare full-page cache \u2014 once a page was cached during business hours, every later visitor (off-hours, weekend, whenever) got the cached HTML with the chat button visible. The widget JS now re-checks the schedule on every page load using <code>Intl.DateTimeFormat<\/code> with <code>timeZone: 'America\/New_York'<\/code> and strips the chat placement from the DOM if outside hours, so cached pages honour the schedule too.<\/li>\n<\/ul>\n\n<h4>2.5.26<\/h4>\n\n<ul>\n<li>New: real-time cache invalidation via webhook (Layer C of the 2026-05-25 outage hardening pass). On activation\/upgrade the plugin now generates a per-site 256-bit HMAC secret, registers it with the central A1 Tools server, and exposes <code>POST \/wp-json\/a1-tools\/v1\/invalidate-cache<\/code>. When an admin saves any variable \/ store \/ franchise \/ city page \/ service \/ review \/ before-after \/ team member \/ FAQ \/ SEO location on the central server, that server pushes an HMAC-signed ping here within milliseconds and the matching transient is cleared on the spot. End result: variable edits propagate to live customer pages in seconds instead of waiting up to 30 minutes for the cache to expire. The 30-min cache TTL + 5-min CDN cache remain in place as the safety net if a ping is missed.<\/li>\n<\/ul>\n\n<h4>2.5.25<\/h4>\n\n<ul>\n<li>Performance \/ reliability: hardening pass on the data-fetch layer triggered by the 2026-05-25 central-server outage. The outage was caused by sites with caching disabled hammering the upstream API on every page render until the central PHP-FPM pool exhausted. Three coordinated changes here:\n\n<ul>\n<li>Stampede protection in <code>a1tools_fetch_api_data()<\/code>: when N concurrent Apache workers on the same site hit an expired transient at the same instant, a short lock transient now lets exactly one worker refill the cache while the others return the stale fallback. Lock TTL (20s) &gt; <code>wp_remote_get<\/code> timeout (15s) so a dying request can't hold the lock indefinitely.<\/li>\n<li>Per-request memoization via a static array in the same function. Pages with many shortcodes\/widgets that each call into the data layer (a header with 8 <code>[a1tools_var]<\/code> tags, for example) now hit the transient backend exactly once per page render instead of once per shortcode.<\/li>\n<li>The \"No caching (always fresh)\" and \"1 minute\" options were removed from the Cache Duration dropdown. They were the root cause of the upstream overload \u2014 a few sites with caching disabled generated enough volume to bring the central server down. Default cache duration bumped 5 min \u2192 30 min. A migration coerces any existing <code>a1tools_cache_expiry = 0<\/code> to the new default on plugin upgrade.<\/li>\n<\/ul><\/li>\n<\/ul>\n\n<h4>2.5.24<\/h4>\n\n<ul>\n<li>New: Web Form widget \u2192 Title &amp; Subtitle style section gains per-breakpoint Alignment controls (Desktop \/ Tablet \/ Mobile, with Left \/ Center \/ Right options). Lets editors center the hero title on desktop while keeping it left-aligned on mobile (or any combination). Default empty inherits whatever the parent column dictates, so existing forms render unchanged.<\/li>\n<\/ul>\n\n<h4>2.5.23<\/h4>\n\n<ul>\n<li>New: Web Form widget \u2192 Container style section gains a \"Border color (hover)\" control, sitting directly below the normal Border group. Pairs a fade transition (<code>border-color 180ms ease<\/code>) on the wrap so the swap is smooth instead of snapping. Matches the existing Submit Button's Normal \/ Hover pattern so editors expecting hover states on bordered elements get a consistent experience.<\/li>\n<\/ul>\n\n<h4>2.5.22<\/h4>\n\n<ul>\n<li>Fix: Web Form widget \u2014 Submit Button \"Full width\" alignment now actually renders full-width. The 2.5.2 implementation used <code>justify-content: stretch<\/code> (which isn't a valid value for <code>justify-content<\/code> \u2014 only <code>align-items<\/code>\/<code>align-content<\/code> accept it, so browsers silently dropped it and fell back to <code>flex-end<\/code>) paired with a <code>[data-align=\"full\"]<\/code> attribute selector for the <code>width: 100%<\/code> rule (which never matched in Elementor's live editor preview because the editor only re-injects CSS, not HTML, until you save + reload). Both alignment and width now flow through CSS variables (<code>--submit-justify<\/code>, <code>--submit-width<\/code>) that Elementor emits on the <code>.a1tools-web-form__actions<\/code> wrapper, so the button responds in real time to the alignment toggle in the editor sidebar AND on the published page. Left \/ Center \/ Right also pick up the same variable plumbing for consistency.<\/li>\n<\/ul>\n\n<h4>2.5.21<\/h4>\n\n<ul>\n<li>New: Web Form widget \u2014 Custom Fields type whitelist gains a \"Time\" option (renders an <code>&lt;input type=\"time\"&gt;<\/code>). Useful alongside the existing Date type for appointment-preference or booking-window forms. Server-side validator in the A1 Tools CRM API extended in lock-step so the new type round-trips into <code>crm_web_form_submissions.custom_fields<\/code> cleanly.<\/li>\n<li>New: Web Form widget \u2014 per-field responsive Column Width control on BOTH Standard Fields and Custom Fields repeaters. Each row exposes a Desktop \/ Tablet \/ Mobile dropdown (100% \/ 75% \/ 66% \/ 50% \/ 33% \/ 25%) so editors can lay out e.g. First Name + Last Name side-by-side on desktop while remaining stacked on mobile. Tablet inherits Desktop, Mobile inherits Tablet, unless explicitly set. Under the hood the form switches from single-column flex to a 12-column CSS grid; existing forms render unchanged (each field defaults to full-width).<\/li>\n<\/ul>\n\n<h4>2.5.20<\/h4>\n\n<ul>\n<li>Maintenance: WP.org publish baseline catch-up. The wordpress.org SVN tags had drifted behind by 9 versions (2.5.11\u20132.5.19 were never tagged on the public plugin marketplace; sites updating from wordpress.org therefore still saw 2.5.10 as the latest available build). 2.5.20 republishes the current trunk so customer sites pick up everything between 2.5.10 and current in a single update. No behavioral changes vs 2.5.18 \u2014 see prior entries below for what shipped over the catch-up window (Web Leads \/ Live Chat overhaul, multi-tenant CRM scoping, franchise grid stabilization, etc.).<\/li>\n<\/ul>\n\n<h4>2.5.18<\/h4>\n\n<ul>\n<li>Improve: Franchise grid shortcode \u2014 when a franchise card has no street\/city\/state\/zip fields populated, the embedded map now falls back to <code>lat,lng<\/code> coordinates instead of using the franchise name as the search query (which would otherwise resolve to an unrelated \"A1 Chimney\" listing in another state). If neither address nor coordinates exist, the map is omitted entirely.<\/li>\n<li>Fix: Franchise grid card layout \u2014 cards become flex columns with <code>min-height: 2.5em<\/code> + <code>line-height: 1.25<\/code> on the title and <code>margin-top: auto<\/code> on the directions link. Stops the map iframe from jumping rows when one card has a single-line title and the neighbor has two lines.<\/li>\n<\/ul>\n\n<h4>2.5.17<\/h4>\n\n<ul>\n<li>Tweak: Live Chat default greeting copy \u2014 \"Hi! Thanks for reaching out \u2014 a team member will be with you in just a moment.\" \u2192 \"Hi! Thanks for reaching out, a team member will be with you as soon as possible.\" Dropped the em-dash for a comma-joined single thought, and softened the \"moment\" promise into \"as soon as possible.\" Per-widget override still wins \u2014 existing Elementor placements that already saved the old wording need to be edited (or cleared) in the widget admin to pick up the new default. A one-time migration on plugin activation also rewrites any saved Elementor postmeta values still carrying the old phrase to the new one.<\/li>\n<\/ul>\n\n<h4>2.5.16<\/h4>\n\n<ul>\n<li>Fix: Live Chat pre-chat form \u2014 name + phone-or-email fields rendered with the customer site's theme-default \"dark form\" styling (black background, white text) instead of the plugin's intended white-with-dark-text. Some Astra \/ Hello-Elementor child themes ship a <code>body input { background: #000; color: #fff }<\/code> rule that loads after the plugin's stylesheet and wins on cascade order. Hardened <code>.a1tools-web-chat-window__prechat input, textarea<\/code> with <code>!important<\/code> on background + color + border to defeat the theme cascade (same pattern as the 2.5.7 SVG-fill fix). The new \"How can we help?\" textarea was visually correct out of the box in 2.5.15 only because no theme had targeted a bare <code>textarea<\/code> element yet; it's now under the same shield for safety.<\/li>\n<\/ul>\n\n<h4>2.5.15<\/h4>\n\n<ul>\n<li>New: Live Chat pre-chat form \u2014 added a third field, \"How can we help?\" (label + required-flag + placeholder all configurable in the Elementor widget admin). The visitor types their first question or message before starting the chat. Server-side: the question is stored as the first <code>sender='visitor'<\/code> message in the conversation, between \"Chat started by \u2026\" and the auto-greeting, so the flow reads as: (1) system header, (2) visitor's question, (3) auto-reply \/ \"team member will be with you shortly.\" Dispatchers viewing the chat in the CRM Web Leads inbox see the visitor's intent immediately instead of having to ask \"what brings you here?\" once they pick up.<\/li>\n<\/ul>\n\n<h4>2.5.14<\/h4>\n\n<ul>\n<li>Improve: Live Chat  &hellip;<\/li>\n<\/ul>","raw_excerpt":"Centrally manage contact information, social media links, and business details across your WordPress sites from the A1 Tools platform.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/278012","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=278012"}],"author":[{"embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/a1tools"}],"wp:attachment":[{"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=278012"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=278012"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=278012"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=278012"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=278012"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ky.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=278012"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}