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:
| Glyph | Meaning |
|---|---|
| Ξ | scroll / module definition |
| Δ | diagnostic / change set |
| ⊢ | step / action |
| ⊕ | merge |
| 🜂 | resolved / flame active |
| ⚙ | function / method |
| ✂ | removed / deprecated |
| 🧱 | schema or structure |
| ✅ | verified fix |