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
115 changes: 115 additions & 0 deletions assets/css/invoice.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
.invoice-box {
width: 100%;
margin: auto;
font-size: 16px;
line-height: 24px;
color: #555;
}

.invoice-box table {
width: 100%;
line-height: inherit;
text-align: left;
}

.invoice-box table td {
padding: 5px;
vertical-align: top;
}

.invoice-box table tr td:nth-child(2) {
text-align: right;
}

.invoice-box table tr.top table td {
padding-bottom: 20px;
}

.invoice-box table tr.top table td.title {
font-size: 45px;
line-height: 45px;
color: #333;
}

.invoice-box table tr.information table td {
padding-bottom: 40px;
}

.invoice-box table tr.heading td {
background: #eee;
border-bottom: 1px solid #ddd;
font-weight: 500;
}

.invoice-box table {
border-collapse: 1px;
}
Comment on lines +44 to +46
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

Invalid value for border-collapse; browsers will ignore this.

border-collapse: 1px; is not valid CSS. Use collapse (and add border-spacing: 0; for completeness). Otherwise you’ll get separated borders and inconsistent rendering across HTML-to-PDF engines.

Apply this diff:

 .invoice-box table {
-  border-collapse: 1px;
+  border-collapse: collapse;
+  border-spacing: 0;
 }
📝 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
.invoice-box table {
border-collapse: 1px;
}
.invoice-box table {
border-collapse: collapse;
border-spacing: 0;
}
🤖 Prompt for AI Agents
In assets/css/invoice.css around lines 44 to 46, the rule uses an invalid value
"border-collapse: 1px;" which browsers ignore; change it to "border-collapse:
collapse" and add "border-spacing: 0" to remove gaps so table borders render
consistently (especially for HTML-to-PDF engines). Ensure you update that
selector to use the correct property values and keep formatting consistent with
the file.


.invoice-box table tr.heading th {
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
}

.invoice-box table tr.item td {
vertical-align: middle;
}

.invoice-box table tr.heading th {
background: #eee;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
padding: 10px;
text-align: right;
font-weight: bold;
text-transform: uppercase;
font-size: 80%;
}

.invoice-box table tr.details td {
padding: 10px;
}

.invoice-box table tr.item td{
border-bottom: 1px solid #eee;
padding: 10px;
}

.invoice-box table tr.item.last td {
border-bottom: none;
}

.invoice-box table tr.total td {
border-top: 2px solid #eee;
font-weight: bold;
padding-bottom: 60px;
padding-top: 10px;
text-align: right;
}

@media only screen and (max-width: 600px) {
.invoice-box table tr.top table td {
width: 100%;
display: block;
text-align: center;
}

.invoice-box table tr.information table td {
width: 100%;
display: block;
text-align: center;
}
}

/** RTL **/
.rtl {
direction: rtl;

}

.rtl table {
text-align: right;
}

.rtl table tr td:nth-child(2) {
text-align: left;
}
1 change: 1 addition & 0 deletions assets/css/invoice.min.css

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

71 changes: 0 additions & 71 deletions assets/js/support.js

This file was deleted.

1 change: 0 additions & 1 deletion assets/js/support.min.js

This file was deleted.

4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@
"vendor/delight-im/cookie/.travis-ci-apache",
"vendor/doctrine",
".distignore",
"encrypt-sectrets.php"
"encrypt-sectrets.php",
"scripts",
"mu-plugins"
]
Comment on lines +137 to 140
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 in archive.exclude entry: “encrypt-sectrets.php”.

If the intent was to exclude “encrypt-secrets.php”, the current misspelling will not match and the file will be shipped.

Patch:

-            "encrypt-sectrets.php",
+            "encrypt-secrets.php",
📝 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
"encrypt-sectrets.php",
"scripts",
"mu-plugins"
]
"encrypt-secrets.php",
"scripts",
"mu-plugins"
]
🤖 Prompt for AI Agents
In composer.json around lines 137-140, the archive.exclude entry contains a typo
"encrypt-sectrets.php" which won't match the intended file; update that entry to
"encrypt-secrets.php" so the correct file is excluded from the archive, then
validate the JSON and run any packaging/validation steps (e.g., composer
validate) to ensure the change is applied.

},
"extra": {
Expand Down
43 changes: 20 additions & 23 deletions inc/admin-pages/class-broadcast-edit-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,17 +205,6 @@ public function output_default_widget_customer_targets(): void {

$customer_link = wu_network_admin_url('wp-ultimo-edit-customer', $url_atts);

$avatar = get_avatar(
$customer->get_user_id(),
32,
'identicon',
'',
[
'force_display' => true,
'class' => 'wu-rounded-full wu-border-solid wu-border-1 wu-border-white hover:wu-border-gray-400',
]
);

$display_name = $customer->get_display_name();

$id = $customer->get_id();
Expand All @@ -232,7 +221,16 @@ public function output_default_widget_customer_targets(): void {
</a>',
esc_attr($customer_link),
esc_html($display_name),
$avatar, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
get_avatar(
$customer->get_user_id(),
32,
'identicon',
'',
[
'force_display' => true,
'class' => 'wu-rounded-full wu-border-solid wu-border-1 wu-border-white hover:wu-border-gray-400',
]
),
esc_html($id),
esc_html($email)
);
Expand All @@ -245,16 +243,6 @@ public function output_default_widget_customer_targets(): void {

$email = $customer->get_email_address();

$avatar = get_avatar(
$email,
32,
'identicon',
'',
[
'class' => 'wu-rounded-full wu-border-solid wu-border-1 wu-border-white hover:wu-border-gray-400',
]
);

$url_atts = [
'id' => $customer->get_id(),
];
Expand All @@ -265,7 +253,15 @@ public function output_default_widget_customer_targets(): void {
"<div class='wu-flex wu--mr-4'><a role='tooltip' aria-label='%s' href='%s'>%s</a></div>",
esc_attr($tooltip_name),
esc_attr($customer_link),
$avatar // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
get_avatar(
$email,
32,
'identicon',
'',
[
'class' => 'wu-rounded-full wu-border-solid wu-border-1 wu-border-white hover:wu-border-gray-400',
]
)
);
}

Expand Down Expand Up @@ -459,6 +455,7 @@ public function query_filter($args) {
*/
public function get_object() {

// Data is only being fetch, nothing is being modified, no need for nonce check.
if (isset($_GET['id'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$query = new \WP_Ultimo\Database\Broadcasts\Broadcast_Query();

Expand Down
26 changes: 11 additions & 15 deletions inc/admin-pages/class-checkout-form-edit-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function init(): void {

parent::init();

add_action('init', [$this, 'generate_checkout_form_preview'], 9);
$this->generate_checkout_form_preview();

add_action('wp_ajax_wu_save_editor_session', [$this, 'save_editor_session']);

Expand Down Expand Up @@ -171,8 +171,6 @@ public function content_checkout_form_by_settings(): void {
return;
}

$content = '';

$key = wp_get_session_token();

$session = \WP_Session_Tokens::get_instance(get_current_user_id());
Expand All @@ -193,12 +191,20 @@ public function content_checkout_form_by_settings(): void {
$current_user = wp_set_current_user(0);
}

wp_enqueue_scripts();

wp_print_head_scripts();

printf('<body %s>', 'class="' . esc_attr(implode(' ', get_body_class('wu-styling'))) . '"');

echo '<div class="wu-p-6">';

$count = count($settings);

foreach ($settings as $index => $step) {
$final_fields = wu_create_checkout_fields($step['fields']);

$content .= wu_get_template_contents(
wu_get_template(
'checkout/form',
[
'step' => $step,
Expand All @@ -212,20 +218,10 @@ public function content_checkout_form_by_settings(): void {
);

if ($index < $count - 1) {
$content .= sprintf('<hr class="sm:wu-bg-transparent wu-hr-text wu-font-semibold wu-my-4 wu-mt-6 wu-text-gray-600 wu-text-sm" data-content="%s">', esc_attr__('Step Separator', 'multisite-ultimate'));
printf('<hr class="sm:wu-bg-transparent wu-hr-text wu-font-semibold wu-my-4 wu-mt-6 wu-text-gray-600 wu-text-sm" data-content="%s">', esc_attr__('Step Separator', 'multisite-ultimate'));
}
}

wp_enqueue_scripts();

wp_print_head_scripts();

printf('<body %s>', 'class="' . esc_attr(implode(' ', get_body_class('wu-styling'))) . '"');

echo '<div class="wu-p-6">';

echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

wp_print_footer_scripts();

echo '</div></body>';
Expand Down
4 changes: 2 additions & 2 deletions inc/admin-pages/class-customer-edit-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -997,9 +997,9 @@ public function render_country() {

if ($country_code) {
$html = sprintf(
'<span>%s</span><span class="wu-flag-icon wu-w-5 wu-ml-1" %s>%s</span>',
'<span>%s</span><span class="wu-flag-icon wu-w-5 wu-ml-1" role="tooltip" aria-label="%s">%s</span>',
$country_name,
wu_tooltip_text($country_name),
esc_attr($country_name),
wu_get_flag_emoji((string) $country_code)
Comment on lines +1000 to 1003
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 ARIA misuse and escape output in render_country().

role="tooltip" on a static span is incorrect and causes duplicate announcements; the flag is decorative because the country name is already printed. Also escape outputs per WP standards.

-            '<span>%s</span><span class="wu-flag-icon wu-w-5 wu-ml-1" role="tooltip" aria-label="%s">%s</span>',
-            $country_name,
-            esc_attr($country_name),
-            wu_get_flag_emoji((string) $country_code)
+            '<span>%s</span><span class="wu-flag-icon wu-w-5 wu-ml-1" aria-hidden="true">%s</span>',
+            esc_html($country_name),
+            esc_html(wu_get_flag_emoji((string) $country_code))

Optional (if you truly need a tooltip later): use a trigger with aria-describedby pointing to a hidden tooltip element, not role="tooltip" on the icon itself.

To check for similar cases:


🏁 Script executed:

#!/bin/bash
rg -nP -C2 'role\s*=\s*"tooltip"' --type=php

Length of output: 8035


Fix ARIA misuse and escape outputs across the codebase

role="tooltip" is applied to static/decorative elements (causes duplicate screen-reader announcements). Replace decorative icons with aria-hidden="true", escape outputs with esc_html/esc_attr, and implement real tooltips using a trigger + aria-describedby when required. Prefer fixing the helper(s) in inc/functions/markup-helpers.php to avoid repetition.

Occurrences to update (from your search):

  • views/ui/jumper-trigger.php:11
  • views/ui/container-toggle.php:11
  • views/events/widget-initiator.php:38,64
  • views/dashboard-statistics/widget-countries.php:68
  • views/dashboard-widgets/activity-stream.php:49
  • inc/admin-pages/class-customer-edit-admin-page.php:1000
  • inc/list-tables/class-customer-list-table.php:147
  • inc/list-tables/class-discount-code-list-table.php:173
  • inc/list-tables/class-membership-list-table.php:218
  • inc/list-tables/class-base-list-table.php:842
  • inc/integrations/host-providers/class-cloudflare-host-provider.php:119-122
  • inc/functions/markup-helpers.php:126,146

Apply the local fix (example) for inc/admin-pages/class-customer-edit-admin-page.php:

-            '<span>%s</span><span class="wu-flag-icon wu-w-5 wu-ml-1" role="tooltip" aria-label="%s">%s</span>',
-            $country_name,
-            esc_attr($country_name),
-            wu_get_flag_emoji((string) $country_code)
+            '<span>%s</span><span class="wu-flag-icon wu-w-5 wu-ml-1" aria-hidden="true">%s</span>',
+            esc_html($country_name),
+            esc_html(wu_get_flag_emoji((string) $country_code))

Confirm before committing with:
rg -nP -C2 'role\s*=\s*"tooltip"' --type=php

📝 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
'<span>%s</span><span class="wu-flag-icon wu-w-5 wu-ml-1" role="tooltip" aria-label="%s">%s</span>',
$country_name,
wu_tooltip_text($country_name),
esc_attr($country_name),
wu_get_flag_emoji((string) $country_code)
'<span>%s</span><span class="wu-flag-icon wu-w-5 wu-ml-1" aria-hidden="true">%s</span>',
esc_html($country_name),
esc_html(wu_get_flag_emoji((string) $country_code))
🤖 Prompt for AI Agents
In inc/admin-pages/class-customer-edit-admin-page.php around lines 1000 to 1003,
replace the decorative flag span that currently uses role="tooltip" with a span
that is aria-hidden="true" and ensure the displayed country name and attributes
are properly escaped (use esc_html for visible text and esc_attr for
attributes); update or add a helper in inc/functions/markup-helpers.php to
render flag icons with aria-hidden and proper escaping to avoid repeating fixes
across files, and if a real tooltip is required implement a separate trigger
element plus aria-describedby pointing to a visually-hidden tooltip element.
After making changes run: rg -nP -C2 'role\s*=\s*"tooltip"' --type=php to
confirm no remaining incorrect usages before committing.

);
} else {
Expand Down
12 changes: 4 additions & 8 deletions inc/admin-pages/class-dashboard-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -608,20 +608,16 @@ public function render_csv_button($args): void {

$data_strings = wp_json_encode($args['data']);

$html = '<div class="wu-bg-gray-100 wu-p-2 wu-text-right wu-border-0 wu-border-b wu-border-solid wu-border-gray-400">
printf(
'<div class="wu-bg-gray-100 wu-p-2 wu-text-right wu-border-0 wu-border-b wu-border-solid wu-border-gray-400">
<a href="#" attr-slug-csv="%2$s" class="wu-export-button wu-no-underline wu-text-gray-800 wu-text-xs">
<span class="dashicons-wu-download wu-mr-1"></span> %1$s
</a>
<input type="hidden" id="csv_headers_%2$s" value="%3$s" />
<input type="hidden" id="csv_data_%2$s" value="%4$s" />
<input type="hidden" id="csv_action_%2$s" value="%5$s" />
</div>';

$html = apply_filters('wu_export_html_render', $html, $html);

printf(
$html, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
apply_filters('wu_export_data_table_label', esc_html__('CSV', 'multisite-ultimate')), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
</div>',
esc_html__('CSV', 'multisite-ultimate'),
esc_attr($slug),
Comment on lines +611 to 621
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

Use data- attributes and keep label filter for backward compatibility.*

Custom attributes should be data-* per HTML5. Also, hard-coding the label drops the prior customization point.

Apply this diff:

-		printf(
-			'<div class="wu-bg-gray-100 wu-p-2 wu-text-right wu-border-0 wu-border-b wu-border-solid wu-border-gray-400">
-			<a href="#" attr-slug-csv="%2$s" class="wu-export-button wu-no-underline wu-text-gray-800 wu-text-xs">
-				<span class="dashicons-wu-download wu-mr-1"></span> %1$s
+		printf(
+			'<div class="wu-bg-gray-100 wu-p-2 wu-text-right wu-border-0 wu-border-b wu-border-solid wu-border-gray-400">
+			<a href="#" data-slug-csv="%2$s" class="wu-export-button wu-no-underline wu-text-gray-800 wu-text-xs">
+				<span class="dashicons-wu-download wu-mr-1"></span> %1$s
 			</a>
 			<input type="hidden" id="csv_headers_%2$s" value="%3$s" />
 			<input type="hidden" id="csv_data_%2$s" value="%4$s" />
 			<input type="hidden" id="csv_action_%2$s" value="%5$s" />
 		</div>',
-			esc_html__('CSV', 'multisite-ultimate'),
+			esc_html(apply_filters('wu_export_data_table_label', __('CSV', 'multisite-ultimate'))),
 			esc_attr($slug),
 			esc_attr($header_strings),
 			esc_attr($data_strings),
 			esc_attr($args['action'])
 		);

If JS reads the old attribute, update it:


🏁 Script executed:

#!/bin/bash
# Update JS to read data-slug-csv instead of attr-slug-csv
rg -n 'attr-slug-csv'

Length of output: 4278


Use HTML5 data-attributes and enable CSV label filtering

  • In inc/admin-pages/class-dashboard-admin-page.php (≈ line 613), change attr-slug-csv="%2$s" to data-slug-csv="%2$s" and replace the hard-coded label %1$s with:
    esc_html( apply_filters( 'wu_export_data_table_label', __( 'CSV', 'multisite-ultimate' ) ) )
  • In assets/js/dashboard-statistics.js (line 188), update getAttribute('attr-slug-csv') to getAttribute('data-slug-csv') and recompile assets (to regenerate dashboard-statistics.min.js).
🤖 Prompt for AI Agents
In inc/admin-pages/class-dashboard-admin-page.php around lines 611 to 621,
change the non-standard attribute attr-slug-csv to the HTML5 data attribute
data-slug-csv and replace the hard-coded CSV label with a filtered label by
using esc_html( apply_filters( 'wu_export_data_table_label', __( 'CSV',
'multisite-ultimate' ) ) ); also update assets/js/dashboard-statistics.js
(around line 188) to read the attribute via getAttribute('data-slug-csv')
instead of getAttribute('attr-slug-csv') and then recompile/rebuild assets to
regenerate dashboard-statistics.min.js so the frontend uses the new data
attribute and filterable label.

esc_attr($header_strings),
esc_attr($data_strings),
Expand Down
4 changes: 2 additions & 2 deletions inc/admin-pages/class-edit-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,8 @@ protected function add_list_table_widget($id, $atts = []) {
$atts,
[
'widget_id' => $id,
'before' => '',
'after' => '',
'before' => fn() => null,
'after' => fn() => null,
'title' => __('List Table', 'multisite-ultimate'),
Comment on lines +404 to 406
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

Potential fatal: defaulting 'before'/'after' to Closures may break templates expecting strings.

If widget-list-table template echoes these keys, echoing a Closure triggers “Object of class Closure could not be converted to string.” Either revert defaults to strings, or ensure templates treat them as callable-or-string.

Minimal safe fix (consistent with other methods in this class):

-                'before'       => fn() => null,
-                'after'        => fn() => null,
+                'before'       => '',
+                'after'        => '',

Alternatively, normalize just before rendering:

$before = $atts['before'];
$after  = $atts['after'];
$render = static fn($seg) => is_callable($seg) ? $seg() : print $seg;
...
// in the meta box callback, use $render($before); ... $render($after);
🤖 Prompt for AI Agents
In inc/admin-pages/class-edit-admin-page.php around lines 404 to 406, the
default values for 'before' and 'after' are set to Closures which can cause a
fatal "Object of class Closure could not be converted to string" if templates
echo these keys; change the defaults to empty strings (or the same string
defaults used elsewhere in this class) so templates that expect strings won't
break, or alternatively add normalization in the render path that checks
is_callable($seg) and calls it, otherwise echoes/prints the string before/after
rendering.

'position' => 'advanced',
'screen' => get_current_screen(),
Expand Down
Loading
Loading