Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<p align="center">
<a href="https://github.com/superdav42/wp-multisite-waas/actions/workflows/tests.yml"><img src="https://github.com/superdav42/wp-multisite-waas/actions/workflows/tests.yml/badge.svg" alt="Unit & Integration Tests"></a>
<a href="https://github.com/superdav42/wp-multisite-waas/actions/workflows/e2e.yml"><img src="https://github.com/superdav42/wp-multisite-waas/actions/workflows/e2e.yml/badge.svg" alt="E2E Tests"></a>
<a href="https://img.shields.io/coderabbit/prs/github/superdav42/wp-multisite-waas?utm_source=oss&utm_medium=github&utm_campaign=superdav42%2Fwp-multisite-waas&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews"><img src="https://img.shields.io/coderabbit/prs/github/superdav42/wp-multisite-waas?utm_source=oss&utm_medium=github&utm_campaign=superdav42%2Fwp-multisite-waas&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews" alt="E2E Tests"></a>
</p>

## 🌟 Overview
Expand Down
430 changes: 366 additions & 64 deletions assets/js/lib/apexcharts.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion assets/js/lib/apexcharts.min.js

Large diffs are not rendered by default.

180 changes: 135 additions & 45 deletions assets/js/lib/shepherd.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion assets/js/lib/shepherd.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion inc/admin-pages/class-edit-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
namespace WP_Ultimo\Admin_Pages;

// Exit if accessed directly
use WP_Ultimo\Models\Limitable;
use WP_Ultimo\Models\Interfaces\Limitable;

defined('ABSPATH') || exit;

Expand Down
38 changes: 23 additions & 15 deletions inc/class-sunrise.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ public static function load_dependencies(): void {
require_once __DIR__ . '/functions/array-helpers.php';
require_once __DIR__ . '/traits/trait-singleton.php';
require_once __DIR__ . '/objects/class-limitations.php';
require_once __DIR__ . '/models/interface-limitable.php';
require_once __DIR__ . '/models/interfaces/interface-limitable.php';
require_once __DIR__ . '/models/interfaces/interface-notable.php';
require_once __DIR__ . '/models/interfaces/interface-billable.php';
require_once __DIR__ . '/models/traits/trait-limitable.php';
require_once __DIR__ . '/models/traits/trait-notable.php';
require_once __DIR__ . '/models/traits/trait-billable.php';
Expand Down Expand Up @@ -306,17 +308,19 @@ protected static function read_sunrise_meta() {
return self::$sunrise_meta;
}

$sunrise_meta = get_network_option(null, 'wu_sunrise_meta', null);

$existing = [];

if ($sunrise_meta) {
$existing = $sunrise_meta;

self::$sunrise_meta = $existing;
}
self::$sunrise_meta = get_network_option(
null,
'wu_sunrise_meta',
[
'active' => false,
'created' => 'unknown',
'last_activated' => 'unknown',
'last_deactivated' => 'unknown',
'last_modified' => 'unknown',
]
);

return $existing;
return self::$sunrise_meta;
}
Comment on lines +311 to 324
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Fix: TypeError risk from default 'unknown' timestamps breaks gmdate and the pipeline.

read_sunrise_meta now defaults created/last_* to string 'unknown'. system_info passes these to gmdate as the timestamp arg, causing “gmdate() expects parameter 2 to be int, string given” and failing tests. Default these to integers.

Apply this diff:

-        self::$sunrise_meta = get_network_option(
+        self::$sunrise_meta = get_network_option(
             null,
             'wu_sunrise_meta',
             [
-                'active'           => false,
-                'created'          => 'unknown',
-                'last_activated'   => 'unknown',
-                'last_deactivated' => 'unknown',
-                'last_modified'    => 'unknown',
+                'active'           => false,
+                'created'          => 0,
+                'last_activated'   => 0,
+                'last_deactivated' => 0,
+                'last_modified'    => 0,
             ]
         );

Re-run unit tests after this change; it should eliminate the gmdate TypeError in Sunrise_Test.


🏁 Script executed:

#!/bin/bash
# Locate the read_sunrise_meta method and its defaults
rg -nP 'function\s+read_sunrise_meta' -C5 inc/class-sunrise.php

# Confirm the get_network_option defaults for wu_sunrise_meta
rg -n 'wu_sunrise_meta' -nC3 inc/class-sunrise.php

# Find where gmdate is used across the codebase
rg -n --type=php 'gmdate' -C3 .

# Locate the system_info method to see how sunrise_meta values are passed to gmdate
rg -nP 'function\s+system_info' -C5 inc/class-sunrise.php

Length of output: 25728


🏁 Script executed:

#!/bin/bash
# Display the read_sunrise_meta defaults (around lines 300–330)
sed -n '300,330p' inc/class-sunrise.php

# Display the system_info merge and gmdate usage (around lines 350–380)
sed -n '350,380p' inc/class-sunrise.php

Length of output: 1598


Update default sunrise_meta timestamps and adjust tests accordingly

Changing the defaults from the string 'unknown' to the integer 0 will prevent gmdate() from throwing a TypeError at runtime, but the existing Sunrise_Test is explicitly catching and asserting a TypeError. You will need to:

• In inc/class-sunrise.php, update read_sunrise_meta() defaults:

@@ protected static function read_sunrise_meta() {
-            [
-                'active'           => false,
-                'created'          => 'unknown',
-                'last_activated'   => 'unknown',
-                'last_deactivated' => 'unknown',
-                'last_modified'    => 'unknown',
-            ]
+            [
+                'active'           => false,
+                'created'          => 0,
+                'last_activated'   => 0,
+                'last_deactivated' => 0,
+                'last_modified'    => 0,
+            ]

• In tests/WP_Ultimo/Sunrise_Test.php, remove or update the try { … } catch (TypeError $e) blocks that expect a “gmdate” TypeError. Instead, assert that the returned $sys_info fields are the Unix-epoch date for zero:

-    try {
-        $result = Sunrise::system_info([ 'existing' => 'data' ]);
-        $this->assertEquals('data', $result['existing']);
-    } catch (\TypeError $e) {
-        // expected when missing or wrong types
-        $this->assertStringContainsString('gmdate', $e->getMessage());
-    }
+    $result = Sunrise::system_info([ 'existing' => 'data' ]);
+    $this->assertEquals('data', $result['existing']);
+    $epoch = gmdate('Y-m-d @ H:i:s', 0);
+    $this->assertEquals($epoch, $result['sunrise-created']);
+    $this->assertEquals($epoch, $result['sunrise-last-activated']);
+    $this->assertEquals($epoch, $result['sunrise-last-deactivated']);
+    $this->assertEquals($epoch, $result['sunrise-last-modified']);

After these updates, re-run the unit tests to ensure Sunrise_Test now verifies the epoch defaults rather than a thrown error.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self::$sunrise_meta = get_network_option(
null,
'wu_sunrise_meta',
[
'active' => false,
'created' => 'unknown',
'last_activated' => 'unknown',
'last_deactivated' => 'unknown',
'last_modified' => 'unknown',
]
);
return $existing;
return self::$sunrise_meta;
}
protected static function read_sunrise_meta() {
self::$sunrise_meta = get_network_option(
null,
'wu_sunrise_meta',
[
'active' => false,
'created' => 0,
'last_activated' => 0,
'last_deactivated' => 0,
'last_modified' => 0,
]
);
return self::$sunrise_meta;
}
🤖 Prompt for AI Agents
In inc/class-sunrise.php around lines 311–324, the default timestamp fields in
read_sunrise_meta() are set to the string 'unknown' which causes gmdate()
TypeErrors; change those defaults to the integer 0 so functions receive numeric
timestamps. Then update tests in tests/WP_Ultimo/Sunrise_Test.php to remove the
try/catch blocks expecting a TypeError and instead assert that the returned
sys_info timestamp-derived fields equal the Unix-epoch date/time for zero (e.g.,
gmdate-format values for epoch), and re-run the unit tests to validate the new
assertions.


/**
Expand Down Expand Up @@ -347,22 +351,22 @@ public static function system_info($sys_info) {
'sunrise-created' => [
'tooltip' => '',
'title' => 'Created',
'value' => gmdate('Y-m-d @ H:i:s', $data['created']),
'value' => is_int($data['created']) ? gmdate('Y-m-d @ H:i:s', $data['created']) : $data['created'],
],
'sunrise-last-activated' => [
'tooltip' => '',
'title' => 'Last Activated',
'value' => gmdate('Y-m-d @ H:i:s', $data['last_activated']),
'value' => is_int($data['last_activated']) ? gmdate('Y-m-d @ H:i:s', $data['last_activated']) : $data['last_activated'],
],
'sunrise-last-deactivated' => [
'tooltip' => '',
'title' => 'Last Deactivated',
'value' => gmdate('Y-m-d @ H:i:s', $data['last_deactivated']),
'value' => is_int($data['last_deactivated']) ? gmdate('Y-m-d @ H:i:s', $data['last_deactivated']) : $data['last_deactivated'],
],
'sunrise-last-modified' => [
'tooltip' => '',
'title' => 'Last Modified',
'value' => gmdate('Y-m-d @ H:i:s', $data['last_modified']),
'value' => is_int($data['last_modified']) ? gmdate('Y-m-d @ H:i:s', $data['last_modified']) : $data['last_modified'],
],
Comment on lines 351 to 370
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

is_int() guard won’t ever format: values are stored as strings elsewhere

Because tap() sets timestamps via gmdate('U') (a string), these fields won’t pass is_int(), so system_info will output raw numbers instead of formatted dates. Either store ints or accept numeric strings in the formatter.

Two compatible options (doing both is safest during migration):

  • Option A (formatter hardening): accept numeric strings and cast
-                        'value'   => is_int($data['created']) ? gmdate('Y-m-d @ H:i:s', $data['created']) : $data['created'],
+                        'value'   => is_numeric($data['created']) ? gmdate('Y-m-d @ H:i:s', (int) $data['created']) : $data['created'],
@@
-                        'value'   => is_int($data['last_activated']) ? gmdate('Y-m-d @ H:i:s', $data['last_activated']) : $data['last_activated'],
+                        'value'   => is_numeric($data['last_activated']) ? gmdate('Y-m-d @ H:i:s', (int) $data['last_activated']) : $data['last_activated'],
@@
-                        'value'   => is_int($data['last_deactivated']) ? gmdate('Y-m-d @ H:i:s', $data['last_deactivated']) : $data['last_deactivated'],
+                        'value'   => is_numeric($data['last_deactivated']) ? gmdate('Y-m-d @ H:i:s', (int) $data['last_deactivated']) : $data['last_deactivated'],
@@
-                        'value'   => is_int($data['last_modified']) ? gmdate('Y-m-d @ H:i:s', $data['last_modified']) : $data['last_modified'],
+                        'value'   => is_numeric($data['last_modified']) ? gmdate('Y-m-d @ H:i:s', (int) $data['last_modified']) : $data['last_modified'],
  • Option B (preferred): store ints at the source; see the tap() comments below to switch from string to int.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'sunrise-created' => [
'tooltip' => '',
'title' => 'Created',
'value' => gmdate('Y-m-d @ H:i:s', $data['created']),
'value' => is_int($data['created']) ? gmdate('Y-m-d @ H:i:s', $data['created']) : $data['created'],
],
'sunrise-last-activated' => [
'tooltip' => '',
'title' => 'Last Activated',
'value' => gmdate('Y-m-d @ H:i:s', $data['last_activated']),
'value' => is_int($data['last_activated']) ? gmdate('Y-m-d @ H:i:s', $data['last_activated']) : $data['last_activated'],
],
'sunrise-last-deactivated' => [
'tooltip' => '',
'title' => 'Last Deactivated',
'value' => gmdate('Y-m-d @ H:i:s', $data['last_deactivated']),
'value' => is_int($data['last_deactivated']) ? gmdate('Y-m-d @ H:i:s', $data['last_deactivated']) : $data['last_deactivated'],
],
'sunrise-last-modified' => [
'tooltip' => '',
'title' => 'Last Modified',
'value' => gmdate('Y-m-d @ H:i:s', $data['last_modified']),
'value' => is_int($data['last_modified']) ? gmdate('Y-m-d @ H:i:s', $data['last_modified']) : $data['last_modified'],
],
// In inc/class-sunrise.php, inside the system_info() array construction:
'sunrise-created' => [
'tooltip' => '',
'title' => 'Created',
'value' => is_numeric($data['created'])
? gmdate('Y-m-d @ H:i:s', (int) $data['created'])
: $data['created'],
],
'sunrise-last-activated' => [
'tooltip' => '',
'title' => 'Last Activated',
'value' => is_numeric($data['last_activated'])
? gmdate('Y-m-d @ H:i:s', (int) $data['last_activated'])
: $data['last_activated'],
],
'sunrise-last-deactivated' => [
'tooltip' => '',
'title' => 'Last Deactivated',
'value' => is_numeric($data['last_deactivated'])
? gmdate('Y-m-d @ H:i:s', (int) $data['last_deactivated'])
: $data['last_deactivated'],
],
'sunrise-last-modified' => [
'tooltip' => '',
'title' => 'Last Modified',
'value' => is_numeric($data['last_modified'])
? gmdate('Y-m-d @ H:i:s', (int) $data['last_modified'])
: $data['last_modified'],
],
🤖 Prompt for AI Agents
inc/class-sunrise.php around lines 351 to 370: the current is_int() guards never
match because timestamps are stored as numeric strings (gmdate('U')), so dates
are not formatted; fix by either (A) making the formatter accept numeric strings
(use is_numeric() or cast to int before passing to gmdate) so string timestamps
are formatted, and/or (B — preferred) change the source that writes timestamps
to store integers (use (int) time() or intval(gmdate('U'))); doing both
(hardening the formatter and migrating stored values to ints) is safest during
rollout.

],
]
Expand Down Expand Up @@ -443,6 +447,10 @@ protected static function tap($mode = 'activating', $existing = []) {
]
);

if ('unknown' === $to_save['created']) {
$to_save['created'] = $now;
}

if ('activating' === $mode) {
$to_save['active'] = true;
$to_save['last_activated'] = $now;
Expand Down
39 changes: 20 additions & 19 deletions inc/managers/class-limitation-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
defined('ABSPATH') || exit;

use Psr\Log\LogLevel;
use WP_Ultimo\Objects\Limitations;
use WP_Ultimo\Database\Sites\Site_Type;
use WP_Ultimo\Objects\Limitations;

/**
* Handles processes related to limitations.
Expand Down Expand Up @@ -226,10 +226,10 @@ public function handle_confirm_limitations_reset(): void {
/**
* Returns the type of the object that has limitations.
*
* @since 2.0.0
* @param \WP_Ultimo\Models\Interfaces\Limitable $object_model Model to test.
*
* @param \WP_Ultimo\Models\Limitable $object_model Model to test.
* @return string
* @since 2.0.0
*/
public function get_object_type($object_model) {

Expand All @@ -249,11 +249,11 @@ public function get_object_type($object_model) {
/**
* Injects the limitations panels when necessary.
*
* @since 2.0.0
* @param array $sections List of tabbed widget sections.
* @param \WP_Ultimo\Models\Interfaces\Limitable $object_model The model being edited.
*
* @param array $sections List of tabbed widget sections.
* @param \WP_Ultimo\Models\Limitable $object_model The model being edited.
* @return array
* @since 2.0.0
*/
public function add_limitation_sections($sections, $object_model) {

Expand Down Expand Up @@ -571,11 +571,11 @@ protected function override_notice($show = false, $additional_checks = []) {
/**
* Register the user roles fields
*
* @since 2.0.0
* @param array $sections Sections and fields.
* @param \WP_Ultimo\Models\Interfaces\Limitable $object_model The object being edit.
*
* @param array $sections Sections and fields.
* @param \WP_Ultimo\Models\Limitable $object_model The object being edit.
* @return void
* @since 2.0.0
*/
public function register_user_fields(&$sections, $object_model): void {

Expand Down Expand Up @@ -636,11 +636,11 @@ public function register_user_fields(&$sections, $object_model): void {
/**
* Register the post type fields
*
* @since 2.0.0
* @param array $sections Sections and fields.
* @param \WP_Ultimo\Models\Interfaces\Limitable $object_model The object being edit.
*
* @param array $sections Sections and fields.
* @param \WP_Ultimo\Models\Limitable $object_model The object being edit.
* @return void
* @since 2.0.0
*/
public function register_post_type_fields(&$sections, $object_model): void {

Expand Down Expand Up @@ -706,13 +706,14 @@ public function register_post_type_fields(&$sections, $object_model): void {
}
}


/**
* Returns the list of fields for the site tab.
*
* @since 2.0.0
* @param \WP_Ultimo\Models\Interfaces\Limitable $object_model The model being edited.
*
* @param \WP_Ultimo\Models\Limitable $object_model The model being edited.
* @return array
* @since 2.0.0
*/
protected function get_sites_fields($object_model) {

Expand Down Expand Up @@ -768,10 +769,10 @@ protected function get_sites_fields($object_model) {
/**
* Returns the HTML markup for the plugin selector list.
*
* @since 2.0.0
* @param \WP_Ultimo\Models\Interfaces\Limitable $object_model The model being edited.
*
* @param \WP_Ultimo\Models\Limitable $object_model The model being edited.
* @return string
* @since 2.0.0
*/
public function get_plugin_selection_list($object_model) {

Expand All @@ -789,11 +790,11 @@ public function get_plugin_selection_list($object_model) {
/**
* Returns the HTML markup for the plugin selector list.
*
* @since 2.0.0
* @param \WP_Ultimo\Models\Interfaces\Limitable $obj The model being edited.
* @param array $section The section array.
*
* @param \WP_Ultimo\Models\Limitable $obj The model being edited.
* @param array $section The section array.
* @return string
* @since 2.0.0
*/
public function get_theme_selection_list($obj, &$section) {

Expand Down
4 changes: 3 additions & 1 deletion inc/managers/class-notes-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
namespace WP_Ultimo\Managers;

// Exit if accessed directly
use WP_Ultimo\Models\Traits\Notable;

defined('ABSPATH') || exit;

/**
Expand Down Expand Up @@ -108,7 +110,7 @@ public function register_forms(): void {
* @since 2.0.0
*
* @param array $sections Array sections.
* @param object $obj The object.
* @param \WP_Ultimo\Models\Interfaces\Notable $obj The object.
*
* @return array
*/
Expand Down
4 changes: 3 additions & 1 deletion inc/models/class-customer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
namespace WP_Ultimo\Models;

use WP_Ultimo\Models\Base_Model;
use WP_Ultimo\Models\Interfaces\Billable;
use WP_Ultimo\Models\Interfaces\Notable;
use WP_Ultimo\Models\Membership;
use WP_Ultimo\Models\Site;
use WP_Ultimo\Models\Payment;
Expand All @@ -22,7 +24,7 @@
*
* @since 2.0.0
*/
class Customer extends Base_Model {
class Customer extends Base_Model implements Billable, Notable {

use Traits\Billable;
use Traits\Notable;
Expand Down
10 changes: 5 additions & 5 deletions inc/models/class-membership.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@

namespace WP_Ultimo\Models;

use WP_Ultimo\Models\Base_Model;
use WP_Ultimo\Models\Product;
use WP_Ultimo\Models\Site;
use WP_Ultimo\Database\Memberships\Membership_Status;
use WP_Ultimo\Checkout\Cart;
use WP_Ultimo\Database\Memberships\Membership_Status;
use WP_Ultimo\Models\Interfaces\Billable;
use WP_Ultimo\Models\Interfaces\Limitable;
use WP_Ultimo\Models\Interfaces\Notable;

// Exit if accessed directly
defined('ABSPATH') || exit;
Expand All @@ -23,7 +23,7 @@
*
* @since 2.0.0
*/
class Membership extends Base_Model implements Limitable {
class Membership extends Base_Model implements Limitable, Billable, Notable {

use Traits\Limitable;
use Traits\Billable;
Expand Down
3 changes: 2 additions & 1 deletion inc/models/class-payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace WP_Ultimo\Models;

use WP_Ultimo\Models\Base_Model;
use WP_Ultimo\Models\Interfaces\Notable;
use WP_Ultimo\Database\Payments\Payment_Status;
use WP_Ultimo\Checkout\Line_Item;
use WP_Ultimo\Models\Customer;
Expand All @@ -24,7 +25,7 @@
*
* @since 2.0.0
*/
class Payment extends Base_Model {
class Payment extends Base_Model implements Notable {

use Traits\Notable;

Expand Down
2 changes: 1 addition & 1 deletion inc/models/class-product.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
// Exit if accessed directly
defined('ABSPATH') || exit;

use WP_Ultimo\Models\Base_Model;
use WP_Ultimo\Database\Products\Product_Type;
use WP_Ultimo\Models\Interfaces\Limitable;

/**
* Product model class. Implements the Base Model.
Expand Down
6 changes: 3 additions & 3 deletions inc/models/class-site.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
namespace WP_Ultimo\Models;

use Psr\Log\LogLevel;
use WP_Ultimo\Models\Base_Model;
use WP_Ultimo\Objects\Limitations;
use WP_Ultimo\Database\Sites\Site_Type;
use WP_Ultimo\Models\Interfaces\Limitable;
use WP_Ultimo\Models\Interfaces\Notable;
use WP_Ultimo\UI\Template_Previewer;

// Exit if accessed directly
Expand All @@ -23,7 +23,7 @@
*
* @since 2.0.0
*/
class Site extends Base_Model implements Limitable {
class Site extends Base_Model implements Limitable, Notable {

use Traits\Limitable;
use \WP_Ultimo\Traits\WP_Ultimo_Site_Deprecated;
Expand Down
47 changes: 47 additions & 0 deletions inc/models/interfaces/interface-billable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
/**
* Interface for billable models.
*
* @package WP_Ultimo
* @subpackage Models\Interfaces
* @since 2.0.0
*/

namespace WP_Ultimo\Models\Interfaces;

defined( 'ABSPATH' ) || exit;

/**
* Billable interface.
*/
Comment on lines +14 to +16
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Typo: “trait” → “interface” in docblock

Docblock says “Classes that implement this trait” but this is an interface.

- * Classes that implement this trait need to implement
+ * Classes that implement this interface need to implement
🤖 Prompt for AI Agents
In inc/models/interfaces/interface-billable.php around lines 14 to 16, the
docblock erroneously refers to this as a “trait” — update the docblock wording
to correctly call it an “interface” (e.g., change “Classes that implement this
trait” to “Classes that implement this interface” or similar), keeping the rest
of the description intact and adjusting any verb tense/grammar as needed.

interface Billable {

/**
* Returns the default billing address.
*
* Classes that implement this trait need to implement
* this method.
*
* @since 2.0.0
* @return \WP_Ultimo\Objects\Billing_Address
*/
public function get_default_billing_address();

/**
* Gets the billing address for this object.
*
* @since 2.0.0
* @return \WP_Ultimo\Objects\Billing_Address
*/
public function get_billing_address();

/**
* Sets the billing address.
*
* @since 2.0.0
*
* @param array|\WP_Ultimo\Objects\Billing_Address $billing_address The billing address.
* @return void
*/
public function set_billing_address($billing_address): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @subpackage Models
*/

namespace WP_Ultimo\Models;
namespace WP_Ultimo\Models\Interfaces;

defined( 'ABSPATH' ) || exit;

Expand Down
Loading
Loading