diff --git a/inc/admin-pages/class-base-admin-page.php b/inc/admin-pages/class-base-admin-page.php index a4bdcf0..fb35114 100644 --- a/inc/admin-pages/class-base-admin-page.php +++ b/inc/admin-pages/class-base-admin-page.php @@ -188,7 +188,7 @@ abstract class Base_Admin_Page { /* * Add forms */ - add_action('plugins_loaded', [$this, 'register_forms']); + $this->register_forms(); /** * Allow plugin developers to run additional things when pages are registered. diff --git a/inc/admin-pages/class-customer-edit-admin-page.php b/inc/admin-pages/class-customer-edit-admin-page.php index b6313c9..c30f48d 100644 --- a/inc/admin-pages/class-customer-edit-admin-page.php +++ b/inc/admin-pages/class-customer-edit-admin-page.php @@ -108,6 +108,8 @@ class Customer_Edit_Admin_Page extends Edit_Admin_Page { wp_enqueue_style('wu-flags'); + wp_enqueue_script_module('wu-flags-polyfill'); + wp_enqueue_editor(); wp_enqueue_media(); @@ -944,10 +946,10 @@ class Customer_Edit_Admin_Page extends Edit_Admin_Page { if ($country_code) { $html = sprintf( - '%s', + '%s%s', $country_name, - strtolower((string) $country_code), - wu_tooltip_text($country_name) + wu_tooltip_text($country_name), + wu_get_flag_emoji((string) $country_code) ); } else { $html = $country_name; diff --git a/inc/admin-pages/customer-panel/class-checkout-admin-page.php b/inc/admin-pages/customer-panel/class-checkout-admin-page.php index 3b6af34..8c5355d 100644 --- a/inc/admin-pages/customer-panel/class-checkout-admin-page.php +++ b/inc/admin-pages/customer-panel/class-checkout-admin-page.php @@ -95,7 +95,7 @@ class Checkout_Admin_Page extends \WP_Ultimo\Admin_Pages\Base_Customer_Facing_Ad */ public function get_title() { - return sprintf(__('Checkout', 'wp-ultimo')); + return __('Checkout', 'wp-ultimo'); } /** diff --git a/inc/builders/block-editor/class-block-editor-widget-manager.php b/inc/builders/block-editor/class-block-editor-widget-manager.php index d0e7ed0..1f13ced 100644 --- a/inc/builders/block-editor/class-block-editor-widget-manager.php +++ b/inc/builders/block-editor/class-block-editor-widget-manager.php @@ -64,7 +64,7 @@ class Block_Editor_Widget_Manager { */ public function is_block_preview($is_preview) { - if (defined('REST_REQUEST') && true === REST_REQUEST && 'edit' === filter_input(INPUT_GET, 'context', FILTER_SANITIZE_STRING)) { + if (defined('REST_REQUEST') && true === REST_REQUEST && ! empty($_GET['context']) && 'edit' === $_GET['context']) { // phpcs:ignore WordPress.Security.NonceVerification $is_preview = true; } diff --git a/inc/checkout/class-cart.php b/inc/checkout/class-cart.php index 6620143..88db86c 100644 --- a/inc/checkout/class-cart.php +++ b/inc/checkout/class-cart.php @@ -502,7 +502,7 @@ class Cart implements \JsonSerializable { return $this->cart_descriptor; } - $desc = wu_get_setting('company_name', __('Subscription', 'wp-ultimo')); + $desc = wu_get_setting('company_name', get_network_option(null, 'site_name')); $products = []; diff --git a/inc/class-domain-mapping.php b/inc/class-domain-mapping.php index 739e849..5f8b678 100644 --- a/inc/class-domain-mapping.php +++ b/inc/class-domain-mapping.php @@ -135,7 +135,7 @@ class Domain_Mapping { // add_action('allowed_http_origin', array($this, 'add_mapped_domains_as_allowed_origins')); /** - * On WP Multisite WaaS 1.X builds we used Mercator. The Mercator actions and filters are now deprecated. + * On WP Ultimo 1.X builds we used Mercator. The Mercator actions and filters are now deprecated. */ if (has_action('mercator_load')) { do_action_deprecated('mercator_load', [], '2.0.0', 'wu_domain_mapping_load'); diff --git a/inc/class-maintenance-mode.php b/inc/class-maintenance-mode.php index 07cb324..0b3229b 100644 --- a/inc/class-maintenance-mode.php +++ b/inc/class-maintenance-mode.php @@ -30,7 +30,7 @@ class Maintenance_Mode { */ public function init(): void { - add_action('wp_ultimo_load', [$this, 'add_settings']); + add_action('init', [$this, 'add_settings']); if (wu_get_setting('maintenance_mode')) { $this->hooks(); @@ -145,7 +145,7 @@ class Maintenance_Mode { $site_id = \WP_Ultimo\Helpers\Hash::decode(wu_request('site_hash'), 'site'); if ( ! current_user_can_for_blog($site_id, 'manage_options')) { - return wp_send_json_error( + wp_send_json_error( [ 'message' => __('You do not have the necessary permissions to perform this option.', 'wp-ultimo'), 'value' => false, diff --git a/inc/class-requirements.php b/inc/class-requirements.php index e76e9a6..ddcba7c 100644 --- a/inc/class-requirements.php +++ b/inc/class-requirements.php @@ -44,7 +44,7 @@ class Requirements { * @since 2.0.0 * @var string */ - public static $php_recommended_version = '7.4.1'; + public static $php_recommended_version = '8.2.27'; /** * Minimum WordPress version required to run WP Multisite WaaS. @@ -60,7 +60,7 @@ class Requirements { * @since 2.0.0 * @var string */ - public static $wp_recommended_version = '6.4.1'; + public static $wp_recommended_version = '6.7.2'; /** * Static-only class. diff --git a/inc/class-settings.php b/inc/class-settings.php index df6d5d7..2846863 100644 --- a/inc/class-settings.php +++ b/inc/class-settings.php @@ -91,7 +91,7 @@ class Settings { return $status; } - $status = wu_get_setting('enable_registration') ? 'all' : $status; + $status = wu_get_setting('enable_registration', true) ? 'all' : $status; return $status; } @@ -153,13 +153,8 @@ class Settings { $this->settings = wu_get_option(self::KEY); } - if (false === $this->settings || empty($this->settings)) { - if ( ! $this->saving) { - $this->saving = true; - $this->settings = $this->save_settings([], true); - } else { - return []; - } + if (empty($this->settings)) { + return []; } if ($check_caps) {} // phpcs:ignore; @@ -174,10 +169,11 @@ class Settings { * @since 1.4.0 Now we can filter settings we get. * * @param string $setting Settings name to return. - * @param mixed $default Default value for the setting if it doesn't exist. + * @param mixed $default_value Default value for the setting if it doesn't exist. + * * @return mixed The value of that setting */ - public function get_setting($setting, $default = false) { + public function get_setting($setting, $default_value = false) { $settings = $this->get_all(); @@ -185,9 +181,9 @@ class Settings { _doing_it_wrong($setting, __('Dashes are no longer supported when registering a setting. You should change it to underscores in later versions.', 'wp-ultimo'), '2.0.0'); } - $setting_value = $settings[ $setting ] ?? $default; + $setting_value = $settings[ $setting ] ?? $default_value; - return apply_filters('wu_get_setting', $setting_value, $setting, $default, $settings); + return apply_filters('wu_get_setting', $setting_value, $setting, $default_value, $settings); } /** @@ -234,7 +230,7 @@ class Settings { $sections = $this->get_sections(); - $saved_settings = ! $reset ? $this->get_all() : []; + $saved_settings = $this->get_all(); do_action('wu_before_save_settings', $settings_to_save); @@ -253,7 +249,7 @@ class Settings { $new_value = false; } - $value = $reset ? $field->default : $new_value; + $value = $new_value; $field->set_value($value); diff --git a/inc/class-sunrise.php b/inc/class-sunrise.php index cbfe9fe..663e69e 100644 --- a/inc/class-sunrise.php +++ b/inc/class-sunrise.php @@ -105,21 +105,12 @@ class Sunrise { public static function load_dependencies(): void { require_once __DIR__ . '/deprecated/early-deprecated.php'; - require_once __DIR__ . '/deprecated/mercator.php'; - - require_once __DIR__ . '/class-autoloader.php'; - require_once __DIR__ . '/functions/site.php'; - require_once __DIR__ . '/functions/debug.php'; - require_once __DIR__ . '/functions/url.php'; - require_once __DIR__ . '/functions/number-helpers.php'; - 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/traits/trait-limitable.php'; @@ -127,6 +118,10 @@ class Sunrise { require_once __DIR__ . '/traits/trait-wp-ultimo-site-deprecated.php'; require_once __DIR__ . '/database/engine/class-enum.php'; require_once __DIR__ . '/database/sites/class-site-type.php'; + require_once __DIR__ . '/../vendor/berlindb/core/src/Database/Base.php'; + require_once __DIR__ . '/../vendor/berlindb/core/src/Database/Query.php'; + require_once __DIR__ . '/database/engine/class-query.php'; + require_once __DIR__ . '/database/sites/class-site-query.php'; require_once __DIR__ . '/models/class-base-model.php'; require_once __DIR__ . '/models/class-domain.php'; require_once __DIR__ . '/models/class-site.php'; @@ -260,49 +255,21 @@ class Sunrise { */ public static function try_upgrade() { - $possible_sunrises = [ - WP_PLUGIN_DIR . '/wp-multisite-waas/sunrise.php', - WPMU_PLUGIN_DIR . '/wp-multisite-waas/sunrise.php', - ]; + $copy_results = @copy( + dirname(WP_ULTIMO_PLUGIN_FILE) . '/sunrise.php', + WP_CONTENT_DIR . '/sunrise.php' + ); // phpcs:ignore - $sunrise_found = false; - - $error = false; - - $location = WP_CONTENT_DIR . '/sunrise.php'; - - foreach ($possible_sunrises as $new_file) { - if ( ! file_exists($new_file)) { - continue; - } - - $sunrise_found = true; - - $copy_results = @copy($new_file, $location); // phpcs:ignore - - if ( ! $copy_results) { - $error = error_get_last(); - - continue; - } - - wu_log_add('sunrise', __('Sunrise upgrade attempt succeeded.', 'wp-ultimo')); - - return true; - } - - if (false === $sunrise_found) { - $error = [ - 'message' => __('File not found.', 'wp-ultimo'), - ]; - } - - if ( ! empty($error)) { + if ( ! $copy_results) { + $error = error_get_last(); wu_log_add('sunrise', $error['message'], LogLevel::ERROR); /* translators: the placeholder is an error message */ return new \WP_Error('error', sprintf(__('Sunrise copy failed: %s', 'wp-ultimo'), $error['message'])); } + + wu_log_add('sunrise', __('Sunrise upgrade attempt succeeded.', 'wp-ultimo')); + return true; } /** diff --git a/inc/class-wp-ultimo.php b/inc/class-wp-ultimo.php index 0258c32..d0c3ca1 100644 --- a/inc/class-wp-ultimo.php +++ b/inc/class-wp-ultimo.php @@ -175,11 +175,6 @@ final class WP_Ultimo { */ $this->scripts = WP_Ultimo\Scripts::get_instance(); - /* - * Checks Sunrise versions - */ - WP_Ultimo\Sunrise::manage_sunrise_updates(); - /* * Loads tables */ @@ -205,11 +200,20 @@ final class WP_Ultimo { */ do_action('wp_ultimo_load'); + add_action('init', [$this, 'after_init']); + } + + public function after_init() { /* * Loads admin pages * @todo: move this to a manager in the future? */ $this->load_admin_pages(); + + /* + * Checks Sunrise versions + */ + WP_Ultimo\Sunrise::manage_sunrise_updates(); } /** diff --git a/inc/functions/currency.php b/inc/functions/currency.php index 4adfffe..70f6856 100644 --- a/inc/functions/currency.php +++ b/inc/functions/currency.php @@ -85,7 +85,7 @@ function wu_get_currencies(): array { function wu_get_currency_symbol($currency = '') { if ( ! $currency) { - $currency = wu_get_setting('currency_symbol'); + $currency = wu_get_setting('currency_symbol', 'USD'); } switch ($currency) { case 'AED': $currency_symbol = 'د.إ'; @@ -252,10 +252,10 @@ function wu_format_currency($value, $currency = null, $format = null, $thousands $atts = wp_parse_args( $args, [ - 'currency' => wu_get_setting('currency_symbol'), - 'format' => wu_get_setting('currency_position'), - 'thousands_sep' => wu_get_setting('thousand_separator'), - 'decimal_sep' => wu_get_setting('decimal_separator'), + 'currency' => wu_get_setting('currency_symbol', 'USD'), + 'format' => wu_get_setting('currency_position', '%s %v'), + 'thousands_sep' => wu_get_setting('thousand_separator', ','), + 'decimal_sep' => wu_get_setting('decimal_separator', '.'), 'precision' => (int) wu_get_setting('precision', 2), ] ); diff --git a/inc/functions/markup-helpers.php b/inc/functions/markup-helpers.php index 51e2ef9..3faa570 100644 --- a/inc/functions/markup-helpers.php +++ b/inc/functions/markup-helpers.php @@ -766,3 +766,27 @@ function wu_is_block_theme() { return false; } + +/** + * Generate flag emoji from a two-character country code. + * + * @param string $country_code The two-letter uppercase country code (e.g., "US", "GB"). + * @return string The flag emoji or empty string if invalid input. + */ +function wu_get_flag_emoji(string $country_code): string { + // Ensure the country code is uppercase. + $country_code = strtoupper($country_code); + + // Validate that the input is exactly two letters. + if (strlen($country_code) !== 2 || ! ctype_alpha($country_code)) { + return ''; // Return an empty string for invalid input. + } + + // Convert the country code to regional indicator symbols. + $emoji = ''; + foreach (str_split($country_code) as $char) { + $emoji .= mb_chr(0x1F1E6 - ord('A') + ord($char), 'UTF-8'); + } + + return $emoji; +} diff --git a/inc/functions/settings.php b/inc/functions/settings.php index c400c2e..f015e58 100644 --- a/inc/functions/settings.php +++ b/inc/functions/settings.php @@ -146,7 +146,7 @@ function wu_get_network_logo($size = 'full') { switch_to_blog(wu_get_main_site_id()); - $settings_logo = wp_get_attachment_image_src(wu_get_setting('company_logo'), $size); // phpcs:ignore + $settings_logo = wp_get_attachment_image_src(wu_get_setting('company_logo', ''), $size); // phpcs:ignore restore_current_blog(); diff --git a/inc/gateways/class-paypal-gateway.php b/inc/gateways/class-paypal-gateway.php index 9e23755..cef178c 100644 --- a/inc/gateways/class-paypal-gateway.php +++ b/inc/gateways/class-paypal-gateway.php @@ -358,7 +358,7 @@ class PayPal_Gateway extends Base_Gateway { */ $temp_payment = wu_membership_create_new_payment($membership, false, true, false); - $description = wu_get_setting('company_name', __('Subscription', 'wp-ultimo')) . ': ' . implode(', ', array_map(fn($item) => 'x' . $item->get_quantity() . ' ' . $item->get_title(), $temp_payment->get_line_items())); + $description = wu_get_setting('company_name', get_network_option(null, 'site_name')) . ': ' . implode(', ', array_map(fn($item) => 'x' . $item->get_quantity() . ' ' . $item->get_title(), $temp_payment->get_line_items())); $args = [ 'USER' => $this->username, diff --git a/inc/invoices/class-invoice.php b/inc/invoices/class-invoice.php index 775122e..d921bb5 100644 --- a/inc/invoices/class-invoice.php +++ b/inc/invoices/class-invoice.php @@ -243,8 +243,8 @@ class Invoice { $attributes = wp_parse_args( $attributes, [ - 'company_name' => wu_get_setting('company_name'), - 'company_address' => wu_get_setting('company_address'), + 'company_name' => wu_get_setting('company_name', get_network_option(null, 'site_name')), + 'company_address' => wu_get_setting('company_address', ''), 'primary_color' => '#675645', 'font' => 'DejaVuSansCondensed', 'logo_url' => wu_get_network_logo(), diff --git a/inc/managers/class-notification-manager.php b/inc/managers/class-notification-manager.php index 2b40692..cc8d88f 100644 --- a/inc/managers/class-notification-manager.php +++ b/inc/managers/class-notification-manager.php @@ -39,7 +39,7 @@ class Notification_Manager { */ public function init(): void { - add_action('wp_ultimo_load', [$this, 'add_settings']); + add_action('init', [$this, 'add_settings']); if (is_admin() && ! is_network_admin()) { add_action('admin_init', [$this, 'hide_notifications_subsites']); diff --git a/inc/models/class-customer.php b/inc/models/class-customer.php index 80d7b66..b85e5cd 100644 --- a/inc/models/class-customer.php +++ b/inc/models/class-customer.php @@ -730,7 +730,7 @@ class Customer extends Base_Model { * @options customer * @return void */ - public function set_type($type): void { + public function set_type($type) { $this->type = $type; } diff --git a/inc/models/class-payment.php b/inc/models/class-payment.php index 9b2e3f0..9ae7b1e 100644 --- a/inc/models/class-payment.php +++ b/inc/models/class-payment.php @@ -905,7 +905,7 @@ class Payment extends Base_Model { if (false === $this->invoice_number) { $provisional = true; - $this->invoice_number = wu_get_setting('next_invoice_number'); + $this->invoice_number = wu_get_setting('next_invoice_number', 1); } $prefix = wu_get_setting('invoice_prefix', ''); diff --git a/inc/ui/class-base-element.php b/inc/ui/class-base-element.php index 8799ef7..129787c 100644 --- a/inc/ui/class-base-element.php +++ b/inc/ui/class-base-element.php @@ -237,11 +237,14 @@ abstract class Base_Element { add_action('wu_element_preview', [$this, 'setup_preview']); - // Init should be the correct time to call this to avoid the deprecated notice from I18N. - // But it doesn't work for some reason, fix later. - // add_action('init', function () { - do_action('wu_element_loaded', $this); - // } ); + add_action( + 'init', + function () { + do_action('wu_element_loaded', $this); + }, + 5, + 0 + ); if ($this->public) { self::register_public_element($this); diff --git a/inc/ui/class-checkout-element.php b/inc/ui/class-checkout-element.php index 94ea272..67a2f65 100644 --- a/inc/ui/class-checkout-element.php +++ b/inc/ui/class-checkout-element.php @@ -570,7 +570,7 @@ class Checkout_Element extends Base_Element { return sprintf(__('Checkout form %s contains no fields.', 'wp-ultimo'), $slug); } - if ( ! $checkout_form->is_active() || ! wu_get_setting('enable_registration')) { + if ( ! $checkout_form->is_active() || ! wu_get_setting('enable_registration', true)) { return sprintf('

%s

', __('Registration is not available at this time.', 'wp-ultimo')); } diff --git a/inc/ui/class-jumper.php b/inc/ui/class-jumper.php index 28109e6..bab134f 100644 --- a/inc/ui/class-jumper.php +++ b/inc/ui/class-jumper.php @@ -46,7 +46,7 @@ class Jumper { */ public function __construct() { - add_action('wp_ultimo_load', [$this, 'add_settings'], 20); + add_action('init', [$this, 'add_settings'], 20); add_action('init', [$this, 'load_jumper']); } diff --git a/inc/ui/class-template-previewer.php b/inc/ui/class-template-previewer.php index 601f1b0..6a75d70 100644 --- a/inc/ui/class-template-previewer.php +++ b/inc/ui/class-template-previewer.php @@ -394,12 +394,13 @@ class Template_Previewer { * @since 2.0.0 * * @param string $setting The setting key. - * @param mixed $default Default value, if it is not found. + * @param mixed $default_value Default value, if it is not found. + * * @return mixed */ - public function get_setting($setting, $default = false) { - - return wu_get_isset($this->get_settings(), $setting, $default); + public function get_setting($setting, $default_value = false) { + $settings = wu_get_option(self::KEY, []); + return wu_get_isset($settings, $setting, $default_value); } /** diff --git a/inc/ui/class-thank-you-element.php b/inc/ui/class-thank-you-element.php index 69d918b..536918f 100644 --- a/inc/ui/class-thank-you-element.php +++ b/inc/ui/class-thank-you-element.php @@ -392,7 +392,7 @@ class Thank_You_Element extends Base_Element { /* * Deal with conversion tracking */ - $conversion_snippets = $atts['checkout_form']->get_conversion_snippets(); + $conversion_snippets = $atts['checkout_form'] ? $atts['checkout_form']->get_conversion_snippets() : false; if ( ! empty($conversion_snippets)) { $product_ids = []; diff --git a/tests/Admin_Pages/Dashboard_Admin_Page_Test.php b/tests/Admin_Pages/Dashboard_Admin_Page_Test.php index 530460e..10c21b3 100644 --- a/tests/Admin_Pages/Dashboard_Admin_Page_Test.php +++ b/tests/Admin_Pages/Dashboard_Admin_Page_Test.php @@ -36,7 +36,6 @@ class Dashboard_Admin_Page_Test extends WP_UnitTestCase { // Verify localized script data is correct $localized_vars = wp_scripts()->get_data('wu-dashboard-stats', 'data'); - echo($localized_vars); $this->assertStringContainsString('"month_list":["Jan ', $localized_vars); $this->assertStringContainsString('"today":"', $localized_vars); // Check that today is included $this->assertStringContainsString('"new_mrr":"New MRR"', $localized_vars); diff --git a/views/dashboard-widgets/my-sites.php b/views/dashboard-widgets/my-sites.php index b4de063..1f07a96 100644 --- a/views/dashboard-widgets/my-sites.php +++ b/views/dashboard-widgets/my-sites.php @@ -5,8 +5,6 @@ * @since 2.0.0 */ -$current_site = wu_get_current_site(); - $add_new_url = wu_get_setting('enable_multiple_sites') ? $element->get_new_site_url() : wu_get_registration_url(); // Redirect back to this page after create the site