Skip to main content

Shopify Location-Based Product Visibility Using Product Metafields

This guide explains how to configure a Shopify store so customers only see products available at their selected location

Shopify Location-Based Product Visibility Using Product Metafields

Overview

While RP-Promap Adds the ability to use Location Targeting , this guide explains how to configure a Shopify store so customers only see products available at their selected location.

The implementation uses:

  • Shopify product metafields

  • A customer location selector

  • Liquid rendering

  • JavaScript filtering

  • Search integration

  • Optional add-to-cart restriction

This method works without Shopify Plus and does not require a custom app.


Requirements

Before starting, ensure your Shopify store has:

  • Online Store access

  • Theme code editing access

  • Product metafields enabled

  • A theme that supports custom Liquid edits (Dawn recommended)


System Architecture

Customer selects location         ↓ Location saved in browser storage         ↓ Collections + Search + Product pages filter products         ↓ Only products assigned to that location remain visible

Step 1 — Create Product Metafield

Open:

Shopify Admin → Settings → Custom Data → Products

Create a metafield:

Setting

Value

Name

Available Locations

Namespace and key

custom.available_locations

Type

List → Single line text


Step 2 — Assign Locations to Products

Open a product.

Under metafields:

Available Locations

Add values such as:

miami orlando dallas

Example:

Product

Locations

Miami Hoodie

miami

Florida Tee

miami, orlando

National Product

miami, orlando, dallas


Step 3 — Create Location Selector Snippet

Create:

snippets/location-selector.liquid

Add:

<div class="location-selector">   <label for="locationSelect">Choose location:</label>    <select id="locationSelect">     <option value="">All locations</option>     <option value="miami">Miami</option>     <option value="orlando">Orlando</option>     <option value="dallas">Dallas</option>   </select> </div>  <script>   document.addEventListener('DOMContentLoaded', function () {     const select = document.getElementById('locationSelect');     const saved = localStorage.getItem('selected_location') || '';      select.value = saved;      select.addEventListener('change', function () {       localStorage.setItem('selected_location', this.value);        document.dispatchEvent(new CustomEvent('locationChanged', {         detail: { location: this.value }       }));        filterProductsByLocation();     });   }); </script>

Step 4 — Add Selector to Header

Open:

sections/header.liquid

Add:

{% render 'location-selector' %}

Recommended placement:

  • Top navigation

  • Header utility area

  • Announcement bar


Step 5 — Configure Collection Filtering

Open your collection grid section.

Usually:

sections/main-collection-product-grid.liquid

Find:

{% for product in collection.products %}

Replace product wrapper with:

{% for product in collection.products %}   {% assign locations = product.metafields.custom.available_locations.value %}    <div     class="location-filter-product"     data-product-locations="{% if locations != blank %}{{ locations | join: ',' | escape }}{% endif %}"   >     {% render 'card-product', card_product: product %}   </div> {% endfor %}

Step 6 — Configure Search Filtering

Open:

sections/main-search.liquid

Find:

{% for item in search.results %}

Update product rendering:

{% for item in search.results %}    {% if item.object_type == 'product' %}     {% assign locations = item.metafields.custom.available_locations.value %}      <div       class="location-filter-product"       data-product-locations="{% if locations != blank %}{{ locations | join: ',' | escape }}{% endif %}"     >       {% render 'card-product', card_product: item %}     </div>    {% else %}     <div class="search-result-item">       <!-- existing non-product result code -->     </div>   {% endif %}  {% endfor %}

Step 7 — Add Global Filtering JavaScript

Open:

layout/theme.liquid

Before:

</body>

Add:

<script>   function filterProductsByLocation() {     const selectedLocation = localStorage.getItem('selected_location') || '';      const products = document.querySelectorAll('.location-filter-product');      products.forEach(function(product) {        const locations = product.dataset.productLocations || '';        const locationList = locations.split(',').map(function(location) {         return location.trim();       });        if (!selectedLocation || locationList.includes(selectedLocation)) {         product.style.display = '';       } else {         product.style.display = 'none';       }      });   }    document.addEventListener('DOMContentLoaded', filterProductsByLocation);    document.addEventListener('locationChanged', filterProductsByLocation);    document.addEventListener('shopify:section:load', function () {     filterProductsByLocation();   }); </script>

Step 8 — Product Page Availability Message

Open your product template section.

Usually:

sections/main-product.liquid

Add:

{% assign locations = product.metafields.custom.available_locations.value %}  <div   id="locationProductStatus"   data-product-locations="{% if locations != blank %}{{ locations | join: ',' | escape }}{% endif %}" ></div>  <script>   document.addEventListener('DOMContentLoaded', function () {      const box = document.getElementById('locationProductStatus');      if (!box) return;      const selectedLocation = localStorage.getItem('selected_location') || '';      const locations = box.dataset.productLocations || '';      const locationList = locations.split(',').map(function(location) {       return location.trim();     });      if (!selectedLocation) {        box.innerHTML = 'Select a location to check availability.';      } else if (locationList.includes(selectedLocation)) {        box.innerHTML = 'Available at your selected location.';      } else {        box.innerHTML = 'Not available at your selected location.';      }    }); </script>

Step 9 — Optional Add-to-Cart Restriction

Prevent checkout for unavailable locations.

Add below the previous script:

<script>   document.addEventListener('DOMContentLoaded', function () {      const selectedLocation = localStorage.getItem('selected_location') || '';      const statusBox = document.getElementById('locationProductStatus');      const addButton = document.querySelector('button[name="add"]');      if (!statusBox || !addButton || !selectedLocation) return;      const locations = statusBox.dataset.productLocations || '';      const locationList = locations.split(',').map(function(location) {       return location.trim();     });      if (!locationList.includes(selectedLocation)) {        addButton.disabled = true;        addButton.textContent = 'Unavailable at selected location';      }    }); </script>

Recommended Enhancements

Geolocation Auto-Selection

Automatically select the nearest store using:

  • Shopify Geolocation API

  • Cloudflare country headers

  • IP geolocation services


Store Pickup Integration

Combine with:

  • Shopify Local Pickup

  • Store Pickup apps

  • Delivery radius apps


Dynamic Inventory Sync

Advanced implementations can:

  • Sync actual Shopify inventory levels

  • Use Storefront API

  • Show per-location stock quantities


Limitations

This implementation:

✅ Filters storefront visibility
✅ Filters search results
✅ Supports collections
✅ Supports metafields
✅ Supports product pages

This implementation does NOT:

❌ Change Shopify inventory routing
❌ Change fulfillment logic
❌ Restrict warehouse assignment
❌ Modify Shopify checkout inventory behavior


Recommended Use Cases

Ideal for:

  • Multi-store retailers

  • Regional inventory

  • Franchise systems

  • Warehouse segmentation

  • Localized catalogs

  • Pickup-based commerce


Troubleshooting

Products Still Visible

Verify:

  • Product metafield values are correct

  • JavaScript loaded successfully

  • Product wrapper contains data-product-locations


Dropdown Not Saving

Check:

  • Browser localStorage enabled

  • No JavaScript console errors


Add-to-Cart Still Enabled

Verify:

  • Product page script added

  • Theme uses button[name="add"]

Some themes use custom selectors.


RP Promap Notes

Recommended naming convention:

custom.available_locations

Recommended location slugs:

miami orlando dallas

Use lowercase values only for consistency.


© Rose Perl Technology

Did this answer your question?