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
8 changes: 4 additions & 4 deletions inc/class-newsletter.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ public function add_settings(): void {
'general',
self::SETTING_FIELD_SLUG,
[
'title' => __('Signup for Ultimate Multisite Newsletter', 'ultimate-multisite'),
'desc' => __('Be informed of new releases and all things related to running a WaaS Network.', 'ultimate-multisite'),
'type' => 'toggle',
'value' => '1',
'title' => __('Signup for Ultimate Multisite Newsletter', 'ultimate-multisite'),
'desc' => __('Be informed of new releases and all things related to running a WaaS Network.', 'ultimate-multisite'),
'type' => 'toggle',
'default' => '1',
Comment on lines +48 to +51

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 12 "save_settings\(|newsletter_optin|wu_request\('tab'" --glob '*.php' .

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 50394


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant newsletter registration, setup-wizard submit logic, and settings save behavior.
sed -n '1,70p' inc/class-newsletter.php
printf '\n--- setup-wizard save_settings ---\n'
sed -n '815,833p' inc/admin-pages/class-setup-wizard-admin-page.php
printf '\n--- setup-wizard fields methods around general/general settings ---\n'
rg -n "class Setup_Wizard|get_general_settings|add_action|action='.*newsletter|checkbox|toggle|newsletter_optin|name='\$field|fields_to_get|fields_to_save" inc/admin-pages/class-setup-wizard-admin-page.php inc/functions/settings.php inc/class-settings.php

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 7648


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- setup-wizard general fields ---'
sed -n '580,609p' inc/admin-pages/class-setup-wizard-admin-page.php

printf '\n%s\n' '--- settings field form rendering around checkboxes/toggles ---'
sed -n '130,230p' inc/class-settings.php
sed -n '200,250p' inc/class-settings.php

printf '%s\n' '--- deterministic save_settings tab-zero logic check from source text ---'
python3 - <<'PY'
from pathlib import Path
import re

path = Path('inc/class-settings.php')
src = path.read_text()
m = re.search(
    r'public\s+function\s+save_settings\s*\([^)]*\).*?\n\t{2}\{\n(.*?)^'.format(),
    src,
    re.S | re.M
)
if not m:
    raise SystemExit('save_settings not found')
body = m.group(1)
print('contains omitted toggle general false:')
print("wu_request('tab' === \"general\")" in body)
print('! isset($settings_to_save[ $field_slug ]) && new_value = false' in body)

# Read-only source-based invariant: if the exact general-tab guard and omitted toggle guard exist, omitted general toggles are false.
guard = "if (wu_request('tab', 'general') === $section_slug && 'toggle' === $field->type && ! isset($settings_to_save[ $field_slug ]))"
print('exact general omit guard:')
print(guard in body)
if guard in body:
    assignment = body[body.find(guard):].partition('\n')[0]
    print('first line in guard block:')
    print(assignment)
PY

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 5931


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- field registration helper ---'
rg -n -C 10 "function wu_register_settings_field|if (.*tab|fields\]\s*\[" inc/functions/settings.php

printf '\n%s\n' '--- save_settings omitted toggle block ---'
sed -n '352,390p' inc/class-settings.php

printf '\n%s\n' '--- newsletter post handler fields/form references ---'
rg -n -C 5 "newsletter_optin|wu-settings-field|type.*checkbox|type.*toggle|input name|name.*news" --glob '*.php' --glob '*.js' .

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 328


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- field registration helper ---'
rg -n -C 8 'function wu_register_settings_field|fields\]\s*\[' inc/functions/settings.php

printf '%s\n' '--- save_settings omitted toggle block ---'
sed -n '352,390p' inc/class-settings.php

printf '%s\n' '--- newsletter post handler fields/form references ---'
rg -n -C 5 'newsletter_optin|wu-settings-field|checkbox|toggle|submit|posts-to-edit|name.*news' --glob '*.php' --glob '*.js' .

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 50394


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- wu_register_settings_field definition ---'
rg -n "function wu_register_settings_field|if \(\$tab" inc/functions/settings.php

printf '%s\n' '--- save_settings omitted toggle block ---'
sed -n '352,390p' inc/class-settings.php

printf '%s\n' '--- newsletter opt-in handling ---'
sed -n '70,140p' inc/class-newsletter.php

printf '%s\n' '--- deterministic data-flow evidence from source slices ---'
python3 - <<'PY'
from pathlib import Path

setup = Path('inc/admin-pages/class-setup-wizard-admin-page.php').read_text()
settings = Path('inc/class-settings.php').read_text()
news = Path('inc/class-newsletter.php').read_text()

print('setup uses general wizard step:', "'your-company' === $step" in setup)
print('setup includes all general fields:', "WP_Ultimo\\Settings::get_instance()->get_section('general')['fields']" in setup)
print('setup submits intersected POST keys:', "array_intersect_key($_POST, $fields_to_save)" in setup)
print('settings omits general toggles to false:', "wu_request('tab', 'general') === \$section_slug && 'toggle' === \$field->type && ! isset(\$settings_to_save[ \$field_slug ])" in settings)
print('newsletter subscribes by post presence pattern:', 'isset(\$settings_to_save[' in news and 'newsletter_optin' in news)
PY

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 3553


Persist the newsletter optin default on the wizard save path.

The wizard renders all general section fields but submits only $_POST keys, so an unchecked newsletter_optin arrives as 0 for Settings::save_settings(). Since that save path also treats omitted general toggles as 0, a fresh wizard can overwrite the registered default unless the checkbox submits its value or the save path preserves defaults for omitted toggles.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@inc/class-newsletter.php` around lines 48 - 51, Update the wizard save flow
used by Settings::save_settings() so newsletter_optin retains its registered
default when the checkbox is omitted, rather than being converted to 0. Ensure
the general-section toggle handling distinguishes an omitted field from an
explicitly submitted unchecked value, while preserving explicit opt-out
behavior.

],
45
);
Expand Down
1 change: 1 addition & 0 deletions inc/class-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -2149,6 +2149,7 @@ public static function get_setting_defaults(): array {
'thousand_separator' => ',',
'precision' => '2',
'enable_beta_updates' => 0,
'newsletter_optin' => '1',

// Login & Registration
'enable_registration' => 1,
Expand Down
16 changes: 16 additions & 0 deletions tests/WP_Ultimo/Settings_Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,22 @@ public function test_get_all_with_defaults_includes_default_role_when_db_is_empt
$this->assertEquals('administrator', $all['default_role']);
}

public function test_get_all_with_defaults_includes_newsletter_optin_when_db_is_empty() {
// Simulate a fresh install with no saved settings.
wu_save_option(Settings::KEY, []);

$ref = new \ReflectionProperty(Settings::class, 'settings');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$ref->setValue($this->settings, null);

$all = $this->settings->get_all_with_defaults();

$this->assertArrayHasKey('newsletter_optin', $all);
$this->assertSame('1', $all['newsletter_optin']);
}

public function test_get_all_with_defaults_preserves_saved_values() {
// When a value IS saved in the DB it must be preserved.
$this->settings->save_setting('default_role', 'editor');
Expand Down
Loading