Skip to content

fix: remove return type declarations from base classes to restore addon compatibility#780

Merged
superdav42 merged 2 commits intomainfrom
bugfix/base-gateway-return-type-compat
Apr 10, 2026
Merged

fix: remove return type declarations from base classes to restore addon compatibility#780
superdav42 merged 2 commits intomainfrom
bugfix/base-gateway-return-type-compat

Conversation

@superdav42
Copy link
Copy Markdown
Collaborator

@superdav42 superdav42 commented Apr 10, 2026

Summary

Fixes a fatal Compile Error on PHP 8.x that breaks the WooCommerce addon v2.0.22 (and potentially other addons) when upgrading to UM v2.5.1. Sites go completely down on any page load.

Root Cause

Two earlier commits added PHP return type declarations to public methods on base/abstract classes that external addons extend:

Commit What it did
b41dc2b2 "Use PHP 7.4 features" Added : void to setters (set_order, set_payment, set_membership, set_customer, trigger_payment_processed)
b8df0b85 "Add PayPal REST gateway" Added : string to URL methods (get_payment_url_on_gateway, get_subscription_url_on_gateway, get_customer_url_on_gateway)

PHP enforces that child class method signatures must be compatible with parent declarations. When a parent adds : string, any existing child class overriding that method without the return type causes:

Compile Error: Declaration of ChildClass::method($param)
must be compatible with ParentClass::method($param): string

This is a fatal error — no graceful degradation, site is completely down.

What Changed

Removed return type declarations from all overridable public methods across 6 base/abstract classes and their bundled subclasses (36 files total):

  • Base_Gateway (12 methods) — the confirmed breaking class
  • Base_Element (17 methods) — output(): void is abstract, every UI element addon must implement it
  • Base_Model (6 methods) — set_slug(), hydrate(), etc.
  • Base_Host_Provider (11 methods) — extended by hosting integration addons
  • Base_Capability_Module + Capability_Module interface (7 methods)
  • Base_Signup_Field (1 method)

All bundled subclasses (Stripe, PayPal, PayPal REST, all UI elements, host providers) also had their return types removed for consistency.

PHPDoc @return tags are preserved — IDEs and PHPStan still get type information.

Why Not Just Fix the Addon?

The addon fix is trivial (add : string to the override). But:

  1. The core plugin should not break existing addons with a minor release
  2. There are likely other addons and custom gateway implementations affected
  3. The Base_Element::output(): void abstract method would break every custom UI element addon
  4. Return types on extensible base classes are a semver-major change

Testing

  • PHPStan: zero new errors (15 pre-existing unrelated errors)
  • Verified child classes with return types (provider implementations) still pass — PHP allows a child to be more specific than its parent

Runtime Testing

  • Risk: Critical (payment gateway, site-down fatal)
  • Level: self-assessed — the fix is mechanical (removing type declarations), verified by PHPStan, and the failure mode is a PHP Compile Error that would be immediately visible

Summary by CodeRabbit

  • Refactor
    • Updated method signatures across gateway, integration, UI, and model classes to remove explicit return type and parameter type declarations while preserving existing functionality.

External gateway plugins that extend Base_Gateway without matching return
type declarations cause a PHP fatal error. Removing return types from the
abstract base class restores compatibility with third-party gateways while
keeping the concrete implementations (Stripe, PayPal) typed.
…store addon compatibility

PHP enforces that child class method signatures must be compatible with
parent declarations. When a parent adds a return type (e.g. ': string'),
any existing child class that overrides that method without the return
type causes a fatal Compile Error on PHP 8.x.

This broke the WooCommerce addon v2.0.22 (and potentially other addons)
when upgrading to UM v2.5.1, because Base_Gateway added ': string' to
get_payment_url_on_gateway() and other methods that addons override.

Removes return type declarations from all overridable public methods in:
- Base_Gateway (12 methods) + all bundled gateway subclasses
- Base_Element (17 methods) + all bundled element subclasses
- Base_Model (6 methods)
- Base_Host_Provider (11 methods) + DNS_Provider_Interface
- Base_Capability_Module (7 methods) + Capability_Module interface
- Base_Signup_Field (1 method)

Root cause: two commits added return types to existing public APIs:
- b41dc2b 'Use PHP 7.4 features' added void returns to setters
- b8df0b8 'Add PayPal REST gateway' added string returns to URL methods

PHPDoc @return tags are preserved for IDE/static analysis support.
Bundled subclasses that override these methods also have their return
types removed for consistency. External addon subclasses that already
added matching return types will continue to work (child can be more
specific than parent).

Reported-by: Kenedy (WC addon v2.0.22 fatal on UM v2.5.1)
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 10, 2026

📝 Walkthrough

Walkthrough

This PR systematically removes explicit PHP return type declarations and parameter type hints from method signatures across gateway, integration, model, and UI element classes. Internal logic and behavior remain unchanged; only type enforcement at the signature level is relaxed.

Changes

Cohort / File(s) Summary
Gateway Classes - Base & Implementations
inc/gateways/class-base-gateway.php, inc/gateways/class-base-paypal-gateway.php, inc/gateways/class-base-stripe-gateway.php, inc/gateways/class-paypal-gateway.php, inc/gateways/class-paypal-rest-gateway.php
Removed return type declarations (: void, : bool, : array, : string, : ?array) and parameter type hints (int, string) from public methods including set_order(), get_payment_method_display(), supports_payment_polling(), verify_and_complete_payment(), get_payment_url_on_gateway(), get_subscription_url_on_gateway(), get_customer_url_on_gateway(), and various setter methods.
Signup Fields & Model Classes
inc/checkout/signup-fields/class-base-signup-field.php, inc/models/class-base-model.php
Removed : void return type declarations from setter methods including set_attributes(), set_slug(), set_date_created(), set_date_modified(), set_migrated_from_id(), and lifecycle methods like hydrate().
Integration Base Classes
inc/integrations/class-base-capability-module.php, inc/integrations/interface-capability-module.php
Removed return type declarations and parameter types from capability module contract methods: supports(), set_integration(), get_integration(), get_supported_features(), register_hooks(), get_fields(), get_explainer_lines().
Host Provider Base & Interface
inc/integrations/host-providers/class-base-host-provider.php, inc/integrations/host-providers/interface-dns-provider.php
Removed return type declarations from host provider lifecycle and DNS management methods: init(), setup_constants(), test_connection(), supports_dns_management(), is_dns_enabled(), enable_dns(), disable_dns(), get_supported_record_types(), and parameter types from methods like get_zone_id().
Host Provider Implementations
inc/integrations/host-providers/class-cloudflare-host-provider.php, inc/integrations/host-providers/class-cpanel-host-provider.php, inc/integrations/host-providers/class-hestia-host-provider.php
Removed : void and : ?string return type declarations from host provider-specific methods: test_connection(), additional_hooks(), on_add_subdomain(), on_remove_subdomain(), on_add_domain(), on_remove_domain(), get_zone_id(), and removed parameter type hints.
UI Element Classes - Base & Implementations
inc/ui/class-base-element.php, inc/ui/class-account-summary-element.php, inc/ui/class-billing-info-element.php, inc/ui/class-checkout-element.php, inc/ui/class-command-palette-manager.php, inc/ui/class-current-membership-element.php, inc/ui/class-current-site-element.php, inc/ui/class-domain-mapping-element.php, inc/ui/class-invoices-element.php, inc/ui/class-limits-element.php, inc/ui/class-login-form-element.php, inc/ui/class-magic-link-url-element.php, inc/ui/class-my-sites-element.php, inc/ui/class-payment-methods-element.php, inc/ui/class-simple-text-element.php, inc/ui/class-site-actions-element.php, inc/ui/class-site-maintenance-element.php, inc/ui/class-template-previewer.php, inc/ui/class-template-switching-element.php, inc/ui/class-thank-you-element.php, inc/ui/class-toolbox.php, inc/ui/class-tours.php
Removed : void and : string return type declarations from output rendering and initialization methods: output(), init(), register_public_element(), setup_for_admin(), maybe_setup(), enqueue_element_scripts(), register_shortcode(), register_form(), render_generator_modal(), render_customize_modal(), handle_customize_modal(), register_default_scripts(), get_content(), as_inline_content(), save_widget_settings(), as_metabox(), super_admin_notice(), set_display(). Parameter types also removed where applicable.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through the code with glee,
Removing types with wild decree,
Looser signatures, freedom anew,
PHP says "no rules—do what you do!"
Flexibility wins, and types say "wheee!" 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: removing return type declarations from base classes to restore addon compatibility, which is the primary objective of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/base-gateway-return-type-compat

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
inc/integrations/host-providers/class-cloudflare-host-provider.php (1)

312-369: ⚠️ Potential issue | 🟠 Major

Don't abort the whole subdomain cleanup when one Cloudflare record is missing.

At Line 353, return exits on_remove_subdomain() on the first empty lookup, so the later candidate (notably the www. record) is never removed. This branch also masks WP_Error responses from cloudflare_api_call(). Use explicit error handling and continue for a missing record instead.

♻️ Proposed fix
 		foreach ($domains_to_remove as $original_subdomain) {
 			$dns_entries = $this->cloudflare_api_call(
 				"client/v4/zones/$zone_id/dns_records/",
 				'GET',
 				[
 					'name' => $original_subdomain,
 					'type' => 'CNAME',
 				]
 			);

-			if ( ! $dns_entries->result) {
-				return;
-			}
+			if (is_wp_error($dns_entries)) {
+				wu_log_add(
+					'integration-cloudflare',
+					sprintf(
+						'Failed to look up subdomain "%s" in Cloudflare. Reason: %s',
+						$original_subdomain,
+						$dns_entries->get_error_message()
+					),
+					LogLevel::ERROR
+				);
+
+				return;
+			}
+
+			if (empty($dns_entries->result)) {
+				continue;
+			}

 			$dns_entry_to_remove = $dns_entries->result[0];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/integrations/host-providers/class-cloudflare-host-provider.php` around
lines 312 - 369, The on_remove_subdomain method currently returns early when a
DNS lookup or delete fails, preventing the loop from attempting the second
candidate (e.g., the 'www.' record); update the foreach in class
Cloudflare_Host_Provider::on_remove_subdomain to handle errors explicitly: after
calling $this->cloudflare_api_call(...) for $dns_entries, if it returns a
WP_Error or has an empty result, log a warning and continue to the next
$original_subdomain instead of returning; similarly, after the DELETE call, if
$results is a WP_Error log the failure and continue (do not return), and only
log success when the delete actually succeeds. Ensure you reference
$dns_entries, $dns_entry_to_remove and $results variables and use continue
rather than return so both candidate records are processed.
inc/ui/class-base-element.php (1)

220-252: ⚠️ Potential issue | 🟠 Major

Compatibility pass is incomplete—concrete UI element lifecycle hooks still typed.

Untyping Base_Element::init() helps addons extending the abstract base, but 17+ concrete element classes still expose setup(), setup_preview(), and register_scripts() with : void return types. Any addon extending one of these concrete classes (Current_Site_Element, Domain_Mapping_Element, Template_Switching_Element, Site_Actions_Element, Site_Maintenance_Element, Thank_You_Element, and others) and overriding one of these hooks without matching return type will still hit the PHP 7.4+ declaration fatal this PR aims to eliminate. Either remove return types from these lifecycle hooks in concrete classes, or confirm addons do not extend these classes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/ui/class-base-element.php` around lines 220 - 252, The concrete element
classes still declare lifecycle hooks with a ": void" return type (e.g., methods
setup(), setup_preview(), register_scripts() on classes like
Current_Site_Element, Domain_Mapping_Element, Template_Switching_Element,
Site_Actions_Element, Site_Maintenance_Element, Thank_You_Element, etc.), which
will break addons that override them without the type; remove the explicit ":
void" return type from these concrete lifecycle method signatures (and from any
overrides in those classes) so their declarations match the untyped
Base_Element::init() lifecycle usage, or alternatively ensure every
addon/subclass is updated to declare the same return type—pick the former
(remove return types) for compatibility and update the listed methods across
those concrete classes.
🧹 Nitpick comments (4)
inc/checkout/signup-fields/class-base-signup-field.php (1)

247-247: Document this intentional type-hint exception inline.

This signature change is compatibility-critical; add a short note in the docblock (or inline) that : void is intentionally omitted for addon subclass compatibility, to prevent accidental reintroduction later.

Suggested docblock tweak
 	/**
 	 * Sets the config values for the current field.
+	 *
+	 * Note: Return type intentionally omitted to preserve compatibility with
+	 * third-party subclasses that may not declare `: void`.
 	 *
 	 * `@since` 2.0.0
 	 *
 	 * `@param` array $attributes Array containing settings for the field.
 	 * `@return` void
 	 */
 	public function set_attributes($attributes) {

As per coding guidelines, "Use type hints where present in existing PHP code. Use return type void on init methods."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/checkout/signup-fields/class-base-signup-field.php` at line 247, The
set_attributes method signature intentionally omits a return type to preserve
backward-compatible addon subclass overrides; add a brief inline docblock or
single-line comment above the public function set_attributes($attributes)
stating that the missing ": void" return type is deliberate for addon
compatibility and must not be reintroduced, e.g., reference the compatibility
requirement and the function name so future maintainers know this is
intentional.
inc/gateways/class-base-gateway.php (1)

592-592: Minor cleanup: mark intentionally unused parameter in default verifier.

At Line 592, $payment_id is intentionally unused in the fallback implementation; explicitly unsetting it keeps static analysis clean.

✂️ Proposed cleanup
 public function verify_and_complete_payment($payment_id) {
+	unset($payment_id);
 
 	return [
 		'success' => false,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/gateways/class-base-gateway.php` at line 592, The default implementation
of verify_and_complete_payment($payment_id) leaves the $payment_id parameter
unused; to silence static analyzers, explicitly mark it unused by unsetting it
(e.g., call unset($payment_id)) at the start of the verify_and_complete_payment
method body so the parameter is intentionally discarded.
inc/gateways/class-paypal-gateway.php (1)

1718-1721: Optional: explicitly mark unused parameter in the legacy PayPal payment URL stub.

At Line 1718, the argument is intentionally unused; adding unset() keeps static analysis quiet.

🧹 Proposed cleanup
 public function get_payment_url_on_gateway($gateway_payment_id) {
+	unset($gateway_payment_id);
 
 	return '';
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/gateways/class-paypal-gateway.php` around lines 1718 - 1721, The
get_payment_url_on_gateway($gateway_payment_id) stub currently ignores its
parameter; explicitly mark it unused by calling unset($gateway_payment_id) at
the start of the function (or otherwise reference it in a no-op) and then return
an empty string, so static analyzers stop flagging the unused variable; update
the function body in class PayPal gateway (get_payment_url_on_gateway)
accordingly.
inc/ui/class-command-palette-manager.php (1)

40-40: Codify the init() return-type exception used in this PR.

Line 40 removes : void from init(), which now conflicts with the current PHP guideline. If this compatibility exception is intentional, please update the guideline/AGENTS rule so future changes don’t oscillate between conflicting standards.

As per coding guidelines, "Use type hints where present in existing PHP code. Use return type void on init methods."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/ui/class-command-palette-manager.php` at line 40, The init() method in
class Command_Palette_Manager lost its return type hint; restore the PHP return
type by changing the method signature back to public function init(): void to
comply with the project's guideline for init methods; ensure this matches any
parent/interface signatures (Command_Palette_Manager::init) and update any unit
tests or callers if they relied on the previous signature, or if the removal was
intentional, update the guideline/AGENTS rule to document this compatibility
exception.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@inc/ui/class-template-previewer.php`:
- Line 45: Update the Template_Previewer::init method to match the Singleton
trait signature by adding the void return type; locate the init() method in the
Template_Previewer class and change its declaration to include ": void" so it
aligns with \WP_Ultimo\Traits\Singleton::init(): void and PHP method signature
compatibility.

---

Outside diff comments:
In `@inc/integrations/host-providers/class-cloudflare-host-provider.php`:
- Around line 312-369: The on_remove_subdomain method currently returns early
when a DNS lookup or delete fails, preventing the loop from attempting the
second candidate (e.g., the 'www.' record); update the foreach in class
Cloudflare_Host_Provider::on_remove_subdomain to handle errors explicitly: after
calling $this->cloudflare_api_call(...) for $dns_entries, if it returns a
WP_Error or has an empty result, log a warning and continue to the next
$original_subdomain instead of returning; similarly, after the DELETE call, if
$results is a WP_Error log the failure and continue (do not return), and only
log success when the delete actually succeeds. Ensure you reference
$dns_entries, $dns_entry_to_remove and $results variables and use continue
rather than return so both candidate records are processed.

In `@inc/ui/class-base-element.php`:
- Around line 220-252: The concrete element classes still declare lifecycle
hooks with a ": void" return type (e.g., methods setup(), setup_preview(),
register_scripts() on classes like Current_Site_Element, Domain_Mapping_Element,
Template_Switching_Element, Site_Actions_Element, Site_Maintenance_Element,
Thank_You_Element, etc.), which will break addons that override them without the
type; remove the explicit ": void" return type from these concrete lifecycle
method signatures (and from any overrides in those classes) so their
declarations match the untyped Base_Element::init() lifecycle usage, or
alternatively ensure every addon/subclass is updated to declare the same return
type—pick the former (remove return types) for compatibility and update the
listed methods across those concrete classes.

---

Nitpick comments:
In `@inc/checkout/signup-fields/class-base-signup-field.php`:
- Line 247: The set_attributes method signature intentionally omits a return
type to preserve backward-compatible addon subclass overrides; add a brief
inline docblock or single-line comment above the public function
set_attributes($attributes) stating that the missing ": void" return type is
deliberate for addon compatibility and must not be reintroduced, e.g., reference
the compatibility requirement and the function name so future maintainers know
this is intentional.

In `@inc/gateways/class-base-gateway.php`:
- Line 592: The default implementation of
verify_and_complete_payment($payment_id) leaves the $payment_id parameter
unused; to silence static analyzers, explicitly mark it unused by unsetting it
(e.g., call unset($payment_id)) at the start of the verify_and_complete_payment
method body so the parameter is intentionally discarded.

In `@inc/gateways/class-paypal-gateway.php`:
- Around line 1718-1721: The get_payment_url_on_gateway($gateway_payment_id)
stub currently ignores its parameter; explicitly mark it unused by calling
unset($gateway_payment_id) at the start of the function (or otherwise reference
it in a no-op) and then return an empty string, so static analyzers stop
flagging the unused variable; update the function body in class PayPal gateway
(get_payment_url_on_gateway) accordingly.

In `@inc/ui/class-command-palette-manager.php`:
- Line 40: The init() method in class Command_Palette_Manager lost its return
type hint; restore the PHP return type by changing the method signature back to
public function init(): void to comply with the project's guideline for init
methods; ensure this matches any parent/interface signatures
(Command_Palette_Manager::init) and update any unit tests or callers if they
relied on the previous signature, or if the removal was intentional, update the
guideline/AGENTS rule to document this compatibility exception.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9a8daf22-fdb9-4641-92d1-6776cb321d58

📥 Commits

Reviewing files that changed from the base of the PR and between aaddd40 and 0109e58.

📒 Files selected for processing (36)
  • inc/checkout/signup-fields/class-base-signup-field.php
  • inc/gateways/class-base-gateway.php
  • inc/gateways/class-base-paypal-gateway.php
  • inc/gateways/class-base-stripe-gateway.php
  • inc/gateways/class-paypal-gateway.php
  • inc/gateways/class-paypal-rest-gateway.php
  • inc/integrations/class-base-capability-module.php
  • inc/integrations/host-providers/class-base-host-provider.php
  • inc/integrations/host-providers/class-cloudflare-host-provider.php
  • inc/integrations/host-providers/class-cpanel-host-provider.php
  • inc/integrations/host-providers/class-hestia-host-provider.php
  • inc/integrations/host-providers/interface-dns-provider.php
  • inc/integrations/interface-capability-module.php
  • inc/models/class-base-model.php
  • inc/ui/class-account-summary-element.php
  • inc/ui/class-base-element.php
  • inc/ui/class-billing-info-element.php
  • inc/ui/class-checkout-element.php
  • inc/ui/class-command-palette-manager.php
  • inc/ui/class-current-membership-element.php
  • inc/ui/class-current-site-element.php
  • inc/ui/class-domain-mapping-element.php
  • inc/ui/class-invoices-element.php
  • inc/ui/class-limits-element.php
  • inc/ui/class-login-form-element.php
  • inc/ui/class-magic-link-url-element.php
  • inc/ui/class-my-sites-element.php
  • inc/ui/class-payment-methods-element.php
  • inc/ui/class-simple-text-element.php
  • inc/ui/class-site-actions-element.php
  • inc/ui/class-site-maintenance-element.php
  • inc/ui/class-template-previewer.php
  • inc/ui/class-template-switching-element.php
  • inc/ui/class-thank-you-element.php
  • inc/ui/class-toolbox.php
  • inc/ui/class-tours.php

* @return void
*/
public function init(): void {
public function init() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Locate singleton-related definitions.
fd -i 'singleton' inc | sort

# 2) Inspect interface/trait signatures for init/get_instance contracts.
rg -n -C3 --type=php 'interface\s+.*Singleton|trait\s+Singleton|function\s+init\s*\(|function\s+get_instance\s*\(' inc

# 3) Check whether classes using the Singleton trait also implement a Singleton interface.
rg -n -C2 --type=php 'class\s+\w+.*\{|use\s+\\WP_Ultimo\\Traits\\Singleton|implements\s+.*Singleton' inc

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 50394


🏁 Script executed:

cat -n inc/ui/class-template-previewer.php | head -60

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 1532


Add return type void to init() method.

Template_Previewer uses \WP_Ultimo\Traits\Singleton (line 24), which declares init(): void. The method on line 45 is missing the return type hint and must be updated to match the trait signature and align with coding guidelines.

public function init(): void {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/ui/class-template-previewer.php` at line 45, Update the
Template_Previewer::init method to match the Singleton trait signature by adding
the void return type; locate the init() method in the Template_Previewer class
and change its declaration to include ": void" so it aligns with
\WP_Ultimo\Traits\Singleton::init(): void and PHP method signature
compatibility.

@superdav42 superdav42 merged commit 8d39121 into main Apr 10, 2026
11 checks passed
@superdav42
Copy link
Copy Markdown
Collaborator Author

Summary

Fixes a fatal Compile Error on PHP 8.x that breaks the WooCommerce addon v2.0.22 (and potentially other addons) when upgrading to UM v2.5.1. Sites go completely down on any page load.

Root Cause

Two earlier commits added PHP return type declarations to public methods on base/abstract classes that external addons extend:

Commit What it did
b41dc2b2 "Use PHP 7.4 features" Added : void to setters (set_order, set_payment, set_membership, set_customer, trigger_payment_processed)
b8df0b85 "Add PayPal REST gateway" Added : string to URL methods (get_payment_url_on_gateway, get_subscription_url_on_gateway, get_customer_url_on_gateway)
PHP enforces that child class method signatures must be compatible with parent declarations. When a parent adds : string, any existing child class overriding that method without the return type causes:
Compile Error: Declaration of ChildClass::method($param)
must be compatible with ParentClass::method($param): string

This is a fatal error — no graceful degradation, site is completely down.

What Changed

Removed return type declarations from all overridable public methods across 6 base/abstract classes and their bundled subclasses (36 files total):

  • Base_Gateway (12 methods) — the confirmed breaking class
  • Base_Element (17 methods) — output(): void is abstract, every UI element addon must implement it
  • Base_Model (6 methods) — set_slug(), hydrate(), etc.
  • Base_Host_Provider (11 methods) — extended by hosting integration addons
  • Base_Capability_Module + Capability_Module interface (7 methods)
  • Base_Signup_Field (1 method)
    All bundled subclasses (Stripe, PayPal, PayPal REST, all UI elements, host providers) also had their return types removed for consistency.
    PHPDoc @return tags are preserved — IDEs and PHPStan still get type information.

Why Not Just Fix the Addon?

The addon fix is trivial (add : string to the override). But:

  1. The core plugin should not break existing addons with a minor release
  2. There are likely other addons and custom gateway implementations affected
  3. The Base_Element::output(): void abstract method would break every custom UI element addon
  4. Return types on extensible base classes are a semver-major change

Testing

  • PHPStan: zero new errors (15 pre-existing unrelated errors)
  • Verified child classes with return types (provider implementations) still pass — PHP allows a child to be more specific than its parent

Runtime Testing

  • Risk: Critical (payment gateway, site-down fatal)
  • Level: self-assessed — the fix is mechanical (removing type declarations), verified by PHPStan, and the failure mode is a PHP Compile Error that would be immediately visible

Merged via PR #780 to main.
Merged by deterministic merge pass (pulse-wrapper.sh).


aidevops.sh v3.6.235 spent 6m on this as a headless bash routine.

@github-actions
Copy link
Copy Markdown

Performance Test Results

Performance test results for 954d77d are in 🛎️!

Note: the numbers in parentheses show the difference to the previous (baseline) test run. Differences below 2% or 0.5 in absolute values are not shown.

URL: /

Run DB Queries Memory Before Template Template WP Total LCP TTFB LCP - TTFB
0 40 (-1 / -3% ) 37.78 MB 838.00 ms 170.00 ms (+14.50 ms / +9% ) 1069.00 ms (+21.50 ms / +2% ) 2000.00 ms (-42.00 ms / -2% ) 1906.15 ms (-52.05 ms / -3% ) 91.55 ms (+4.85 ms / +5% )
1 56 49.02 MB 942.50 ms 145.50 ms 1090.50 ms 2090.00 ms 2011.30 ms 81.90 ms

superdav42 added a commit that referenced this pull request Apr 11, 2026
…, static analysis

- Cloudflare on_remove_subdomain: use continue instead of return when DNS
  record is missing so both subdomain candidates are processed; add explicit
  WP_Error check for API lookup failures with proper logging
- Remove : void return types from setup(), setup_preview(), register_scripts()
  on all concrete UI element classes to prevent PHP fatal errors in addons
  that override these methods without matching return type declarations
- Restore : void to Command_Palette_Manager::init() and Template_Previewer::init()
  to match Singleton trait signature (concrete classes, not base/abstract)
- Add compatibility note to Base_Signup_Field::set_attributes() docblock
- Add unset() for intentionally unused parameters in Base_Gateway and PayPal gateway

Fixes #794
superdav42 added a commit that referenced this pull request Apr 11, 2026
…, static analysis (#796)

- Cloudflare on_remove_subdomain: use continue instead of return when DNS
  record is missing so both subdomain candidates are processed; add explicit
  WP_Error check for API lookup failures with proper logging
- Remove : void return types from setup(), setup_preview(), register_scripts()
  on all concrete UI element classes to prevent PHP fatal errors in addons
  that override these methods without matching return type declarations
- Restore : void to Command_Palette_Manager::init() and Template_Previewer::init()
  to match Singleton trait signature (concrete classes, not base/abstract)
- Add compatibility note to Base_Signup_Field::set_attributes() docblock
- Add unset() for intentionally unused parameters in Base_Gateway and PayPal gateway

Fixes #794
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant