From 9dfd261e9829173e6f29469672ae0e3d83a69cf7 Mon Sep 17 00:00:00 2001 From: Sarah Mount Date: Tue, 4 Feb 2025 18:43:23 +0000 Subject: [PATCH] Check that ACF functions exist before use If this plugin is run via a request to wp-activate.php it will produce a 5xx error in our logs. This commit checks for the existance of ACF functions before they are used, and returns early from methods if ACF is not available. --- CHANGELOG.md | 6 ++++++ spec/options.spec.php | 27 +++++++++++++++++++++------ spec/scripts.spec.php | 35 +++++++++++++++++++++++++++++++++++ src/Options.php | 4 ++++ src/Scripts.php | 16 ++++++++++++++++ 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a9ccc8..028748f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +## Changed + +- When ACF is not available the plugin does not produce an error + ## [1.5.4] - 2024-11-28 ### Added diff --git a/spec/options.spec.php b/spec/options.spec.php index a7da94d..e201a4c 100644 --- a/spec/options.spec.php +++ b/spec/options.spec.php @@ -56,14 +56,29 @@ }); describe('->acfInit()', function () { - it('registers options', function () { - allow('acf_add_options_sub_page')->toBeCalled(); - expect('acf_add_options_sub_page')->toBeCalled(); + context('ACF is available', function () { + it('registers options', function () { + allow('function_exists')->toBeCalled()->andReturn(true); - allow('acf_add_local_field_group')->toBeCalled(); - expect('acf_add_local_field_group')->toBeCalled(); + allow('acf_add_options_sub_page')->toBeCalled(); + expect('acf_add_options_sub_page')->toBeCalled(); - $this->options->acfInit(); + allow('acf_add_local_field_group')->toBeCalled(); + expect('acf_add_local_field_group')->toBeCalled(); + + $this->options->acfInit(); + }); + }); + context('ACF is not available', function () { + it('registers options', function () { + allow('function_exists')->toBeCalled()->andReturn(false); + + expect('acf_add_options_sub_page')->not->toBeCalled(); + + expect('acf_add_local_field_group')->not->toBeCalled(); + + $this->options->acfInit(); + }); }); }); }); diff --git a/spec/scripts.spec.php b/spec/scripts.spec.php index 2155b81..4b1cffc 100644 --- a/spec/scripts.spec.php +++ b/spec/scripts.spec.php @@ -37,8 +37,16 @@ }); describe('->enqueueScripts()', function () { + context('ACF is not available', function () { + it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(false); + expect('get_field')->not->toBeCalled(); + $this->scripts->enqueueScripts(); + }); + }); context('Civic Cookie API Key is not set', function () { it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn(''); expect('get_field')->toBeCalled()->once()->with('civic_cookie_control_api_key', 'option'); $this->scripts->enqueueScripts(); @@ -47,6 +55,7 @@ context('Civic Cookie API Key is set', function () { context('but Civic Product Type is not set', function () { it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn('an_api_key', ''); expect('get_field')->toBeCalled()->once()->with('civic_cookie_control_api_key', 'option'); expect('get_field')->toBeCalled()->once()->with('civic_cookie_control_product_type', 'option'); @@ -56,6 +65,7 @@ context('and Civic Product Type is set', function () { context('but marketing scripts are not on', function () { it('enqueues the Civic Cookie Control script and the config and analytics scripts, and injects our settings, with the option to filter them', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn('an_api_key', 'a_product_type', 'a_ga_id', 'a_ga4_id', 'a_gtm_id', 'a_hjid', false, 'an_api_key', 'a_product_type'); expect('get_field')->toBeCalled()->times(2)->with('civic_cookie_control_api_key', 'option'); expect('get_field')->toBeCalled()->times(2)->with('civic_cookie_control_product_type', 'option'); @@ -88,6 +98,7 @@ context('and marketing scripts are on', function () { it('enqueues the Civic Cookie Control script and the config and analytics scripts, and injects our settings including the additional optional cookies, with the option to filter them', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn('an_api_key', 'a_product_type', 'a_ga_id', 'a_ga4_id', 'a_gtm_id', 'a_hjid', true, 'a list of marketing cookies', 'an_api_key', 'a_product_type'); allow('esc_js')->toBeCalled()->andRun(function ($input) { return $input; @@ -139,8 +150,17 @@ }); describe('->addGA4()', function () { + context('ACF is not available', function () { + it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(false); + expect('get_field')->not->toBeCalled(); + + $this->scripts->addGA4(); + }); + }); context('API Key is not set', function () { it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn(null, 'a_product_type', 'a_ga4_id'); ob_start(); @@ -152,6 +172,7 @@ }); context('product type is not set', function () { it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn('an_api_key', null, 'a_ga4_id'); ob_start(); @@ -163,6 +184,7 @@ }); context('GA4 ID is not set', function () { it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn('an_api_key', 'a_product_type', null); ob_start(); @@ -174,6 +196,7 @@ }); context('API Key, product type and GA4 ID are set', function () { it('outputs the GA4 script tag', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn('an_api_key', 'a_product_type', '123456'); allow('esc_attr')->toBeCalled()->andRun(function ($input) { return $input; @@ -189,8 +212,17 @@ }); describe('->addGTM()', function () { + context('ACF is not available', function () { + it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(false); + expect('get_field')->not->toBeCalled(); + + $this->scripts->addGTM(); + }); + }); context('API Key is not set', function () { it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn(null, 'a_product_type', 'a_gtm_id'); ob_start(); @@ -202,6 +234,7 @@ }); context('product type is not set', function () { it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn('an_api_key', null, 'a_gtm_id'); ob_start(); @@ -213,6 +246,7 @@ }); context('GTM ID is not set', function () { it('does nothing', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn('an_api_key', 'a_product_type', null); ob_start(); @@ -224,6 +258,7 @@ }); context('API Key, product type and GTM ID are set', function () { it('outputs the GTM script tag', function () { + allow('function_exists')->toBeCalled()->andReturn(true); allow('get_field')->toBeCalled()->andReturn('an_api_key', 'a_product_type', '123456'); allow('esc_js')->toBeCalled()->andRun(function ($input) { return $input; diff --git a/src/Options.php b/src/Options.php index b6c090e..ec0b0c2 100644 --- a/src/Options.php +++ b/src/Options.php @@ -35,6 +35,10 @@ public function validateTrimmedText($valid, $value, $field, $input_name) public function acfInit(): void { + if (!function_exists('acf_add_options_sub_page')) { + return; + } + acf_add_options_sub_page([ 'page_title' => 'Analytics with Consent', 'menu_slug' => 'analytics-with-consent', diff --git a/src/Scripts.php b/src/Scripts.php index 0526a48..7b7cb19 100644 --- a/src/Scripts.php +++ b/src/Scripts.php @@ -22,6 +22,10 @@ public function addActionLinks(array $links): array public function enqueueScripts(): void { + if (!function_exists('get_field')) { + return; + } + $apiKey = trim(get_field('civic_cookie_control_api_key', 'option')); $productType = trim(get_field('civic_cookie_control_product_type', 'option')); $googleAnalyticsId = trim(get_field('google_analytics_id', 'option')); @@ -49,6 +53,10 @@ public function enqueueStyles(): void public function addGA4(): void { + if (!function_exists('get_field')) { + return; + } + $apiKey = trim(get_field('civic_cookie_control_api_key', 'option')); $productType = trim(get_field('civic_cookie_control_product_type', 'option')); $ga4Id = trim(get_field('ga_4_id', 'option')); @@ -59,6 +67,10 @@ public function addGA4(): void public function addGTM(): void { + if (!function_exists('get_field')) { + return; + } + $apiKey = trim(get_field('civic_cookie_control_api_key', 'option')); $productType = trim(get_field('civic_cookie_control_product_type', 'option')); $gtmId = trim(get_field('google_analytics_gtm', 'option')); @@ -69,6 +81,10 @@ public function addGTM(): void private function defaultConfig(): array { + if (!function_exists('get_field')) { + return []; + } + $optionalCookies = [ [ 'name' => 'analytics',