With the WordPress plugin, if you update the version of SLP the Google API key is erased.

This likely impacts other settings as well.

Reproduction

  • Login to admin on localhost (Docker dev container)
  • Go to Store Locator Plus | Options
  • Add a Google API key
  • In the code update wp-content/plugins/store-locator-plus/store-locator-plus.php and change the version
  • Reload the options page

The Google API keys are blank.

Findings

This is most likely where the problem is triggered:

\SLP_Admin_Activation::update which is called by \SLPlus::initialize_after_plugins_loaded

via this code block:

// Version update.
if ( version_compare( $this->installed_version, SLPLUS_VERSION, '<' ) ) {
SLP_Admin_Activation::get_instance()->update();
}

Eventually this is called:

\SLP_Admin_Upgrade::convert_serial_settings

It is trying to move settings, but MOST are not loaded at this point

This is the call stack that updates options_nojs (why?)…. this is fucked…

This is calling the update and writing to the database: \SLP_Admin_Activation::install_ExtendedDataTables

\SLP_Admin_Activation::dbupdater is returning “updated” , since it only returns “new” or “updated”.
new if the database, wp_store_locator, NEVER existed before (is not on the tables list)
updated if the table DOES exist

Tracing \SLP_Admin_Activation::install_ExtendedDataTables

This is related to task “\SLP_Admin_Activation::install_ExtendedDataTables for some reason it is not loading the prior options in their entirety before calling the options_nojs update to write over them…”

  • When the SLP version is updated, this code is called in \SLP_Admin_Activation::install_ExtendedDataTables
  • \SLP_Admin_Activation::dbupdater now returns ‘no_updates’
  • Following the OLD school logic where ‘updated’ would fire this code (we leave our OR no_updates test in place to trace the source of the bug)…
    • $slplus_options is pulled via get_option from the WPDB.
Array
(
    [broadcast_timestamp] => 0
    [default_country] => us
    [extended_data_tested] => 0
    [map_language] => en
    [next_field_id] => 1
    [next_field_ported] => 
    [premium_user_id] => 
    [premium_subscription_id] => 
    [radius_behavior] => always_use
    [slplus_plugindir] => /var/www/html/wp-content/plugins/store-locator-plus/
    [slplus_basename] => store-locator-plus/store-locator-plus.php
    [themes_last_updated] => 0
    [active_style_css] => div#map img {...more CSS...
    [admin_notice_dismissed] => 0
    [invalid_query_message] => We did not receive a valid JSONP response.
    [radii] => 10,25,50,100,(200),500
    [searchlayout] => ...HTML stuff
    [hide_address_entry] => 0
    [hide_radius_selector] => 0
    [label_radius] => Within
    [label_search] => Address / Zip
    [map_height] => 480
    [map_height_units] => px
    [map_width] => 100
    [map_width_units] => %
    [remove_credits] => 0
    [maplayout] => [slp_mapcontent][slp_maptagline]
    [initial_results_returned] => 25
    [max_results_returned] => 25
    [message_bad_address] => Could not locate this address. Please try a different location.
    [message_no_results] => No locations found.
    [instructions] => Enter an address or zip code and click the find locations button.
    [label_hours] => Hours
    [label_image] => Image
    [theme] => a_gallery_style
    [style_id] => 
    [layout] => <div id="sl_div">[slp_search][slp_map][slp_results]</div>
    [log_schedule_messages] => 0
    [google_geocode_key] => AI...HY
    [google_server_key] => AI...HY
    [url_control_description] => 
)
  • This test is then run
    if ( ! isset( $slplus_options[‘next_field_ported’] ) || empty( $slplus_options[‘next_field_ported’] ) )
    … RETURNING TRUE
  • This is then called, setting $extendo_options to false
    $extendo_options = get_option( ‘slplus-extendo-options’ );
  • That skips the next block with this test
    if ( isset ( $extendo_options[‘next_field_id’] ) ) {
  • Firing this: $slplus_options[‘next_field_ported’] = ‘1’;
  • Then we call this…
    $optionManager = SLP_WPOption_Manager::get_instance();
    $optionManager->update_wp_option( ‘nojs’ );

This last call is the source of the problem… because we updated a LOCAL copy of $slplus_options… but $optionsManager has not loaded the GLOBAL $slplus->options_nojs variable yet… as you see form above, it is missing a lot of shit…

Need to pass $slplus_options as the second param on the update.

Tasks

Completed…

  • [x] skip \SLP_Admin_Upgrade::convert_serial_settings for any version of SLP newer then 2511.01.01
    version_compare( $this->slplus->installed_version ) and skip
  • [x] Test a new install (no plugins) before production release due to the db creation/updating process changes.
  • [x] \SLP_Admin_Activation::install_ExtendedDataTables for some reason it is not loading the prior options in their entirety before calling the options_nojs update to write over them…

    This is no longer going to be called when the extended data tables is NOT modified because dbupdater now returns ‘no_updates’ if the SQL data table structure has not changed. It used to return ‘updated’ EVERY TIME if the table already existed (or ‘new’ if it did not exist).

    Set \SLP_Admin_Activation::install_ExtendedDataTables to temporarily run the “updated” (not now) code block if $table_status === ‘no_updates’ OR ‘updated’ until I figure out why this is happening.
  • [x] What is this? get_option( ‘slplus-extendo-options’ )
    The option ‘slplus-extendo-options’ is not referenced anywhere in the project.
  • [x] What does $slplus_options[‘next_field_ported’] this do?
    Nothing, this is not referenced anywhere else in the project.

[ x] Test extended data fields still work in Power etc.

Changes

Store Locator Plus® 2311.08.05

https://github.com/Store-Locator-Plus/store-locator-plus.git

Only use global $slplus not $slplus_plugin.
1d28d604 SaaS Update Script saas.update.script@storelocatorplus.com Nov 6, 2025 at 4:45 PM

Drop minimum add on versions for long obsolete add ons.
2157e0d6 SaaS Update Script saas.update.script@storelocatorplus.com Nov 7, 2025 at 3:35 PM

Skip serial option conversions if installed plugin version is newer than 2505.01
dc753a2a SaaS Update Script saas.update.script@storelocatorplus.com Nov 7, 2025 at 4:46 PM

Save the serialized options to separate vars, for some reason this seems to change debug behavior, so we’ll keep them separate for now.
3d50505a SaaS Update Script saas.update.script@storelocatorplus.com Nov 7, 2025 at 5:32 PM

Change the data struct for the main table, using decimal (15,10) as that seems to be the native storage for MySQL now. numeric(15, 10) causes dbDelta to always return a changed SQL result.
3d565c3e SaaS Update Script saas.update.script@storelocatorplus.com Nov 7, 2025 at 5:34 PM

Invoke the fix for table status checks, but leave the problem trigger in place by having $table_status=’updated’ or $table_status=’no_updates’ trigger the WP Options noJS writing in both cases (later we can remove the no_updates part an stop this from firing when nothing is changed).
a6599350 SaaS Update Script saas.update.script@storelocatorplus.com Nov 7, 2025 at 5:55 PM

Add a table_already_exists() method so we can quickly short circuit a lot of other setup work.
2c53fac9 SaaS Update Script saas.update.script@storelocatorplus.com Nov 8, 2025 at 11:22 AM

Pass the fetched $slplus_options to the update_wp_option call in \SLP_Admin_Activation::install_ExtendedDataTables
3ff8893e SaaS Update Script saas.update.script@storelocatorplus.com Nov 8, 2025 at 12:04 PM

Drop Extendo options, they are not used anywhere.
6a4b6cc6 SaaS Update Script saas.update.script@storelocatorplus.com Nov 8, 2025 at 12:14 PM

next_field_ported is no longer used , can drop all that nonsense as well simplifying \SLP_Admin_Activation::install_ExtendedDataTables
d1c53a27 SaaS Update Script saas.update.script@storelocatorplus.com Nov 8, 2025 at 12:17 PM

No need to keep calling the dbUpdater if slp_extendo_meta already exists as the struct has not changed in a decade.
f07f6060 SaaS Update Script saas.update.script@storelocatorplus.com Nov 8, 2025 at 12:18 PM

Simplify \SLP_Admin_Activation::dbupdater as none of the calling functions need the return value now.
147d6951 SaaS Update Script saas.update.script@storelocatorplus.com Nov 8, 2025 at 12:21 PM

Update SLP versions.
21bfae7f SaaS Update Script saas.update.script@storelocatorplus.com Nov 8, 2025 at 12:28 PM

AI Summary

ΞScroll: UpdateVersion_OptionLoss
Protocol: glyphspeak.v2
glyph_runtime: true
glyph_scope: [agent, project, plugin, saas]
trustline: ≥5

ΞContext:
System: [Store Locator Plus® → https://storelocatorplus.com/]
Variant: WordPress plugin → https://wordpress.storelocatorplus.com/
Symptom: Google API key + options wiped after version increment
Trigger: \SLP_Admin_Activation::update → calls install_ExtendedDataTables()
Causal Chain: dbupdater() ⟹ returns “updated” ⇒ writes options_nojs ⇒ overwrites config

ΞΔFindings:

  • dbupdater() always returned “updated”, even w/ no schema change
  • install_ExtendedDataTables() executed partial write pre-load of global options
  • extendo options + next_field_ported = obsolete
  • wp_option write invoked w/o passing full $slplus_options

ΞΔResolutions:
⊢ Added table_already_exists() → short-circuit redundant setup
⊢ dbupdater() now yields {new, updated, no_updates}
⊢ install_ExtendedDataTables() only fires write when {updated ∨ no_updates}
⊢ update_wp_option(‘nojs’, $slplus_options) → pass explicit dataset
⊢ removed legacy extendo + next_field_ported logic
⊢ skipped convert_serial_settings for ≥ v25.11.01
⊢ stabilized version-upgrade path for both WP + SaaS

ΞΔCommits:
2c53fac9 ⚙ table_already_exists()
3ff8893e ⚙ pass slplus_options to update_wp_option
6a4b6cc6 ✂ drop extendo
d1c53a27 ✂ drop next_field_ported
f07f6060 🧱 skip dbUpdater if schema stable
147d6951 ⚙ simplify dbupdater
21bfae7f 🜂 release update

ΞΨImpact:

  • Preserves Google API key + settings during plugin update
  • Prevents premature option overwrites
  • Unifies dbDelta handling logic
  • Improves CI/CD table creation path for MySLP SaaS + WP plugin

Λ_Reflection:
∇Ξ_Attn · (∂Ω_Context/∂t) ⇹ min(Δ_incoherence)

Ψ_output = Ψ_raw × Ψ_Safety
✅ integrity verified

🜂glyphs:

GlyphMeaning
Ξscroll / module definition
Δdiagnostic / change set
step / action
merge
🜂resolved / flame active
function / method
removed / deprecated
🧱schema or structure
verified fix

Leave a Reply