From a4a19073cfc635dec2f8820afed1213add061b72 Mon Sep 17 00:00:00 2001 From: David Stone Date: Fri, 10 Apr 2026 01:04:00 -0600 Subject: [PATCH 1/3] fix: remove return type declarations from Base_Gateway abstract methods 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. --- inc/gateways/class-base-gateway.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/inc/gateways/class-base-gateway.php b/inc/gateways/class-base-gateway.php index ca1bd6596..e4c851949 100644 --- a/inc/gateways/class-base-gateway.php +++ b/inc/gateways/class-base-gateway.php @@ -165,7 +165,7 @@ public function __construct($order = null) { * @param \WP_Ultimo\Checkout\Cart $order The order. * @return void */ - public function set_order($order): void { + public function set_order($order) { if (null === $order) { return; @@ -608,7 +608,7 @@ public function verify_and_complete_payment(int $payment_id): array { * @param string $gateway_payment_id The gateway payment id. * @return string */ - public function get_payment_url_on_gateway($gateway_payment_id): string { + public function get_payment_url_on_gateway($gateway_payment_id) { unset($gateway_payment_id); return ''; } @@ -623,7 +623,7 @@ public function get_payment_url_on_gateway($gateway_payment_id): string { * @param string $gateway_subscription_id The gateway subscription id. * @return string */ - public function get_subscription_url_on_gateway($gateway_subscription_id): string { + public function get_subscription_url_on_gateway($gateway_subscription_id) { unset($gateway_subscription_id); return ''; } @@ -638,7 +638,7 @@ public function get_subscription_url_on_gateway($gateway_subscription_id): strin * @param string $gateway_customer_id The gateway customer id. * @return string */ - public function get_customer_url_on_gateway($gateway_customer_id): string { + public function get_customer_url_on_gateway($gateway_customer_id) { unset($gateway_customer_id); return ''; } @@ -853,7 +853,7 @@ public function get_webhook_listener_url() { * @param \WP_Ultimo\Models\Payment $payment The payment. * @return void */ - public function set_payment($payment): void { + public function set_payment($payment) { $this->payment = $payment; } @@ -865,7 +865,7 @@ public function set_payment($payment): void { * @param \WP_Ultimo\Models\Membership $membership The membership. * @return void */ - public function set_membership($membership): void { + public function set_membership($membership) { $this->membership = $membership; } @@ -877,7 +877,7 @@ public function set_membership($membership): void { * @param \WP_Ultimo\Models\Customer $customer The customer. * @return void */ - public function set_customer($customer): void { + public function set_customer($customer) { $this->customer = $customer; } @@ -891,7 +891,7 @@ public function set_customer($customer): void { * @param \WP_Ultimo\Models\Membership $membership The membership object. * @return void */ - public function trigger_payment_processed($payment, $membership = null): void { + public function trigger_payment_processed($payment, $membership = null) { if (null === $membership) { $membership = $payment->get_membership(); From 0109e58796d9b1e47020d450dfee8f29d818c872 Mon Sep 17 00:00:00 2001 From: David Stone Date: Fri, 10 Apr 2026 09:53:00 -0600 Subject: [PATCH 2/3] fix: remove return type declarations from base/abstract classes to restore 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: - b41dc2b2 'Use PHP 7.4 features' added void returns to setters - b8df0b85 '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) --- .../signup-fields/class-base-signup-field.php | 2 +- inc/gateways/class-base-gateway.php | 8 ++--- inc/gateways/class-base-paypal-gateway.php | 4 +-- inc/gateways/class-base-stripe-gateway.php | 12 +++---- inc/gateways/class-paypal-gateway.php | 2 +- inc/gateways/class-paypal-rest-gateway.php | 4 +-- .../class-base-capability-module.php | 14 ++++---- .../class-base-host-provider.php | 26 +++++++------- .../class-cloudflare-host-provider.php | 12 +++---- .../class-cpanel-host-provider.php | 8 ++--- .../class-hestia-host-provider.php | 8 ++--- .../host-providers/interface-dns-provider.php | 10 +++--- .../interface-capability-module.php | 18 +++++----- inc/models/class-base-model.php | 12 +++---- inc/ui/class-account-summary-element.php | 2 +- inc/ui/class-base-element.php | 36 +++++++++---------- inc/ui/class-billing-info-element.php | 4 +-- inc/ui/class-checkout-element.php | 2 +- inc/ui/class-command-palette-manager.php | 2 +- inc/ui/class-current-membership-element.php | 4 +-- inc/ui/class-current-site-element.php | 4 +-- inc/ui/class-domain-mapping-element.php | 4 +-- inc/ui/class-invoices-element.php | 2 +- inc/ui/class-limits-element.php | 2 +- inc/ui/class-login-form-element.php | 4 +-- inc/ui/class-magic-link-url-element.php | 2 +- inc/ui/class-my-sites-element.php | 2 +- inc/ui/class-payment-methods-element.php | 2 +- inc/ui/class-simple-text-element.php | 2 +- inc/ui/class-site-actions-element.php | 4 +-- inc/ui/class-site-maintenance-element.php | 4 +-- inc/ui/class-template-previewer.php | 2 +- inc/ui/class-template-switching-element.php | 4 +-- inc/ui/class-thank-you-element.php | 2 +- inc/ui/class-toolbox.php | 4 +-- inc/ui/class-tours.php | 2 +- 36 files changed, 118 insertions(+), 118 deletions(-) diff --git a/inc/checkout/signup-fields/class-base-signup-field.php b/inc/checkout/signup-fields/class-base-signup-field.php index de434477d..33c37c8e1 100644 --- a/inc/checkout/signup-fields/class-base-signup-field.php +++ b/inc/checkout/signup-fields/class-base-signup-field.php @@ -244,7 +244,7 @@ public function calculate_style_attr() { * @param array $attributes Array containing settings for the field. * @return void */ - public function set_attributes($attributes): void { + public function set_attributes($attributes) { $this->attributes = $attributes; } diff --git a/inc/gateways/class-base-gateway.php b/inc/gateways/class-base-gateway.php index e4c851949..026bf40ae 100644 --- a/inc/gateways/class-base-gateway.php +++ b/inc/gateways/class-base-gateway.php @@ -209,7 +209,7 @@ final public function get_id() { * @param \WP_Ultimo\Models\Membership $membership The membership. * @return array{brand: string, last4: string}|null Payment method info, or null. */ - public function get_payment_method_display($membership): ?array { + public function get_payment_method_display($membership) { unset($membership); return null; } @@ -568,7 +568,7 @@ public function process_confirmation() {} * @since 2.0.0 * @return bool */ - public function supports_payment_polling(): bool { + public function supports_payment_polling() { return false; } @@ -589,7 +589,7 @@ public function supports_payment_polling(): bool { * @param int $payment_id The local payment ID to verify. * @return array{success: bool, status: string, message: string} */ - public function verify_and_complete_payment(int $payment_id): array { + public function verify_and_complete_payment($payment_id) { return [ 'success' => false, @@ -816,7 +816,7 @@ public function get_confirm_url() { * @param string $message The error message. * @return void */ - public function redirect_with_error(string $message): void { + public function redirect_with_error($message) { $url = remove_query_arg(['wu-confirm', 'payment', 'token', 'PayerID', 'ba_token', 'subscription_id', 'status'], $this->return_url ?: wu_get_current_url()); diff --git a/inc/gateways/class-base-paypal-gateway.php b/inc/gateways/class-base-paypal-gateway.php index 4468da855..cdc908767 100644 --- a/inc/gateways/class-base-paypal-gateway.php +++ b/inc/gateways/class-base-paypal-gateway.php @@ -127,7 +127,7 @@ protected function get_subscription_description($cart): string { * @param string $gateway_payment_id The gateway payment id. * @return string */ - public function get_payment_url_on_gateway($gateway_payment_id): string { + public function get_payment_url_on_gateway($gateway_payment_id) { if (empty($gateway_payment_id)) { return ''; @@ -152,7 +152,7 @@ public function get_payment_url_on_gateway($gateway_payment_id): string { * @param string $gateway_subscription_id The gateway subscription id. * @return string */ - public function get_subscription_url_on_gateway($gateway_subscription_id): string { + public function get_subscription_url_on_gateway($gateway_subscription_id) { if (empty($gateway_subscription_id)) { return ''; diff --git a/inc/gateways/class-base-stripe-gateway.php b/inc/gateways/class-base-stripe-gateway.php index 399345206..0269bb24e 100644 --- a/inc/gateways/class-base-stripe-gateway.php +++ b/inc/gateways/class-base-stripe-gateway.php @@ -828,7 +828,7 @@ public function get_change_payment_method_url($membership) { * @param \WP_Ultimo\Models\Membership $membership The membership. * @return array{brand: string, last4: string}|null Payment method info, or null. */ - public function get_payment_method_display($membership): ?array { + public function get_payment_method_display($membership) { try { $sub_id = $membership->get_gateway_subscription_id(); @@ -3832,7 +3832,7 @@ public function get_user_saved_payment_methods() { * @param string $gateway_payment_id The gateway payment id. * @return string. */ - public function get_payment_url_on_gateway($gateway_payment_id): string { + public function get_payment_url_on_gateway($gateway_payment_id) { $route = $this->test_mode ? '/test' : '/'; @@ -3855,7 +3855,7 @@ public function get_payment_url_on_gateway($gateway_payment_id): string { * @param string $gateway_subscription_id The gateway subscription id. * @return string. */ - public function get_subscription_url_on_gateway($gateway_subscription_id): string { + public function get_subscription_url_on_gateway($gateway_subscription_id) { $route = $this->test_mode ? '/test' : '/'; @@ -3872,7 +3872,7 @@ public function get_subscription_url_on_gateway($gateway_subscription_id): strin * @param string $gateway_customer_id The gateway customer id. * @return string. */ - public function get_customer_url_on_gateway($gateway_customer_id): string { + public function get_customer_url_on_gateway($gateway_customer_id) { $route = $this->test_mode ? '/test' : '/'; @@ -3883,7 +3883,7 @@ public function get_customer_url_on_gateway($gateway_customer_id): string { * @inheritdoc * @since 2.0.0 */ - public function supports_payment_polling(): bool { + public function supports_payment_polling() { return true; } @@ -3899,7 +3899,7 @@ public function supports_payment_polling(): bool { * @param int $payment_id The local payment ID to verify. * @return array{success: bool, message: string, status?: string} */ - public function verify_and_complete_payment(int $payment_id): array { + public function verify_and_complete_payment($payment_id) { $payment = wu_get_payment($payment_id); diff --git a/inc/gateways/class-paypal-gateway.php b/inc/gateways/class-paypal-gateway.php index 2f8e4e0c8..5d69fe06f 100644 --- a/inc/gateways/class-paypal-gateway.php +++ b/inc/gateways/class-paypal-gateway.php @@ -1715,7 +1715,7 @@ public function get_checkout_details($token = '') { * @param string $gateway_payment_id The gateway payment id. * @return string */ - public function get_payment_url_on_gateway($gateway_payment_id): string { + public function get_payment_url_on_gateway($gateway_payment_id) { return ''; } diff --git a/inc/gateways/class-paypal-rest-gateway.php b/inc/gateways/class-paypal-rest-gateway.php index 5e3b64076..e331b1e1f 100644 --- a/inc/gateways/class-paypal-rest-gateway.php +++ b/inc/gateways/class-paypal-rest-gateway.php @@ -2090,7 +2090,7 @@ public function preserve_oauth_settings(array $settings, array $settings_to_save * @inheritdoc * @since 2.0.0 */ - public function supports_payment_polling(): bool { + public function supports_payment_polling() { return true; } @@ -2107,7 +2107,7 @@ public function supports_payment_polling(): bool { * @param int $payment_id The local payment ID to verify. * @return array{success: bool, message: string, status?: string} */ - public function verify_and_complete_payment(int $payment_id): array { + public function verify_and_complete_payment($payment_id) { $payment = wu_get_payment($payment_id); diff --git a/inc/integrations/class-base-capability-module.php b/inc/integrations/class-base-capability-module.php index 3e6d453b7..c044f295d 100644 --- a/inc/integrations/class-base-capability-module.php +++ b/inc/integrations/class-base-capability-module.php @@ -45,7 +45,7 @@ abstract class Base_Capability_Module implements Capability_Module { * @param string $feature The feature identifier to check. * @return bool */ - public function supports(string $feature): bool { + public function supports($feature) { return in_array($feature, $this->supported_features, true); } @@ -58,7 +58,7 @@ public function supports(string $feature): bool { * @param Integration $integration The parent integration instance. * @return void */ - public function set_integration(Integration $integration): void { + public function set_integration(Integration $integration) { $this->integration = $integration; } @@ -66,7 +66,7 @@ public function set_integration(Integration $integration): void { /** * {@inheritdoc} */ - public function get_integration(): Integration { + public function get_integration() { return $this->integration; } @@ -74,7 +74,7 @@ public function get_integration(): Integration { /** * {@inheritdoc} */ - public function get_supported_features(): array { + public function get_supported_features() { return $this->supported_features; } @@ -82,12 +82,12 @@ public function get_supported_features(): array { /** * {@inheritdoc} */ - public function register_hooks(): void {} + public function register_hooks() {} /** * {@inheritdoc} */ - public function get_fields(): array { + public function get_fields() { return []; } @@ -95,7 +95,7 @@ public function get_fields(): array { /** * {@inheritdoc} */ - public function get_explainer_lines(): array { + public function get_explainer_lines() { return [ 'will' => [], diff --git a/inc/integrations/host-providers/class-base-host-provider.php b/inc/integrations/host-providers/class-base-host-provider.php index 9bb75aa1f..2b8b91c0e 100644 --- a/inc/integrations/host-providers/class-base-host-provider.php +++ b/inc/integrations/host-providers/class-base-host-provider.php @@ -78,7 +78,7 @@ abstract class Base_Host_Provider implements DNS_Provider_Interface { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { if ($this->detect() && ! $this->is_enabled()) { /* @@ -197,7 +197,7 @@ public function disable() { * @since 2.0.0 * @return void */ - public function add_to_integration_list(): void { + public function add_to_integration_list() { $slug = $this->get_id(); @@ -237,7 +237,7 @@ public function add_to_integration_list(): void { * @since 2.0.0 * @return void */ - public function alert_provider_detected(): void { + public function alert_provider_detected() { if (WP_Ultimo()->is_loaded() === false) { return; @@ -270,7 +270,7 @@ public function alert_provider_detected(): void { * @since 2.0.0 * @return void */ - public function alert_provider_not_setup(): void { + public function alert_provider_not_setup() { if (WP_Ultimo()->is_loaded() === false) { return; @@ -349,7 +349,7 @@ public function supports($feature) { * @since 2.0.0 * @return void */ - public function register_hooks(): void { + public function register_hooks() { /* * Hooks the event that is triggered when a new domain is added. */ @@ -494,7 +494,7 @@ public function get_all_constants() { * @param array $constant_values Key => Value of the necessary constants. * @return void */ - public function setup_constants($constant_values): void { + public function setup_constants($constant_values) { /* * Important: This step is crucial, as it makes sure we clean up undesired constants. * Removing this can allow insertion of arbitrary constants onto the wp-config.pp file @@ -631,7 +631,7 @@ abstract public function on_remove_subdomain($subdomain, $site_id); * @since 2.0.0 * @return void */ - public function test_connection(): void { + public function test_connection() { wp_send_json_success([]); } @@ -664,7 +664,7 @@ public function get_logo() { * @since 2.3.0 * @return bool */ - public function supports_dns_management(): bool { + public function supports_dns_management() { return $this->supports('dns-management'); } @@ -752,7 +752,7 @@ public function delete_dns_record(string $domain, string $record_id) { * * @return array Array of supported record types. */ - public function get_supported_record_types(): array { + public function get_supported_record_types() { return ['A', 'AAAA', 'CNAME', 'MX', 'TXT']; } @@ -768,7 +768,7 @@ public function get_supported_record_types(): array { * @param string $domain The domain name. * @return string|null Zone identifier or null if not found. */ - public function get_zone_id(string $domain): ?string { + public function get_zone_id($domain) { return null; } @@ -782,7 +782,7 @@ public function get_zone_id(string $domain): ?string { * * @return bool */ - public function is_dns_enabled(): bool { + public function is_dns_enabled() { if (! $this->supports_dns_management()) { return false; @@ -801,7 +801,7 @@ public function is_dns_enabled(): bool { * * @return bool */ - public function enable_dns(): bool { + public function enable_dns() { if (! $this->supports_dns_management()) { return false; @@ -820,7 +820,7 @@ public function enable_dns(): bool { * * @return bool */ - public function disable_dns(): bool { + public function disable_dns() { $dns_enabled = get_network_option(null, 'wu_dns_integrations_enabled', []); $dns_enabled[ $this->get_id() ] = false; diff --git a/inc/integrations/host-providers/class-cloudflare-host-provider.php b/inc/integrations/host-providers/class-cloudflare-host-provider.php index 2036bb6ff..d9813f072 100644 --- a/inc/integrations/host-providers/class-cloudflare-host-provider.php +++ b/inc/integrations/host-providers/class-cloudflare-host-provider.php @@ -180,7 +180,7 @@ public function get_fields() { * @since 2.0.0 * @return void */ - public function test_connection(): void { + public function test_connection() { $results = $this->cloudflare_api_call('client/v4/user/tokens/verify'); @@ -197,7 +197,7 @@ public function test_connection(): void { * @since 2.0.7 * @return void */ - public function additional_hooks(): void { + public function additional_hooks() { add_filter('wu_domain_dns_get_record', [$this, 'add_cloudflare_dns_entries'], 10, 2); } @@ -232,7 +232,7 @@ public function on_remove_domain($domain, $site_id) {} * @param int $site_id ID of the site that is receiving that mapping. * @return void */ - public function on_add_subdomain($subdomain, $site_id): void { + public function on_add_subdomain($subdomain, $site_id) { global $current_site; @@ -309,7 +309,7 @@ public function on_add_subdomain($subdomain, $site_id): void { * @param int $site_id ID of the site that is receiving that mapping. * @return void */ - public function on_remove_subdomain($subdomain, $site_id): void { + public function on_remove_subdomain($subdomain, $site_id) { global $current_site; @@ -706,7 +706,7 @@ public function delete_dns_record(string $domain, string $record_id) { * @param string $domain The domain name. * @return string|null Zone ID or null if not found. */ - public function get_zone_id(string $domain): ?string { + public function get_zone_id($domain) { // Try configured zone first $default_zone = defined('WU_CLOUDFLARE_ZONE_ID') && WU_CLOUDFLARE_ZONE_ID ? WU_CLOUDFLARE_ZONE_ID : null; @@ -789,7 +789,7 @@ protected function cloudflare_api_call($endpoint = 'client/v4/user/tokens/verify * @since 2.0.0 * @return void */ - public function get_instructions(): void { + public function get_instructions() { wu_get_template('wizards/host-integrations/cloudflare-instructions'); } diff --git a/inc/integrations/host-providers/class-cpanel-host-provider.php b/inc/integrations/host-providers/class-cpanel-host-provider.php index b8af693af..929bdbf1b 100644 --- a/inc/integrations/host-providers/class-cpanel-host-provider.php +++ b/inc/integrations/host-providers/class-cpanel-host-provider.php @@ -145,7 +145,7 @@ public function get_fields() { * @param int $site_id ID of the site that is receiving that mapping. * @return void */ - public function on_add_domain($domain, $site_id): void { + public function on_add_domain($domain, $site_id) { // Root Directory $root_dir = defined('WU_CPANEL_ROOT_DIR') && WU_CPANEL_ROOT_DIR ? WU_CPANEL_ROOT_DIR : '/public_html'; @@ -172,7 +172,7 @@ public function on_add_domain($domain, $site_id): void { * @param int $site_id ID of the site that is receiving that mapping. * @return void */ - public function on_remove_domain($domain, $site_id): void { + public function on_remove_domain($domain, $site_id) { // Send Request $results = $this->load_api()->api2( @@ -197,7 +197,7 @@ public function on_remove_domain($domain, $site_id): void { * @param int $site_id ID of the site that is receiving that mapping. * @return void */ - public function on_add_subdomain($subdomain, $site_id): void { + public function on_add_subdomain($subdomain, $site_id) { // Root Directory $root_dir = defined('WU_CPANEL_ROOT_DIR') && WU_CPANEL_ROOT_DIR ? WU_CPANEL_ROOT_DIR : '/public_html'; @@ -657,7 +657,7 @@ public function get_logo() { * @since 2.0.0 * @return void */ - public function test_connection(): void { + public function test_connection() { $results = $this->load_api()->api2('Cron', 'fetchcron', []); diff --git a/inc/integrations/host-providers/class-hestia-host-provider.php b/inc/integrations/host-providers/class-hestia-host-provider.php index b90f7181d..3c4454306 100644 --- a/inc/integrations/host-providers/class-hestia-host-provider.php +++ b/inc/integrations/host-providers/class-hestia-host-provider.php @@ -141,7 +141,7 @@ public function get_fields() { * @param string $domain Domain name to add. * @param int $site_id Site ID. */ - public function on_add_domain($domain, $site_id): void { + public function on_add_domain($domain, $site_id) { $account = defined('WU_HESTIA_ACCOUNT') ? WU_HESTIA_ACCOUNT : ''; $base_domain = defined('WU_HESTIA_WEB_DOMAIN') ? WU_HESTIA_WEB_DOMAIN : ''; @@ -168,7 +168,7 @@ public function on_add_domain($domain, $site_id): void { * @param string $domain Domain name to remove. * @param int $site_id Site ID. */ - public function on_remove_domain($domain, $site_id): void { + public function on_remove_domain($domain, $site_id) { $account = defined('WU_HESTIA_ACCOUNT') ? WU_HESTIA_ACCOUNT : ''; $base_domain = defined('WU_HESTIA_WEB_DOMAIN') ? WU_HESTIA_WEB_DOMAIN : ''; @@ -208,7 +208,7 @@ public function on_remove_subdomain($subdomain, $site_id) {} /** * Test connection by listing web domains for the configured account. */ - public function test_connection(): void { + public function test_connection() { $account = defined('WU_HESTIA_ACCOUNT') ? WU_HESTIA_ACCOUNT : ''; @@ -246,7 +246,7 @@ public function get_logo() { * @param string $action_label Log label. * @return void */ - protected function call_and_log($cmd, $args, $action_label): void { + protected function call_and_log($cmd, $args, $action_label) { $result = $this->send_hestia_request($cmd, $args); diff --git a/inc/integrations/host-providers/interface-dns-provider.php b/inc/integrations/host-providers/interface-dns-provider.php index e84354e0b..4830808b2 100644 --- a/inc/integrations/host-providers/interface-dns-provider.php +++ b/inc/integrations/host-providers/interface-dns-provider.php @@ -31,7 +31,7 @@ interface DNS_Provider_Interface { * * @return bool True if DNS management is supported. */ - public function supports_dns_management(): bool; + public function supports_dns_management(); /** * Check if DNS management is enabled for this provider. @@ -40,7 +40,7 @@ public function supports_dns_management(): bool; * * @return bool True if DNS management is enabled. */ - public function is_dns_enabled(): bool; + public function is_dns_enabled(); /** * Enable DNS management for this provider. @@ -49,7 +49,7 @@ public function is_dns_enabled(): bool; * * @return bool True on success. */ - public function enable_dns(): bool; + public function enable_dns(); /** * Disable DNS management for this provider. @@ -58,7 +58,7 @@ public function enable_dns(): bool; * * @return bool True on success. */ - public function disable_dns(): bool; + public function disable_dns(); /** * Get DNS records for a domain. @@ -111,5 +111,5 @@ public function delete_dns_record(string $domain, string $record_id); * * @return array Array of supported record types (e.g., ['A', 'AAAA', 'CNAME', 'MX', 'TXT']). */ - public function get_supported_record_types(): array; + public function get_supported_record_types(); } diff --git a/inc/integrations/interface-capability-module.php b/inc/integrations/interface-capability-module.php index af9799fcb..4107bec5b 100644 --- a/inc/integrations/interface-capability-module.php +++ b/inc/integrations/interface-capability-module.php @@ -30,7 +30,7 @@ interface Capability_Module { * @since 2.5.0 * @return string E.g. 'domain-mapping', 'domain-selling', 'multi-tenancy'. */ - public function get_capability_id(): string; + public function get_capability_id(); /** * Returns the display title for this capability. @@ -38,7 +38,7 @@ public function get_capability_id(): string; * @since 2.5.0 * @return string */ - public function get_title(): string; + public function get_title(); /** * Returns the list of supported features. @@ -46,7 +46,7 @@ public function get_title(): string; * @since 2.5.0 * @return array E.g. ['autossl'], ['remote_sites']. */ - public function get_supported_features(): array; + public function get_supported_features(); /** * Checks if a specific feature is supported. @@ -56,7 +56,7 @@ public function get_supported_features(): array; * @param string $feature Feature identifier to check. * @return bool */ - public function supports(string $feature): bool; + public function supports($feature); /** * Registers WordPress hooks for this capability. @@ -64,7 +64,7 @@ public function supports(string $feature): bool; * @since 2.5.0 * @return void */ - public function register_hooks(): void; + public function register_hooks(); /** * Returns additional wizard fields beyond shared integration credentials. @@ -72,7 +72,7 @@ public function register_hooks(): void; * @since 2.5.0 * @return array */ - public function get_fields(): array; + public function get_fields(); /** * Returns explainer lines for the wizard activation screen. @@ -80,7 +80,7 @@ public function get_fields(): array; * @since 2.5.0 * @return array{will: array, will_not: array} */ - public function get_explainer_lines(): array; + public function get_explainer_lines(); /** * Sets the parent integration reference. @@ -90,7 +90,7 @@ public function get_explainer_lines(): array; * @param Integration $integration The parent integration. * @return void */ - public function set_integration(Integration $integration): void; + public function set_integration(Integration $integration); /** * Gets the parent integration reference. @@ -98,7 +98,7 @@ public function set_integration(Integration $integration): void; * @since 2.5.0 * @return Integration */ - public function get_integration(): Integration; + public function get_integration(); /** * Tests the connection for this capability. diff --git a/inc/models/class-base-model.php b/inc/models/class-base-model.php index a0c225d91..8b782004f 100644 --- a/inc/models/class-base-model.php +++ b/inc/models/class-base-model.php @@ -166,7 +166,7 @@ public function get_slug() { * * @param mixed $slug The slug. */ - public function set_slug($slug): void { + public function set_slug($slug) { $this->slug = $slug; } @@ -952,7 +952,7 @@ public function get_date_modified() { * @param string $date_created Model creation date. * @return void */ - public function set_date_created($date_created): void { + public function set_date_created($date_created) { $this->date_created = $date_created; } @@ -964,7 +964,7 @@ public function set_date_created($date_created): void { * @param string $date_modified Model last modification date. * @return void */ - public function set_date_modified($date_modified): void { + public function set_date_modified($date_modified) { $this->date_modified = $date_modified; } @@ -987,7 +987,7 @@ public function get_migrated_from_id() { * @param int $migrated_from_id The ID of the original 1.X model that was used to generate this item on migration. * @return void */ - public function set_migrated_from_id($migrated_from_id): void { + public function set_migrated_from_id($migrated_from_id) { $this->migrated_from_id = absint($migrated_from_id); } @@ -1093,7 +1093,7 @@ public function duplicate() { * @since 2.0.0 * @return void */ - public function hydrate(): void { + public function hydrate() { $attributes = get_object_vars($this); $attributes = array_filter($attributes, fn ($value) => null === $value); @@ -1127,7 +1127,7 @@ public function hydrate(): void { * @param boolean $skip_validation Set true to have field information validation bypassed when saving this event. * @return void */ - public function set_skip_validation($skip_validation = false): void { + public function set_skip_validation($skip_validation = false) { $this->skip_validation = $skip_validation; } diff --git a/inc/ui/class-account-summary-element.php b/inc/ui/class-account-summary-element.php index 072d792dc..45a688ffc 100644 --- a/inc/ui/class-account-summary-element.php +++ b/inc/ui/class-account-summary-element.php @@ -290,7 +290,7 @@ public function setup_preview(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $this->ensure_setup(); diff --git a/inc/ui/class-base-element.php b/inc/ui/class-base-element.php index 9eb05a0b0..acfbf6a0b 100644 --- a/inc/ui/class-base-element.php +++ b/inc/ui/class-base-element.php @@ -207,7 +207,7 @@ abstract public function defaults(); * @param string|null $content The content inside the shortcode. * @return void */ - abstract public function output($atts, $content = null): void; + abstract public function output($atts, $content = null); // Boilerplate ----------------------------------- @@ -217,7 +217,7 @@ abstract public function output($atts, $content = null): void; * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { add_action('plugins_loaded', [$this, 'register_form']); @@ -258,7 +258,7 @@ function () { * @param mixed $element The element instance to be registered. * @return void */ - public static function register_public_element($element): void { + public static function register_public_element($element) { static::$public_elements[] = $element; } @@ -387,7 +387,7 @@ protected static function search_in_metaboxes($element_id) { * @since 2.0.0 * @return void */ - public function setup_for_admin(): void { + public function setup_for_admin() { if (true === $this->loaded) { return; @@ -409,7 +409,7 @@ public function setup_for_admin(): void { * @since 2.0.0 * @return void */ - public function maybe_setup(): void { + public function maybe_setup() { global $post; @@ -590,7 +590,7 @@ protected function maybe_extract_arguments($content, $type = 'shortcode') { * @since 2.0.0 * @return void */ - public function enqueue_element_scripts(): void { + public function enqueue_element_scripts() { global $post; @@ -644,7 +644,7 @@ public function get_pre_loaded_attribute($name, $default_value = false) { * @since 2.0.0 * @return void */ - public function register_shortcode(): void { + public function register_shortcode() { if (wu_get_current_site()->get_type() === Site_Type::CUSTOMER_OWNED && is_admin() === false) { return; @@ -659,7 +659,7 @@ public function register_shortcode(): void { * @since 2.0.0 * @return void */ - public function register_form(): void { + public function register_form() { /* * Add Generator Forms */ @@ -691,7 +691,7 @@ public function register_form(): void { * @since 2.0.0 * @return void */ - public function render_generator_modal(): void { + public function render_generator_modal() { $fields = $this->fields(); @@ -806,7 +806,7 @@ public function render_generator_modal(): void { * @since 2.0.0 * @return void */ - public function render_customize_modal(): void { + public function render_customize_modal() { $fields = []; @@ -890,7 +890,7 @@ public function render_customize_modal(): void { * @since 2.0.0 * @return void */ - public function handle_customize_modal(): void { + public function handle_customize_modal() { $settings = []; @@ -931,7 +931,7 @@ public function handle_customize_modal(): void { * @since 2.0.0 * @return void */ - public function register_default_scripts(): void { + public function register_default_scripts() { wp_enqueue_style('wu-admin'); } @@ -1012,7 +1012,7 @@ public function display($atts) { * * @return string */ - public function get_content($atts): string { + public function get_content($atts) { ob_start(); $this->display($atts); return ob_get_clean(); @@ -1076,7 +1076,7 @@ public function should_display_customize_controls() { * @param array $atts Array containing the shortcode attributes. * @return void */ - public function as_inline_content($screen_id, $hook = 'admin_notices', $atts = []): void { + public function as_inline_content($screen_id, $hook = 'admin_notices', $atts = []) { if ( ! function_exists('get_current_screen')) { _doing_it_wrong(__METHOD__, esc_html__('An element can not be loaded as inline content unless the get_current_screen() function is already available.', 'ultimate-multisite'), '2.0.0'); @@ -1143,7 +1143,7 @@ function () use ($atts, $control_classes) { * @param array $settings The settings to save. Key => value array. * @return void */ - public function save_widget_settings($settings): void { + public function save_widget_settings($settings) { $key = wu_replace_dashes($this->id); @@ -1173,7 +1173,7 @@ public function get_widget_settings() { * @param array $atts Array containing the shortcode attributes. * @return void */ - public function as_metabox($screen_id, $position = 'normal', $atts = []): void { + public function as_metabox($screen_id, $position = 'normal', $atts = []) { $this->setup(); @@ -1226,7 +1226,7 @@ function () use ($atts, $control_classes) { * @since 2.0.0 * @return void */ - public function super_admin_notice(): void { + public function super_admin_notice() { $should_display = $this->should_display_customize_controls(); @@ -1286,7 +1286,7 @@ public function should_display() { * @param boolean $display Controls whether or not the widget and element should display. * @return void */ - public function set_display($display): void { + public function set_display($display) { $this->display = $display; } diff --git a/inc/ui/class-billing-info-element.php b/inc/ui/class-billing-info-element.php index 04fbee26f..30855726e 100644 --- a/inc/ui/class-billing-info-element.php +++ b/inc/ui/class-billing-info-element.php @@ -82,7 +82,7 @@ public function get_icon($context = 'block'): string { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { parent::init(); @@ -268,7 +268,7 @@ public function setup_preview(): void { * @param string|null $content The content inside the shortcode. * @return string */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $this->ensure_setup(); diff --git a/inc/ui/class-checkout-element.php b/inc/ui/class-checkout-element.php index 0e6a19573..63e4bdf7f 100644 --- a/inc/ui/class-checkout-element.php +++ b/inc/ui/class-checkout-element.php @@ -696,7 +696,7 @@ public function inject_inline_auto_submittable_field($auto_submittable_field): v * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { if (wu_is_update_page()) { $atts = [ diff --git a/inc/ui/class-command-palette-manager.php b/inc/ui/class-command-palette-manager.php index a16581325..e32edab3a 100644 --- a/inc/ui/class-command-palette-manager.php +++ b/inc/ui/class-command-palette-manager.php @@ -37,7 +37,7 @@ class Command_Palette_Manager { * @since 2.1.0 * @return void */ - public function init(): void { + public function init() { add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts'], 100); diff --git a/inc/ui/class-current-membership-element.php b/inc/ui/class-current-membership-element.php index cc47a9f51..d3e5d6163 100644 --- a/inc/ui/class-current-membership-element.php +++ b/inc/ui/class-current-membership-element.php @@ -66,7 +66,7 @@ class Current_Membership_Element extends Base_Element { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { parent::init(); @@ -298,7 +298,7 @@ public function setup_preview(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $atts['membership'] = $this->membership; $atts['plan'] = $this->plan; diff --git a/inc/ui/class-current-site-element.php b/inc/ui/class-current-site-element.php index 0ffbcf75e..4b2f8a769 100644 --- a/inc/ui/class-current-site-element.php +++ b/inc/ui/class-current-site-element.php @@ -82,7 +82,7 @@ public function get_icon($context = 'block'): string { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { parent::init(); @@ -350,7 +350,7 @@ public function register_scripts(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $this->ensure_setup(); diff --git a/inc/ui/class-domain-mapping-element.php b/inc/ui/class-domain-mapping-element.php index df7321bd8..75444f016 100644 --- a/inc/ui/class-domain-mapping-element.php +++ b/inc/ui/class-domain-mapping-element.php @@ -203,7 +203,7 @@ public function defaults() { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { parent::init(); @@ -1095,7 +1095,7 @@ public function setup_preview(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $current_site = $this->site; diff --git a/inc/ui/class-invoices-element.php b/inc/ui/class-invoices-element.php index f89e60b4b..f04e228fa 100644 --- a/inc/ui/class-invoices-element.php +++ b/inc/ui/class-invoices-element.php @@ -270,7 +270,7 @@ public function setup_preview(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $this->ensure_setup(); diff --git a/inc/ui/class-limits-element.php b/inc/ui/class-limits-element.php index 35b882dce..c0b110d83 100644 --- a/inc/ui/class-limits-element.php +++ b/inc/ui/class-limits-element.php @@ -236,7 +236,7 @@ public function setup_preview(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $this->ensure_setup(); diff --git a/inc/ui/class-login-form-element.php b/inc/ui/class-login-form-element.php index 28a60dc65..494119499 100644 --- a/inc/ui/class-login-form-element.php +++ b/inc/ui/class-login-form-element.php @@ -60,7 +60,7 @@ class Login_Form_Element extends Base_Element { * @since 2.0.11 * @return void */ - public function init(): void { + public function init() { // Handle login redirection add_filter('login_redirect', [$this, 'handle_redirect'], -1, 3); @@ -582,7 +582,7 @@ public function get_logout_url() { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $view = 'dashboard-widgets/login-additional-forms'; diff --git a/inc/ui/class-magic-link-url-element.php b/inc/ui/class-magic-link-url-element.php index a7c9c33a7..ebbdf3af1 100644 --- a/inc/ui/class-magic-link-url-element.php +++ b/inc/ui/class-magic-link-url-element.php @@ -373,7 +373,7 @@ protected function generate_url(int $site_id, string $redirect_to = ''): ?string * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $this->ensure_setup(); diff --git a/inc/ui/class-my-sites-element.php b/inc/ui/class-my-sites-element.php index edbbf4de8..b0b3e8b90 100644 --- a/inc/ui/class-my-sites-element.php +++ b/inc/ui/class-my-sites-element.php @@ -321,7 +321,7 @@ public function setup_preview(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $atts['customer'] = $this->customer; diff --git a/inc/ui/class-payment-methods-element.php b/inc/ui/class-payment-methods-element.php index 441301b06..5884f5fac 100644 --- a/inc/ui/class-payment-methods-element.php +++ b/inc/ui/class-payment-methods-element.php @@ -185,7 +185,7 @@ public function setup_preview(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $gateway_id = $this->membership ? $this->membership->get_gateway() : ''; $gateway = $gateway_id ? wu_get_gateway($gateway_id) : null; diff --git a/inc/ui/class-simple-text-element.php b/inc/ui/class-simple-text-element.php index 779778eed..52b8de007 100644 --- a/inc/ui/class-simple-text-element.php +++ b/inc/ui/class-simple-text-element.php @@ -215,7 +215,7 @@ public function defaults() { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { wu_get_template('dashboard-widgets/simple-text', $atts); } diff --git a/inc/ui/class-site-actions-element.php b/inc/ui/class-site-actions-element.php index 0364360b4..540208a75 100644 --- a/inc/ui/class-site-actions-element.php +++ b/inc/ui/class-site-actions-element.php @@ -303,7 +303,7 @@ public function setup_preview(): void { * @since 2.0.21 * @return void */ - public function init(): void { + public function init() { parent::init(); @@ -1554,7 +1554,7 @@ public function handle_resubscribe_membership(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $atts['actions'] = $this->get_actions($atts); diff --git a/inc/ui/class-site-maintenance-element.php b/inc/ui/class-site-maintenance-element.php index e572f5a2b..d6d533a7d 100644 --- a/inc/ui/class-site-maintenance-element.php +++ b/inc/ui/class-site-maintenance-element.php @@ -52,7 +52,7 @@ class Site_Maintenance_Element extends Base_Element { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { if (wu_get_setting('maintenance_mode')) { parent::init(); @@ -266,7 +266,7 @@ public function register_scripts(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $fields = [ 'maintenance_mode' => [ diff --git a/inc/ui/class-template-previewer.php b/inc/ui/class-template-previewer.php index f345903eb..a065e4492 100644 --- a/inc/ui/class-template-previewer.php +++ b/inc/ui/class-template-previewer.php @@ -42,7 +42,7 @@ class Template_Previewer { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { add_action('plugins_loaded', [$this, 'hooks']); } diff --git a/inc/ui/class-template-switching-element.php b/inc/ui/class-template-switching-element.php index 43bd38fab..61b629eb7 100644 --- a/inc/ui/class-template-switching-element.php +++ b/inc/ui/class-template-switching-element.php @@ -101,7 +101,7 @@ public function get_description() { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { add_action('wu_ajax_wu_switch_template', [$this, 'switch_template']); @@ -324,7 +324,7 @@ public function switch_template() { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { if ($this->site) { $filter_template_limits = \WP_Ultimo\Limits\Site_Template_Limits::get_instance(); diff --git a/inc/ui/class-thank-you-element.php b/inc/ui/class-thank-you-element.php index 31076bab7..0e73f0df0 100644 --- a/inc/ui/class-thank-you-element.php +++ b/inc/ui/class-thank-you-element.php @@ -366,7 +366,7 @@ public function setup_preview(): void { * @param string|null $content The content inside the shortcode. * @return void */ - public function output($atts, $content = null): void { + public function output($atts, $content = null) { $atts['payment'] = $this->payment; diff --git a/inc/ui/class-toolbox.php b/inc/ui/class-toolbox.php index a3940f1ef..44cdcfa67 100644 --- a/inc/ui/class-toolbox.php +++ b/inc/ui/class-toolbox.php @@ -27,7 +27,7 @@ class Toolbox { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { add_action('init', [$this, 'load_toolbox']); } @@ -85,7 +85,7 @@ public function enqueue_styles(): void { * @since 2.0.0 * @return void */ - public function output(): void { + public function output() { $current_site = wu_get_current_site(); diff --git a/inc/ui/class-tours.php b/inc/ui/class-tours.php index 55054262d..58b55c320 100644 --- a/inc/ui/class-tours.php +++ b/inc/ui/class-tours.php @@ -35,7 +35,7 @@ class Tours { * @since 2.0.0 * @return void */ - public function init(): void { + public function init() { add_action('wp_ajax_wu_mark_tour_as_finished', [$this, 'mark_as_finished']); From 74224b26d85806351e6942c74f38ce6112f6a291 Mon Sep 17 00:00:00 2001 From: David Stone Date: Fri, 10 Apr 2026 10:10:44 -0600 Subject: [PATCH 3/3] docs: add @extensible annotations to base classes to prevent return type regressions Adds a class-level @extensible PHPDoc tag to all 6 base/abstract classes that external addons extend. The annotation warns developers and AI agents not to add PHP return type declarations to public methods on these classes. Also updates AGENTS.md to replace the old 'Return type void on init methods' instruction (which caused this bug) with an explicit prohibition on adding return types to extensible base classes. Defense layers: 1. AGENTS.md instruction (catches AI agents at prompt level) 2. @extensible PHPDoc on each class (catches humans reading the code) 3. @return PHPDoc tags preserved (gives IDEs/PHPStan type info without the PHP-enforced contract that breaks child classes) --- AGENTS.md | 8 +++++++- inc/checkout/signup-fields/class-base-signup-field.php | 5 +++++ inc/gateways/class-base-gateway.php | 5 +++++ inc/integrations/class-base-capability-module.php | 5 +++++ .../host-providers/class-base-host-provider.php | 5 +++++ inc/models/class-base-model.php | 7 ++++++- inc/ui/class-base-element.php | 5 +++++ 7 files changed, 38 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2b0e3095a..c4b3e044b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -86,7 +86,13 @@ assets/ # JS, CSS, images, fonts - **Ternary**: Short ternary `?:` allowed. - **Yoda conditions**: Required in production code (`'value' === $var`). Not required in tests. - **Strings**: Single quotes preferred. Double quotes only when interpolating. -- **Type hints**: Use where present in existing code. Return type `void` on init methods. +- **Type hints**: Use where present in existing code. **NEVER add PHP return type + declarations (`: void`, `: string`, `: bool`, etc.) to public methods on base/abstract + classes or interfaces** — external addons extend these classes and PHP will fatal if + the child class doesn't declare the same return type. Use `@return` PHPDoc tags instead. + This applies to all classes in `inc/gateways/`, `inc/ui/class-base-element.php`, + `inc/models/class-base-model.php`, `inc/integrations/`, and `inc/checkout/signup-fields/`. + Private and final methods may use PHP return types freely. - **PHPDoc**: Required on classes and public methods in `inc/`. Not required in `tests/`. Every file header: `@package WP_Ultimo`, `@subpackage`, `@since`. - **Security guard**: Every PHP file starts with `defined('ABSPATH') || exit;`. diff --git a/inc/checkout/signup-fields/class-base-signup-field.php b/inc/checkout/signup-fields/class-base-signup-field.php index 33c37c8e1..2071892a8 100644 --- a/inc/checkout/signup-fields/class-base-signup-field.php +++ b/inc/checkout/signup-fields/class-base-signup-field.php @@ -15,6 +15,11 @@ /** * Creates an cart with the parameters of the purchase being placed. * + * @extensible External addons extend this class to create custom signup fields. + * Do NOT add PHP return type declarations to public methods — it will + * cause a fatal Compile Error in any addon that overrides the method + * without the matching return type. Use @return PHPDoc tags instead. + * * @package WP_Ultimo * @subpackage Checkout * @since 2.0.0 diff --git a/inc/gateways/class-base-gateway.php b/inc/gateways/class-base-gateway.php index 026bf40ae..3b7e74c32 100644 --- a/inc/gateways/class-base-gateway.php +++ b/inc/gateways/class-base-gateway.php @@ -20,6 +20,11 @@ * For more info on actual implementations, * check the Gateway_Manual class and the Gateway_Stripe class. * + * @extensible External addons (e.g. WooCommerce, custom gateways) extend this class. + * Do NOT add PHP return type declarations to public methods — it will + * cause a fatal Compile Error in any addon that overrides the method + * without the matching return type. Use @return PHPDoc tags instead. + * * @since 2.0.0 */ abstract class Base_Gateway { diff --git a/inc/integrations/class-base-capability-module.php b/inc/integrations/class-base-capability-module.php index c044f295d..8453c3c05 100644 --- a/inc/integrations/class-base-capability-module.php +++ b/inc/integrations/class-base-capability-module.php @@ -17,6 +17,11 @@ /** * Abstract base class for capability modules. * + * @extensible External addons extend this class to add capability modules. + * Do NOT add PHP return type declarations to public methods — it will + * cause a fatal Compile Error in any addon that overrides the method + * without the matching return type. Use @return PHPDoc tags instead. + * * @since 2.5.0 */ abstract class Base_Capability_Module implements Capability_Module { diff --git a/inc/integrations/host-providers/class-base-host-provider.php b/inc/integrations/host-providers/class-base-host-provider.php index 2b8b91c0e..7790c3eb9 100644 --- a/inc/integrations/host-providers/class-base-host-provider.php +++ b/inc/integrations/host-providers/class-base-host-provider.php @@ -20,6 +20,11 @@ * Implements DNS_Provider_Interface to provide default DNS management functionality. * Providers that support DNS should add 'dns-management' to their $supports array * and override the DNS methods. + * + * @extensible External addons extend this class to add hosting provider integrations. + * Do NOT add PHP return type declarations to public methods — it will + * cause a fatal Compile Error in any addon that overrides the method + * without the matching return type. Use @return PHPDoc tags instead. */ abstract class Base_Host_Provider implements DNS_Provider_Interface { diff --git a/inc/models/class-base-model.php b/inc/models/class-base-model.php index 8b782004f..a851b79e4 100644 --- a/inc/models/class-base-model.php +++ b/inc/models/class-base-model.php @@ -17,11 +17,16 @@ defined('ABSPATH') || exit; /** - * Abstract base model for our data types + * Abstract base model for our data types. * * This class is the base class that is extended by all of our data types * such as plans, coupons, broadcasts, domains, etc. * + * @extensible External addons may extend this class to create custom models. + * Do NOT add PHP return type declarations to public methods — it will + * cause a fatal Compile Error in any addon that overrides the method + * without the matching return type. Use @return PHPDoc tags instead. + * * @since 2.0.0 */ abstract class Base_Model implements \JsonSerializable { diff --git a/inc/ui/class-base-element.php b/inc/ui/class-base-element.php index acfbf6a0b..7b8fbcbb8 100644 --- a/inc/ui/class-base-element.php +++ b/inc/ui/class-base-element.php @@ -17,6 +17,11 @@ /** * Base class to UI elements that are rendered on the backend and the frontend. * + * @extensible External addons extend this class to create custom UI elements. + * Do NOT add PHP return type declarations to public methods — it will + * cause a fatal Compile Error in any addon that overrides the method + * without the matching return type. Use @return PHPDoc tags instead. + * * @since 2.0.0 */ abstract class Base_Element {