Wagtail-Geo-Widget

repository·main·Indexed 41 days ago

https://github.com/frojd/wagtail-geo-widget

A mapping solution for Wagtail CMS that allows editors to interact with maps and manage spatial data. It supports Google Maps and Leaflet-compatible providers (such as OpenStreetMap and Mapbox), integrates with Wagtail StreamField and Inline panels, and provides geocoding via Google, Nominatim, or Mapbox. The widget supports real spatial data using GeoDjango and PointField, or coordinate storage as strings.

Tokens
7.3K
Snippets
26
Records
31
Agent score
99%

What's inside Wagtail-Geo-Widget

  1. Overview of Wagtail-Geo-Widget features

    main

    Wagtail-Geo-Widget provides a complete map solution for Wagtail sites. Key capabilities include:

    • Map Providers: Supports Google Maps or any tile provider compatible with Leaflet (e.g., OpenStreetMap, Mapbox).
    • Spatial Data Support:
      • Real spatial support using GeoDjango and PointField.
      • Alternative coordinate storage as strings for setups without GeoDjango.
    • Integration: Supports Wagtail StreamField and Inline panels.
    • Geocoding: Search functionality via Google Geocoding, Nominatim, or Mapbox.
    • Additional Features: Optional address search fields and multi-language support.
  2. Add a Google Maps block to a Wagtail StreamField

    main

    To include a map within a Wagtail StreamField, use the GoogleMapsBlock. If you prefer using Leaflet instead of Google Maps, substitute GoogleMapsBlock with LeafletBlock.

    When iterating over the StreamField in a template, the map data is stored as a JSON structure. You can access the coordinates using .lat and .lng on the block's value.

    from wagtail.models import Page
    from wagtail.fields import StreamField
    from wagtailgeowidget.blocks import GoogleMapsBlock
    
    class GeoStreamPage(Page):
        body = StreamField([
            ('map', GoogleMapsBlock()),
        ], use_json_field=True)
    
        content_panels = Page.content_panels + [
            FieldPanel('body'),
        ]
    <article>
        {% for map_block in page.body %} 
            <hr />
            {{ map_block.value }}
            <p>Latitude: {{ map_block.value.lat}}</p>
            <p>Longitude: {{ map_block.value.lng }}</p>
        {% endfor %}
    </article>
  3. Add a zoom field to save map zoom state

    main

    To persist the map's zoom level, add a SmallIntegerField to your model and link it to the GoogleMapsPanel using the zoom_field parameter.

    Example

    from django.db import models
    from django.utils.translation import gettext as _
    from wagtail.admin.panels import FieldPanel, MultiFieldPanel
    from wagtailgeowidget.panels import GoogleMapsPanel
    
    class MyPageWithZoomField(Page):
        zoom = models.SmallIntegerField(blank=True, null=True)
        location = models.CharField(max_length=250, blank=True, null=True)
    
        content_panels = Page.content_panels + [
            MultiFieldPanel([
                FieldPanel("zoom"),
                GoogleMapsPanel("location", zoom_field="zoom"),
            ], _('Geo details')),
        ]
  4. Integrate Wagtail Geo Widget with GeoDjango

    main

    To use the geo widget, ensure GeoDjango is configured and your model includes a PointField. You can then add GoogleMapsPanel (or LeafletPanel if using Leaflet) to your content_panels to provide a map interface for that field.

    from django.contrib.gis.db import models
    from wagtailgeowidget.panels import GoogleMapsPanel
    
    
    class MyPage(Page):
        location = models.PointField(srid=4326, null=True, blank=True)
    
        content_panels = Page.content_panels + [
            GoogleMapsPanel('location'),
        ]
  5. Add a Google Maps map to a Wagtail Page

    main

    To add a map to your Wagtail admin, you need a CharField to store the location data and a corresponding content panel.

    Note: If you prefer using Leaflet instead of Google Maps, use LeafletPanel instead of GoogleMapsPanel in your content_panels configuration.

    Basic Implementation

    1. Define a CharField on your model to store the location string.
    2. Add GoogleMapsPanel to your content_panels list, passing the name of the field as the first argument.
    from django.db import models
    from wagtail.models import Page
    from wagtailgeowidget.panels import GoogleMapsPanel
    
    class MyPage(Page):
        location = models.CharField(max_length=250, blank=True, null=True)
    
        content_panels = Page.content_panels + [
            GoogleMapsPanel('location'),
        ]
  6. Add a Leaflet map to a Wagtail Page

    main

    To add a Leaflet map to a standard Wagtail Page, use LeafletPanel within your content_panels. The panel should target a field (e.g., a CharField) that will store the location data.

    from django.db import models
    from wagtail.models import Page
    from wagtailgeowidget.panels import LeafletPanel
    
    
    class MyPage(Page):
        location = models.CharField(max_length=250, blank=True, null=True)
    
        content_panels = Page.content_panels + [
            LeafletPanel('location'),
        ]
  7. Use an address field with the map panel

    main

    You can coordinate the map with a geo-lookup by providing an address_field argument to the map panel. This is typically used alongside a GeoAddressPanel to allow users to search for addresses which then updates the map location.

    from django.contrib.gis.db import models
    from django.utils.translation import gettext as _
    from wagtail.admin.panels import FieldPanel, MultiFieldPanel
    from wagtailgeowidget import geocoders
    from wagtailgeowidget.panels import GeoAddressPanel, GoogleMapsPanel
    
    
    class MyPageWithAddressField(Page):
        address = models.CharField(max_length=250, blank=True, null=True)
        location = models.PointField(srid=4326, null=True, blank=True)
    
        content_panels = Page.content_panels + [
            MultiFieldPanel([
                GeoAddressPanel("address", geocoder=geocoders.GOOGLE_MAPS),
                GoogleMapsPanel('location', address_field='address'),
            ], _('Geo details')),
        ]
  8. Hide the zoom field

    main

    To hide the zoom field in the Wagtail admin, apply the CSS class geo-field-zoom--hide to the field's panel or block.

    • For a FieldPanel, use the classname argument.
    • For a StreamField block, use the form_classname argument within the block tuple.
    # In a FieldPanel
    FieldPanel("zoom", classname="geo-field-zoom--hide")
    
    # In a StreamField
    ('zoom', GeoZoomBlock(required=False, form_classname="geo-field-zoom--hide")),
  9. Hide the latitude and longitude fields

    main

    You can hide the latitude and longitude fields in the Wagtail admin by passing hide_latlng=True to the panel or block configuration.

    For a standard GeoPanel (e.g., GoogleMapsPanel), pass the argument directly to the constructor. For use within a StreamField, pass it to the GoogleMapsBlock.

    # In a model field definition
    GoogleMapsPanel('location', address_field='address', hide_latlng=True)
    
    # In a StreamField definition
    GoogleMapsBlock(address_field='address', hide_latlng=True)
  10. Configure the Google Maps API key

    main

    To use Google Maps, you must retrieve an API key from the Google Cloud Console and add it to your Django settings using the GOOGLE_MAPS_V3_APIKEY key.

    Required Google Services

    Ensure the following APIs are enabled in your Google Cloud project:

    • Geocoding API
    • Maps JavaScript API
    • Maps Static API
    • Places API (New)
    • Places API (Only required if using the older GOOGLE_MAPS_PLACES geocoder)
    GOOGLE_MAPS_V3_APIKEY = "yourapikey"
  11. Add an address field with geocoding support

    main

    You can add an address field that allows users to search for locations. This process (geocoding) transforms a text description into coordinates.

    To implement this:

    1. Create a CharField for the address.
    2. Use GeoAddressPanel to provide the search interface.
    3. Pass the geocoder parameter to GeoAddressPanel to specify the service (e.g., geocoders.GOOGLE_MAPS_PLACES_NEW).
    4. Link the map to the address field by passing address_field='your_address_field_name' to the GoogleMapsPanel.

    Example

    from django.db import models
    from django.utils.translation import gettext as _
    from wagtail.admin.panels import FieldPanel, MultiFieldPanel
    from wagtailgeowidget import geocoders
    from wagtailgeowidget.panels import GeoAddressPanel, GoogleMapsPanel
    
    class MyPageWithAddressField(Page):
        address = models.CharField(max_length=250, blank=True, null=True)
        location = models.CharField(max_length=250, blank=True, null=True)
    
        content_panels = Page.content_panels + [
            MultiFieldPanel([
                GeoAddressPanel("address", geocoder=geocoders.GOOGLE_MAPS_PLACES_NEW),
                GoogleMapsPanel('location', address_field='address'),
            ], _('Geo details')),
        ]