Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
13e948c
Add options for powered by
superdav42 Sep 20, 2025
9a624df
feat: bettter
superdav42 Sep 23, 2025
61cbcb4
fix: work in progress
superdav42 Sep 26, 2025
812b53a
Merge remote-tracking branch 'origin' into poweredby
superdav42 Sep 26, 2025
a9f4291
Fix bug in action scheduler
superdav42 Sep 26, 2025
bd28d20
Scan actions scheduler dir since it don't use normal autoloader
superdav42 Sep 26, 2025
dc7ee72
Remove dump githook
superdav42 Sep 26, 2025
a0397ae
ignore a error I can't seem to get to pass
superdav42 Sep 26, 2025
a3223e0
code style
superdav42 Sep 26, 2025
5c47550
return void in an action
superdav42 Sep 26, 2025
c1a6da6
Ad recommended plugins
superdav42 Sep 26, 2025
34dff07
Add usage column to themes and plugins pages
superdav42 Sep 28, 2025
aa515f4
add missing doc params
superdav42 Sep 28, 2025
19548af
use correct hook function
superdav42 Sep 28, 2025
838f7be
fix status page
superdav42 Sep 28, 2025
484a3b8
Use correct old name
superdav42 Sep 29, 2025
1befc88
Add wu-selected-template class to selected button
superdav42 Sep 29, 2025
bac05be
add missing parameter names
superdav42 Sep 29, 2025
8576621
Escape late as it should be
superdav42 Sep 29, 2025
0545898
fix alignment
superdav42 Sep 29, 2025
bd60384
Add footer credits option
superdav42 Sep 30, 2025
b4abebf
improve columns on themes and plugins pages
superdav42 Sep 30, 2025
3a19ea4
fix resending verification email
superdav42 Sep 30, 2025
2e123ad
add correct doc return
superdav42 Sep 30, 2025
182e578
better autogenerate fields
superdav42 Sep 30, 2025
dcd4fd2
add missing credits class
superdav42 Sep 30, 2025
d53a95f
update lock file
superdav42 Sep 30, 2025
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
20 changes: 0 additions & 20 deletions .githooks/commit-msg

This file was deleted.

8 changes: 8 additions & 0 deletions assets/css/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -5359,4 +5359,12 @@ td.column-id {

#addon_more_info #plugin-information-content #section-description img {
width: 100%;
}

.multisite .plugins .column-auto-updates {
width: 9em;
}

.multisite .plugins details > summary {
cursor: pointer;
}
11 changes: 7 additions & 4 deletions assets/js/thank-you.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,13 @@ document.addEventListener("DOMContentLoaded", () => {
wu_thank_you.ajaxurl,
{
method: "POST",
body: JSON.stringify({
action: "wu_resend_verification_email",
_ajax_nonce: wu_thank_you.resend_verification_email_nonce
})
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
action: "wu_resend_verification_email",
_ajax_nonce: wu_thank_you.resend_verification_email_nonce
}),
}
);
const response = await request.json();
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "devstone/ultimate-multisite",
"url": "https://MultisiteUltimate.com",
"description": "The Multisite Website as a Service (WaaS) plugin.",
"version": "2.4.4",
"version": "2.4.5",
"authors": [
{
"name": "Arindo Duque",
Expand Down
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 13 additions & 7 deletions inc/admin-pages/class-base-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public function __construct() {
*
* @since 2.0.0
* @param string $page_id The ID of this page.
* @param string $page_hook The hook name of this page.
* @return void
*/
do_action('wu_page_added', $this->id, $this->page_hook);
Expand Down Expand Up @@ -358,7 +359,8 @@ function ($vars) {
* Allow plugin developers to add additional content before we print the page.
*
* @since 1.8.2
* @param string $this->id The id of this page.
* @param string $page_id The id of this page.
* @param object $page The page object.
* @return void
*/
do_action('wu_page_before_render', $this->id, $this);
Expand All @@ -367,7 +369,8 @@ function ($vars) {
* Allow plugin developers to add additional content before we print the page.
*
* @since 1.8.2
* @param string $this->id The id of this page.
* @param string $page_id The id of this page.
* @param object $page The page object.
* @return void
*/
do_action("wu_page_{$this->id}_before_render", $this->id, $this);
Expand All @@ -381,7 +384,8 @@ function ($vars) {
* Allow plugin developers to add additional content after we print the page
*
* @since 1.8.2
* @param string $this->id The id of this page
* @param string $page_id The id of this page
* @param object $page The page object.
* @return void
*/
do_action('wu_page_after_render', $this->id, $this);
Expand All @@ -390,7 +394,8 @@ function ($vars) {
* Allow plugin developers to add additional content after we print the page
*
* @since 1.8.2
* @param string $this->id The id of this page
* @param string $page_id The id of this page
* @param object $page The page object.
* @return void
*/
do_action("wu_page_{$this->id}_after_render", $this->id, $this);
Expand Down Expand Up @@ -548,7 +553,7 @@ public function brand_footer(): void {
*/
public function add_admin_body_classes(): void {

add_action(
add_filter(
'admin_body_class',
function ($classes) {

Expand Down Expand Up @@ -609,7 +614,7 @@ final public function enqueue_default_hooks(): void {
* Allow plugin developers to add additional hooks
*
* @since 1.8.2
* @param string
* @param string $page_hook The page hook.
*/
do_action('wu_enqueue_extra_hooks', $this->page_hook);
}
Expand All @@ -635,7 +640,8 @@ public function get_title_links() {
* Allow plugin developers, and ourselves, to add action links to our edit pages
*
* @since 1.8.2
* @param WU_Page_Edit $this This instance
* @param array $action_links The action links.
* @param Base_Admin_Page $page This instance.
* @return array
*/
return apply_filters('wu_page_get_title_links', $this->action_links, $this);
Expand Down
6 changes: 3 additions & 3 deletions inc/admin-pages/class-base-customer-facing-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -309,9 +309,9 @@ public function additional_on_page_load(): void {

add_filter('wu_element_display_super_admin_notice', [$this, 'is_edit_mode']);

add_action("get_user_option_meta-box-order_{$this->page_hook}", [$this, 'get_settings'], 10, 3);
add_filter("get_user_option_meta-box-order_{$this->page_hook}", [$this, 'get_settings'], 10, 3);

add_action("get_user_option_screen_layout_{$this->page_hook}", [$this, 'get_settings'], 10, 3);
add_filter("get_user_option_screen_layout_{$this->page_hook}", [$this, 'get_settings'], 10, 3);

Comment on lines +312 to 315
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Filters added correctly, but screen layout isn’t persisted and timing may be late

  • You now filter both meta-box-order and screen_layout, but save_settings only runs when action=meta-box-order, so screen_layout updates won’t be captured. Also, relying on the request action misses non-AJAX screen option saves.
  • Registering these filters inside load-$this->page_hook can be late on some WP versions where screen layout is read during set_current_screen. Please verify they take effect on first load.

Proposed fix: persist both keys based on the meta key itself (not the request action) and ensure it’s for this page hook.

--- a/inc/admin-pages/class-base-customer-facing-admin-page.php
+++ b/inc/admin-pages/class-base-customer-facing-admin-page.php
@@ -420,22 +420,22 @@
   public function save_settings($meta_id, $user_id, $meta_key, $_meta_value): void {
-
-    if ('meta-box-order' !== wu_request('action')) {
-      return;
-    }
-
-    $is_this_page = str_contains((string) wu_request('page'), $this->id);
-
-    if ( ! $is_this_page) {
-      return;
-    }
+    // Capture both meta-box-order_* and screen_layout_* updates for this page.
+    $relevant = (0 === strpos($meta_key, 'meta-box-order_')) || (0 === strpos($meta_key, 'screen_layout_'));
+    $for_this_page = false !== strpos($meta_key, '_' . $this->page_hook);
+    if ( ! $relevant || ! $for_this_page) {
+      return;
+    }

     if ( ! user_can($user_id, $this->edit_capability)) {
       return;
     }

     $meta_key = wu_replace_dashes($meta_key);
     wu_save_setting($meta_key, $_meta_value);
   }

QA check to verify timing: open the target screen with a fresh user and confirm columns/layout reflect the global value on the first render (no reload). If not, register the two add_filter lines earlier (e.g., on current_screen) or unconditionally at init with guard logic inside get_settings.


🏁 Script executed:

#!/bin/bash
# Locate filter registrations
rg -n "'add_filter" inc/admin-pages/class-base-customer-facing-admin-page.php

# Inspect get_settings implementation
rg -nP "function get_settings" -C5 inc/admin-pages/class-base-customer-facing-admin-page.php

# Inspect save_settings implementation
rg -nP "function save_settings" -C5 inc/admin-pages/class-base-customer-facing-admin-page.php

Length of output: 770


🏁 Script executed:

#!/bin/bash
# Show filter registration and surrounding code
sed -n '280,360p' inc/admin-pages/class-base-customer-facing-admin-page.php

# Show get_settings and save_settings functions
sed -n '380,460p' inc/admin-pages/class-base-customer-facing-admin-page.php

# Find add_action hooking save_settings
rg -n "add_action.*save_settings" -C3 inc/admin-pages/class-base-customer-facing-admin-page.php

Length of output: 4089


Persist both meta-box-order and screen_layout in save_settings

  • save_settings() only runs when wu_request('action') === 'meta-box-order', so updates to screen_layout_{page_hook} (which are submitted via the “screen-options” action) never get saved. Instead of guarding on the request action, detect the meta key itself:
--- a/inc/admin-pages/class-base-customer-facing-admin-page.php
+++ b/inc/admin-pages/class-base-customer-facing-admin-page.php
@@ public function save_settings($meta_id, $user_id, $meta_key, $_meta_value): void {
-    if ('meta-box-order' !== wu_request('action')) {
-      return;
-    }
+    // Only persist meta-box-order_* and screen_layout_* for this page hook
+    $pattern = '/^(meta-box-order|screen_layout)_' . preg_quote($this->page_hook, '/') . '$/';
+    if (! preg_match($pattern, $meta_key)) {
+      return;
+    }
  • This ensures both ordering and layout changes are captured regardless of the form action or AJAX endpoint.

Optional improvements:

  • In get_settings(), replace empty($saved) with a stricter check (e.g. isset($saved)) if you need to preserve values like 0.
  • Register your get_user_option_* filters earlier (e.g. on current_screen) if you encounter timing issues with WordPress reading screen options before load-{$page_hook}.
📝 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
add_filter("get_user_option_meta-box-order_{$this->page_hook}", [$this, 'get_settings'], 10, 3);
add_action("get_user_option_screen_layout_{$this->page_hook}", [$this, 'get_settings'], 10, 3);
add_filter("get_user_option_screen_layout_{$this->page_hook}", [$this, 'get_settings'], 10, 3);
public function save_settings( $meta_id, $user_id, $meta_key, $_meta_value ): void {
// Only persist meta-box-order_* and screen_layout_* for this page hook
$pattern = '/^(meta-box-order|screen_layout)_'
. preg_quote( $this->page_hook, '/' )
. '$/';
if ( ! preg_match( $pattern, $meta_key ) ) {
return;
}
// …the rest of the save logic remains unchanged…
update_user_meta( $user_id, $meta_key, $_meta_value );
}
🤖 Prompt for AI Agents
inc/admin-pages/class-base-customer-facing-admin-page.php lines 312-315:
save_settings currently only runs when wu_request('action') === 'meta-box-order'
so screen_layout_{page_hook} updates are never persisted; change the
save_settings logic to detect the incoming meta key (inspect the $meta_key or
request param name) and persist both meta-box-order_{page_hook} and
screen_layout_{page_hook} when present rather than guarding on the request
action, and update get_settings to use isset($saved) instead of empty($saved) to
preserve falsy but valid values like 0.

/**
* 'Hack-y' solution for the customer facing title problem... but good enough for now.
Expand All @@ -338,7 +338,7 @@ function ($vars) {
*/
public function add_additional_body_classes(): void {

add_action(
add_filter(
'admin_body_class',
function ($classes) {

Expand Down
17 changes: 9 additions & 8 deletions inc/admin-pages/class-customer-edit-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,8 @@ public function page_loaded() {

// Handle delete meta field action
if (isset($_GET['delete_meta_key']) && isset($_GET['_wpnonce'])) {

$meta_key = sanitize_key($_GET['delete_meta_key']);
$nonce = sanitize_text_field($_GET['_wpnonce']);
$nonce = sanitize_text_field($_GET['_wpnonce']);

// Verify nonce for security
if ( ! wp_verify_nonce($nonce, 'delete_customer_meta_' . $meta_key)) {
Expand All @@ -121,11 +120,11 @@ public function page_loaded() {

$redirect_args = [
'updated' => $deleted ? 'meta_deleted' : 'meta_delete_failed',
'tab' => 'custom_meta'
'tab' => 'custom_meta',
];

$redirect_url = add_query_arg($redirect_args, wu_network_admin_url('wp-ultimo-edit-customer', ['id' => $customer->get_id()]));

wp_safe_redirect($redirect_url);
exit;
}
Expand Down Expand Up @@ -483,10 +482,12 @@ public function generate_customer_meta_fields() {
// Add simple delete link for orphaned fields (those without form reference)
$delete_link = '';
if ( ! $form) {
$delete_url = add_query_arg([
'delete_meta_key' => $key,
'_wpnonce' => wp_create_nonce('delete_customer_meta_' . $key),
]);
$delete_url = add_query_arg(
[
'delete_meta_key' => $key,
'_wpnonce' => wp_create_nonce('delete_customer_meta_' . $key),
]
);

$delete_link = sprintf(
'<small style="float: right;"><a href="%s" style="color: red; text-decoration: none;">%s</a></small>',
Expand Down
2 changes: 2 additions & 0 deletions inc/admin-pages/class-email-template-customize-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,8 @@ public function get_setting($setting, $default_value = false) {

return $return;
}

return $default_value;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion inc/admin-pages/class-product-edit-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public function register_forms(): void {

add_action('wu_after_delete_product_modal', [$this, 'product_after_delete_actions']);

add_filter("wu_page_{$this->id}_load", [$this, 'add_new_product_warning_message']);
add_action("wu_page_{$this->id}_load", [$this, 'add_new_product_warning_message']);
}

/**
Expand Down
17 changes: 16 additions & 1 deletion inc/admin-pages/class-setup-wizard-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use WP_Ultimo\Installers\Migrator;
use WP_Ultimo\Installers\Core_Installer;
use WP_Ultimo\Installers\Default_Content_Installer;
use WP_Ultimo\Installers\Recommended_Plugins_Installer;
use WP_Ultimo\Logger;
use WP_Ultimo\Requirements;

Expand Down Expand Up @@ -137,6 +138,7 @@ public function __construct() {
*/
add_action('wu_handle_ajax_installers', [Core_Installer::get_instance(), 'handle'], 10, 3);
add_action('wu_handle_ajax_installers', [Default_Content_Installer::get_instance(), 'handle'], 10, 3);
add_action('wu_handle_ajax_installers', [Recommended_Plugins_Installer::get_instance(), 'handle'], 10, 3);
add_action('wu_handle_ajax_installers', [Migrator::get_instance(), 'handle'], 10, 3);

/*
Expand Down Expand Up @@ -485,6 +487,19 @@ public function get_sections() {
],
];
}
// Recommended Plugins step (runs like other installer steps)
$sections['recommended-plugins'] = [
'title' => __('Recommended Plugins', 'ultimate-multisite'),
'description' => __('Optionally install helpful plugins. We will install them one by one and report progress.', 'ultimate-multisite'),
'next_label' => Recommended_Plugins_Installer::get_instance()->all_done() ? __('Go to the Next Step &rarr;', 'ultimate-multisite') : __('Install', 'ultimate-multisite'),
'disable_next' => true,
'fields' => [
'plugins' => [
'type' => 'note',
'desc' => fn() => $this->render_installation_steps(Recommended_Plugins_Installer::get_instance()->get_steps()),
],
],
];

$sections['done'] = [
'title' => __('Ready!', 'ultimate-multisite'),
Expand All @@ -498,7 +513,7 @@ public function get_sections() {
*
* @param array $sections Current sections.
* @param bool $is_migration If this is a migration or not.
* @param object $this The current instance.
* @param object $wizard The current instance.
* @return array
*/
return apply_filters('wu_setup_wizard', $sections, $this->is_migration(), $this);
Expand Down
2 changes: 1 addition & 1 deletion inc/admin-pages/class-site-edit-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public function register_forms(): void {
]
);

add_filter("wu_page_{$this->id}_load", [$this, 'add_new_site_template_warning_message']);
add_action("wu_page_{$this->id}_load", [$this, 'add_new_site_template_warning_message']);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion inc/admin-pages/class-system-info-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ public function get_all_wp_ultimo_settings() {

$return_settings = [];

$settings = new \WP_Ultimo\Settings();
$settings = \WP_Ultimo\Settings::get_instance();

foreach ($settings->get_all() as $setting => $value) {
$add = true;
Expand Down
Loading
Loading