Data wont save when pulling values for select from API

Hi, I have tapped into the geonames api to pull towns and locations for my business listings. It works fine on the filter and the search however on the admin and editing the listing it resets to blank - any ideas where I might be going wrong? The filter and search can be viewed on storycinn.com. Any help here would really be appreciated. To confirm works on the search - but not on the update or add listing using ‘hivepress/v1/forms/listing_submit’ and ‘hivepress/v1/forms/listing_update’

current code for attributes which loads but wont save!

add_filter(
'hivepress/v1/meta_boxes/listing_attributes',
function( $meta_box ) {
   
if ( isset( $meta_box['fields']['town'] ) ) {
        print_r($meta_box);
        $selected_value = $meta_box['fields']['town']['selected'] ?? null;
       
        // Add new dynamic values
       $options = fetch_irish_towns_from_geonames();
       
        // If a selected value exists, ensure it's part of the options list
        if ( $selected_value && !in_array( $selected_value, $options ) ) {
            // Prepend the selected value to the options array if it's not already present
            array_unshift( $options, $selected_value );
        }

        // Update the field with new options
        $meta_box['fields']['town']['options'] = $options;
     
       
}

return $meta_box;
},
    1000
);
function fetch_irish_towns_from_geonames() {
    $transient_key = 'irish_towns_geonames';
    $towns = get_transient($transient_key);

    if ($towns === false) {
        $username = 'swdadmin';
        $api_url = 'http://api.geonames.org/searchJSON?country=IE&q=Wexford&featureClass=P&maxRows=1000&username=' . $username;
        $response = wp_remote_get($api_url);

        if (is_wp_error($response)) {
            return [];
        }

        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);

        if (!isset($data['geonames'])) {
            return [];
        }

        $towns = [];
        foreach ($data['geonames'] as $place) {
            $towns[] = $place['name'];
        }

        // Cache the results for 12 hours
        set_transient($transient_key, $towns, 12 * HOUR_IN_SECONDS);
    }

    return $towns;
}

Please try using the hivepress/v1/models/listing/attributes filter hook instead, this way if you insert a new attribute of Select type, set editable flag for it and _external flag for it’s edit_field parameters, it will automatically appear in the listing edit form, back-end meta boxes, search form, etc. and will be in sync. You can provide selectable API options to the options array of the field parameters. Please check some sample code snippets here Search · user:hivepress hivepress/v1/models/listing/attributes · GitHub

Hay thanks for this - almost there. Its working now on the business listing user on the /account/listings page but not within the admin. is it a different space where the external is set? Its working fine now for filter/search and business listing user but not the admin. The data wi

Hi,

Please provide the PHP snippet that adds the attribute, this one for hook attaributes and we will review and try to help.

Is where Im trying to load it in however I get “towns” field contains an invalid value. Towns is the attribute name. It works fine on the search and filter (at least it saves the values in the select dropdowns. Add listing from enduser and within wp-admin doesnt save. I assume due to some validation taking place??

I have added a link here for the full functions file from mydrive in case there is issue: functions for hivepress - Google Docs

If this is the only snippet (excluding the function which fetches options) then it’s not fully valid, please try using the hivepress/v1/models/listing/attributes hook only (instead of the meta box hook), then the field will be added everywhere and will be validated correctly.

Same issue:

ive added:

add_filter(
	'hivepress/v1/models/listing/attributes',
	function( $attributes ) {
		if ( isset( $attributes['towns'] ) ) {
			$attributes['towns']['edit_field']['editable'] = true;
            $attributes['towns']['edit_field']['_external'] = true;
		}
 
		return $attributes;
	},
	1000
);

And:

when within the admin wont load at all. Works fine in search and filter??? Any ideas, feel like im going backward at the min and I know its something small

Please try this snippet and disable all the other customizations regarding this (you can also remove or unpublish the Towns attribute in Listings/Attributes):

add_filter(
	'hivepress/v1/models/listing/attributes',
	function( $attributes ) {
		$attributes['towns'] = [
			'editable'   => true,

			'edit_field' => [
				'label'     => 'Towns',
				'type'      => 'select',
				'_external' => true,
				'_order'    => 123,

				'options'   => [
					'one'   => 'one',
					'two'   => 'two',
					'three' => 'three',
				],
			],
		];

		return $attributes;
	},
	1000
);

Once you test it, please replace an array of options with a function which provides an array fetched from the API.

Hope this helps

Perfecto!!! Loads and saves in all the right places.

hay I have moved it someway along with it now showing in the search and the filter. However even when using the simple array above the search results are coming back empty
url:storycinn.com/listings

current code (for search tool and filters):

add_filter(
	'hivepress/v1/models/listing/attributes', function( $attributes ) {
	$attributes['towns'] = [
            'editable'   => true,
            'searchable' => true, // Make the attribute searchable
            'filterable'  => true,
            'display_areas' => ['view_block_secondary','view_page_primary','view_page_secondary'],

            'edit_field' => [
                'label'     => 'Towns',
                'type'      => 'select',
                '_external' => true,
                '_order'    => 120,

                'options'   => [
					'one'   => 'one',
					'two'   => 'two',
					'three' => 'three',
				],
            ],

            'search_field' => [ // Define the search field configuration
                'type'    => 'select', // Can be 'text', 'select', etc.
                'label'   => 'Towns', // The label shown in the filter tool
                '_order'    => 123,
                'options'   => [
					'one'   => 'one',
					'two'   => 'two',
					'three' => 'three',
				],
            ],
                
        ];
    

		return $attributes;
	},
	1000
);

The snippet seems to be ok, I’m afraid that there’s no search support for Select fields not based on taxonomies yet (I added this to the bug tracker). In this case, I recommend creating a Towns field manually in Listings/Attributes (then it will be based on taxonomy terms), and populating terms from the API, e.g. based on an hourly or daily recurring action (you can use the hivepress/v1/events/hourly hook), and in the function you add to the hook you can fetch data via the API and create taxonomy terms (e.g. of “hp_listing_towns” taxonomy if you named the field “towns”) wp_insert_term() – Function | Developer.WordPress.org or delete terms if not available in the list from the API.

Nightmare, I was afraid of this - is there a way to manipulate a standard field instead of a select box so its detected with the s=? in the search. Outside of that could I leverage a custom category and have sub values to it like how the categories currently work with the attributes? I could load town based against each county then?

It’s possible to enable keyword search if you add the _indexable flag to the attribute configuration, but the selectable filter itself (in the search filters form) will not work unfortunately. It’s still doable via the taxonomy terms, even if you need to refresh this API data often you can do this via other hooks (which don’t run hourly or daily, but on specific actions), e.g. on the hivepress/v1/forms/listing_update form loading, and sync the taxonomy terms. It works the same way as providing an array of options directly, but in this case taxonomy terms just work like cached options (although syncing taxonomy terms requires more custom code for sure).

Thanks in the end I have gone for a hybrid approach. On add or update listing I have used the dynamic content in the dropdown but the for the search I have used the text field as its searching the value. Then for the add fields I have added ajax call based on the content for the field to dynamically populate the fields so I am 95% there with a blended approach. Really appreciate the time and effort you put in to help me get solution in place.

1 Like

Hay stumbled on an issue. Is it possible to load the following filter but allow for dynamic values after they load. I have it on the page that when another field changes (county like state) then the values of the below dropdown change. However I get an invalid value for tow error as its not an expected value in hivepress flow.

add_filter(
	'hivepress/v1/models/listing/attributes', function( $attributes ) {
	$attributes['towns'] = [
            'editable'   => true,
            'searchable' => true, // Make the attribute searchable
            //'filterable'  => true,
            'sortable'  => true,
            'indexable'  => true,
            'display_areas' => ['view_block_secondary','view_page_primary','view_page_secondary'],

            'edit_field' => [
                'label'     => 'Town',
                'type'      => 'select',
                '_external' => true,
                '_order'    => 103,
                'options'   => fetch_irish_towns_from_geonames($attributes),
                'required'  => false,

                
            ],

I have tried

add_filter('hivepress/v1/models/listing/attributes/towns/validate', function($valid, $value, $field) {
    return true; // This will bypass validation for the 'towns' field
}, 10, 3);

without success. Any ideas?. Let me know if additional clarity is needed.

Yes, you can load Select options dynamically depending on the selection of another Select field. You can do this by providing the “source” parameter, it should be set to a REST API endpoint URL which returns results in JSON format. Here’s an example of the time slots field from Bookings, where results depend on which date is selected in the Date field Awesome Screenshot

I highly recommend using Geolocation with Regions feature instead of a custom solution, but if you have a strict list of locations then Geolocation may not be suitable.

In relation to my structures how do you recommend the best way to apply:

add_filter(
	'hivepress/v1/models/listing/attributes', function( $attributes ) {
	$attributes['towns'] = [
            'editable'   => true,
            'searchable' => true, // Make the attribute searchable
            //'filterable'  => true,
            'sortable'  => true,
            'indexable'  => true,
            'display_areas' => ['view_block_secondary','view_page_primary','view_page_secondary'],

            'edit_field' => [
                'label'     => 'Town',
                'type'      => 'select',
                'source'    => [],
                '_external' => true,
                '_order'    => 103,
                'options'   => [],
                'required'  => false,

                
            ],

            'search_field' => [ // Define the search field configuration
                'type'    => 'text', // Can be 'text', 'select', etc.
                'label'   => 'Towns', // The label shown in the filter tool
                '_order'    => 113,
                'placeholder'   => 'Enter town name',
                'class' => 'swdtowns',
                
            ],
                
        ];
    

		return $attributes;
	},
	1000
);

and jquery:

jQuery(document).ready(function($) {

$(document).on('select2:select', '[name="location"]', function(e) {
        // Action when an option is selected
        var selectedData = "";
        var selectedData = e.params.data;
        var selectedCounty = selectedData.text;
         var apiUrl = '//secure.geonames.org/searchJSON';
    var username = 'swdadmin'; // Replace with your GeoNames username
    var country = 'IE'; // Fixed country code
        // You can use AJAX to send this value to a PHP function
        console.log(selectedCounty); // for debugging
        //var requestUrl = apiUrl + '?country=' + country + '&q=' + selectedCounty + '&featureClass=P&maxRows=1000&username=' + username;
  var requestUrl = apiUrl + '?q=' + selectedCounty + '&featureClass=P&maxRows=1000&username=' + username;
 
 console.log(requestUrl);
 $.ajax({
            url: requestUrl,
            method: 'GET',
            
            dataType: 'json', // Expecting a JSON response
            success: function(response) {
               // Clear the "towns" select dropdown before populating new options
                $('select[name="towns"]').empty();

                // Check if we have results
                if (response && response.geonames && response.geonames.length > 0) {
                    // Loop through each town in the API response
                    $.each(response.geonames, function(index, town) {
                        // Create a new option element for each town
                        var option = $('<option>', {
                            value: town.name, // Town name as the value
                            text: town.name   // Town name as the display text
                        });
                        
                        // Append the new option to the "towns" select
                        $('select[name="towns"]').append(option);
                    });
                } else {
                    // If no results, show a placeholder message
                    $('select[name="towns"]').append($('<option>', {
                        value: '',
                        text: 'No towns found'
                    }));
                }
            },
            
            error: function(xhr, status, error) {
                // Handle any errors from the API call
                console.log("Error: ", error);
            }
        });
    });


  
    

      });

You can add a “source” parameter to the “edit_field” of the attribute you added, it should point to a URL which returns a JSON with select options. You can also set the “parent” parameter like in this example Awesome Screenshot Then when the parent field changes, the child field (“towns” select field in this case) will send a GET request to the source URL and will use the JSON response to populate the drop-down.

This change is needed if you want to populate a list of towns based on another select value, but if dynamic list is not required then it’s ok. Another more simple workaround is using a single hierarchical list of states and towns with multistep parameter set to true. This would allow selecting a state and town within a single drop-down.

And a possible more simple workaround is using the Geolocation extension where the selected map provider fetches a list of all the needed places, possibly you can restrict this list to states and towns only (via JS) and this may be more simple that creating a custom solution from scratch. If you also enable Regions feature then a separate category (taxonomy term) will be created for each state/town.

Hope this helps