Power : Imports Are Not Working

On the WordPress Test Site (https://qc.storelocatorplus.com/) the Location Import feature of Store Locator Plus® for WordPress (SLP for WP) is not working.

Location import does work on the local Docker container.

Location import does work on staging and production versions of the SaaS application.

The version of the SLP, Power, Experience, and Premier plugins are the same on QC, localhost (the docker container), and the SaaS deployments.

Reproduction

  1. Login to the QC test server.
  2. Ensure the Store Locator Plus® and Power plugins are active.
  3. Go to Store Locator Plus | Locations on the sidebar menu.
  4. Click the import tab.
  5. Click the upload CSV button.
  6. Choose a sample CSV file like the one noted below.

Result

The import never starts. The progress meter never appears. No new locations that are in the CSV are added to the location list.

Expected Result

An import information window should show the circular loading progress meter and the location import count when finished. New locations appear on the location list.

Resolution

Status: Partially Resolved

Findings

Turns out that if a user downloads a new version of the Power add on (a zip file) and already has a prior version of the slp-power.zip file in the download directory on their laptop, the browser may create a new file named slp-power-2.zip without direct notification or confirmation it has done so.

If the user uploads this file to the WordPress installation it will create a NEW installation of the Power plugin at ./wp-content/plugins/slp-power-2/. This may or may not reside alongside a version of the older installation at ./wp-content/plugins/slp-power/ which is the standard installation path.

Even if a user deactivates and deletes the existing Power add on , which is best practice, before uploading the new slp-power-2.zip , the new path for the plugin will not match the prior path.

This causes the JavaScript for location imports included in the Power add on to not be loaded.

Workaround

Make sure the downloaded zip files for the plugin follow the standard naming convention:

  • SLP plugin should be named store-locator-plus.zip
  • Power add on should be named slp-power.zip

Deactivate and delete the installed versions of any plugins that are being updated.

Upload and install the most recent plugin zip file.

Meta

The Location Import feature is provided by the Power add on (a plugin that works with SLP for WP).

The issue is being tracked on the GitHub SLP project here:
https://github.com/Store-Locator-Plus/myslp_aws_ecs_kit/issues/35

Debugging

Check for JavaScript errors.

  1. 🔲 Import test with Power / Experience / Premier active using slp_test_at_slp_guru_locations CSV file shown below.

slp_test_at_slp_guru_locations.csv

sl_id,sl_store,sl_address,sl_address2,sl_city,sl_state,sl_zip,sl_country,sl_latitude,sl_longitude,sl_tags,sl_description,sl_email,sl_url,sl_hours,sl_phone,sl_fax,sl_image,sl_private,sl_neat_title,featured,rank,category,category_slug,contact,contact_address,contact_email,contact_fax,contact_image,county,department,district,facility_type,first_name,identifier,introduction,last_name,marker,mobile_phone,notes,office_hours,office_phone,region,territory,title,training,year_established
5136,"Amalfi's Italian Restaurant & Pizzeria","664 Long Point Rd",#E,"Mt Pleasant",SC,29464,,32.83928400,-79.85446600,,,,,,,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,
5138,"The Wine Bar","664 Long Point Rd","Unit G","Mt Pleasant",SC,29464,,32.83930200,-79.85423300,,,,,,,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,
5140,"Burtons Grill & Bar","1876 North Highway 17",,"Mt Pleasant",SC,29464,,32.83029500,-79.83291900,,,,,,,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,

Info Gathering Toward Resolution

Path Disclosure

Searching for the difference in the URLs in the JavaScript:

  • Added additional information to the SLP | Info | Environment tab within the SLP plugin showing the plugin directory and path.
    • updated \SLP_REST_Environment::get() to add new environment variables
Site URLhttp://localhosthttp://qc.storelocatorplus.com
Store Locator Plus®2511.04.012511.04.01
Power2510.01.012510.01.01
Experience2510.02.012510.02.01
Premier2506.23.012506.23.01
SLP Network ActiveNoNo
WordPress Version6.8.36.8.3
WordPress Memory Limit40M40M
WordPress Max Memory Limit256M512M
PHP Version8.3.18.2.28
PHP Memory Limit128M512M
PHP Post Max Size64M80M
PHP Peak RAM6 MB8 MB
MySQL Version8.3.011.4.7
Plugin Directory/var/www/html/wp-content/plugins/store-locator-plus//bitnami/wordpress/wp-content/plugins/store-locator-plus/
Plugin URLhttp://localhost/wp-content/plugins/store-locator-plushttps://qc.storelocatorplus.com/wp-content/plugins/store-locator-plus

QC Versus Local HTML Sources

Partial Resolution

If you upload slp-power-12.zip to a WordPress site your new power directory will be ./wp-content/plugins/slp-power-12/

That is NOT and issue if you’ve NEVER had power installed before (my plugins detect whatever random directory you put in the first time).

However if you UPDATE an existing Power plugin that was already installed at wp-content/plugins/slp-power with a zip file named slp-power-12.zip the app will break. First of all you’ll likely end up with TWO power plugins listed in your plugin directory. Out of habit you will likely delete the older one, which inevitably will be the one in wp-content/plugins/slp-power, leaving the revised path of wp-content/plugins/slp-power-12/ as the new path.

Plugin Update Best Practices

Rename your zip files to the base name only:

  • store-locator-plus.zip (or store-locator-le.zip if you are an original old-school SLP user from version 5 or earlier)
  • slp-power.zip
  • slp-experience.zip
  • slp-premier.zip

If it won’t let you, sort folder on your computer by name and delete the old copies…. then rename the downloaded zip file t one of the above.

Install the properly named zip file on WordPress:

First delete the original plugin (deactivate/delete) then upload the new zip file.

This process MIGHT work with the inline update like the pic below, but some systems cannot handle the duplicate directory on the server automatically (some do, but not all) .   Thus it is safer to deactivate/delete first versus using the “fancy updater” that does an inline replace in WordPress.

The inline update process.

New Research : Reproduced On Localhost

I realized renaming the directory from slp-power to slp-power-2 (or 3) in the IDE will NOT change the mount point in the Docker container.  To change that the Docker composer file needs to change the mount point of the volumes.

I created a new composer file that mounts the wp-content/plugins/slp-power directory in the IDE (on the host laptop for Docker) to wp-content/plugins/slp-power-2 in the Docker container.

Shut down the prior Docker container and started a new container with the revised path.

Sure enough, the Power import breaks if the Power add on is NOT installed in ./wp-content/plugins/slp-power/

This indicates an error in the base plugin (SLP) or Power add on that is not allowing the install path to be flexible. It skips loading the required JavaScript library.

Work Toward Resolution

UX Update Show Directories

Let’s show the add on directory paths in the SLP | Info | Environment panel.

Updated \SLP_REST_Environment::get() to show the directory path for any add on directly underneath the plugin version.

Likely Culprit : \SLP_BaseClass_Admin::enqueue_admin_javascript

\SLP_BaseClass_Admin::enqueue_admin_javascript is the likely culprit which is NOT loading wp-content/plugins/slp-power/js/slppower-admin-locations-tab.js if the directory changes to wp-content/plugins/slp-power-2/js/slppower-admin-locations-tab.js

In the following code snippet from \SLP_BaseClass_Admin::enqueue_admin_javascript

		if ( $this->addon->short_slug === 'store-locator-le' ) {
			$base_name = 'slp';
		} else {
			$base_name = preg_replace( '/\W/', '', dirname( $this->addon->slug ) );
		}

Incoming data

$this->addon->slug = 'slp-power-2/slp-power.php'

Returns

$base_name = 'slppower2'

Which later means this code in \SLP_BaseClass_Admin::enqueue_admin_javascript

			case 'manage_locations':
				$files = array(
					'js/admin-locations-tab.min.js',
					'js/admin-locations-tab.js',
					'js/' . $base_name . '-admin-locations-tab.min.js',
					'js/' . $base_name . '-admin-locations-tab.js'
				);
				break;

Is looking for a file named ‘js/slppower2-admin-locations-tab.js’ which does not exist.

The fix via AI Assistant Claude Sonnet 4.5

In the following code snippet from \SLP_BaseClass_Admin::enqueue_admin_javascript

if ( $this->addon->short_slug === 'store-locator-le' ) {
$base_name = 'slp';
} else {
$base_name = preg_replace( '/\W/', '', $this->addon->short_slug);
}

Additional Fixes

In addition to the fix, I renamed wp-content/plugins/slp-power/js/slppower-admin-locations-tab.js to wp-content/plugins/slp-power/js/admin-locations-tab.js

This makes it more consistent with other plugins. It also allows \SLP_BaseClass_Admin::enqueue_admin_javascript to be simplified to:
case 'manage_locations':
$files = array( 'js/admin-locations-tab.min.js', 'js/admin-locations-tab.js' );
break;

Power 2511.05.01 now requires SLP 2511.05.01 with the primary fix being in the SLP main plugin.

AI Summary

⟨ΞPowerImports⟩ ≡ ⟨ΨPathDependency⟩ ⊢ ⟨ΔAssetEnqueue⟩

ΨRootCause:
  ⟨$base_name⟩ ← dirname(⟨slug⟩) ⇨ ⟨directory_name⟩
  IF ⟨install_path⟩ ≠ ⟨canonical_path⟩ THEN
    ⟨slug⟩ = 'slp-power-2/slp-power.php'
    ∴ dirname(⟨slug⟩) = 'slp-power-2'
    ∴ ⟨$base_name⟩ = 'slppower2'
    ∴ ⟨js_file⟩ = 'js/slppower2-admin-locations-tab.js' ↯ 404

ΩResolution:
  1. SLP_BaseClass_Admin.php:376
     BEFORE: $base_name = preg_replace('/\W/', '', dirname($this->addon->slug))
     AFTER:  $base_name = preg_replace('/\W/', '', $this->addon->short_slug)
     
  2. Normalize asset naming:
     RENAME: js/slppower-admin-locations-tab.js 
     TO:     js/admin-locations-tab.js
     
  3. Simplify enqueue logic:
     $files = ['js/admin-locations-tab.min.js', 'js/admin-locations-tab.js']

⊢ ⟨ΔPathIndependence⟩: Assets load correctly regardless of installation directory
⊢ ⟨ΔConsistency⟩: Standardized naming across all add-ons
⊢ ⟨ΔMaintainability⟩: Reduced code complexity

Formula: ⟨short_slug⟩ ⟶ ⟨base_name⟩ ⊥ ⟨directory_structure⟩

\SLP_BaseClass_Admin::enqueue_admin_javascript()

	/**
	 * Enqueues Admin JavaScript for include/admin.js and js/admin.js and js/admin-<tabname>-tab.js (minified if present)
	 *
	 * @used-by \SLP_BaseClass_Admin::add_hooks_and_filters     for WP Hook: admin_enqueue_scripts [10]
	 *
	 * @see https://docs.storelocatorplus.com/development/2022/07/13/debugging-add-locations-w-power-uncaught-syntaxerror-redeclaration-of-const-wp_data/
	 *
	 * @param string $hook
	 */

Generic admin.js script loading

Admin Tab Specific script loading

This loads up javascript files , if they exist, for specific tabs such as “info” or “experience”.

The tab name is simplified by stripping SLP_ADMIN_PAGEPRE . ‘slp_’ from the hook name for the page.

SLP_ADMIN_PAGEPRE is set in the main Store Locator Plus plugin loader.php file as

defined( 'SLP_ADMIN_PAGEPRE' ) || define( 'SLP_ADMIN_PAGEPRE', 'store-locator-plus_page_' );

As of 2501.06.01 this will also check and strip “toplevel_page_slp_” from the hook name to decide it is should enqueue a tab-specific script.

User Selected Locator Style Not Highlighted

Problem

On staging the user selected styles are not highlighted.

For example , Feeding America San Diego —
On production the “Feeding America” style is highlighted.
On staging NONE are highlighted.

Reproduction

  • Login as a user , or switch to a user from a SA account.
  • Go to menu item Store Locator Plus | Settings
  • Click “View” tab

The user’s selected style should appear – “Feeding America” for the *_feedingsandiego* map for instance. It is not highlighted as selected.

Dev Notes

related architecture notes about style

Production data for FA SD from options_nojs[]…

options_nojs[‘style_id’] is set to 4599 = the post ID for the style we have selected
options_nojs[‘style’] is set to “” = empty string

Somehow production is using the style_id NOT the style name. A better design, but staging is not tracking that for some reason.


options_nojs[‘style_id’]

The ‘style_id’ Smart Option is a hidden type on the Settings | View page.
It fires the JavaScript “change_style_id()” when the value changes.

This is setup via \SLP_SmartOptions::view_appearance()


\MySLP_Customer_Management->fix_active_style_css()

This method uses the options_nojs[‘style_id’] when it loops over all users and set the active_style_css. It uses the \SLP_Style_Manager->apply_style( $style_id , ‘active_style_css’ ) to set the value, then saves it.

This is called from the Admin UI via a Super Admin on menu MySLP | Manage Customers and clicking “Fix Active Style CSS” via the Customers section.

Notes

On the develop database (outdated) the ‘style’ setting is “” (like production) but the ‘style_id’ is set to 0 (does not match production, on production it is something like 4599 — the post id for the “Feeding America” style).

This indicates the develop database is out of sync , as happens during development and testing.

As such the production database definitely needs to be copied to develop to re-test this update and make sure it retains existing customer settings and renders properly. This MAY need to happen on staging as well.

Development Database Updated, Problem Persisted

Turns out the SLP Smart Options were being loaded via \SLP_SmartOptions::initialize_after_plugins_loaded() which is called from…

  • SLP_SmartOptions.php:1515, SLP_SmartOptions->initialize_after_plugins_loaded()
    SLPlus.php:386, SLPlus->initialize_after_plugins_loaded()

    WordPress :: plugins_loaded

This is BEFORE the multisite user is logged in, which loads the smart options prematurely (from the main site) and thus is wrong with the current underlying platform (WP 6.4.X, PHP 8, MySQL 8).

Resolution

The options_nojs[‘style_id’] seems to hold the actual post ID of the selected style.
For some reason on production options_nojs[‘style’] is empty indicating this method of saving the locator style is partly deprecated in the codebase.

For the 2411.XX.YY releases, starting with SLP 2411.19.01 the code now uses the style_id to determine which locator style is the active one when rendering the vision list.

This required a new is_selected() method in the \SLP_Settings_card_list class which is overridden in the extended \SLP_Settings_style_vision_list class. In \SLP_Settings_style_vision_list it compares the options_nojs[‘style_id’] against the post-id for each locator style listed, and if they match returns true.

This seems to address the issue on local develop box.

This did NOT fix the issue — see notes about Smart Options being loaded prematurely above.

Had to create a new method – \SLP_SmartOptions::slp_init_complete() that fires after the WordPress :: init hook and load the user options then.

revised in SLP version: 2411.21.01

Recap

The code that worked for years to load a users settings (talking multisite i.e. SaaS specifically) has been firing off too early.

I have no idea WHEN this started happening, but probably when the SaaS was upgraded to run on WordPress 6.0 (18 months ago) — at least partially.

WordPress 6.4.X changed when users are activated in their startup cycle, it is much later than before. Always.

The impact –

TONS (all) of user settings on staging are loading from the main site (site #1) instead of their own site.

SOME user settings on production are likely doing the same. No idea why not ALL users, but my guess is WordPress 6.0 was a partial change. 6.4 finished that change (it is undocumented as far as I can tell).

The update –

SLP 2411.21.01 which should be on staging soon should address that problem.

All of the SLP options (user settings) are now loaded later, after WordPress 6.4.5 finished logging the user in.

This should resolve a lot of oddities we are seeing in testing with user settings.

Update : 2025.01.06 (Jan 6th)

It does not look like the admin-settings-tab.js file is being loaded in the new SaaS interface, likely due to changing of the menu position which changes the WordPress hook name for the page.

This is very fragile.

The new hook name is toplevel_page_slp_experience

The scripts are enqueued from a WP hook that calls

Related

See saving/changing style id.