MinistryPlatform Custom Widget
Parish Finder — Installation Guide
A public parish directory that visitors can browse alphabetically or by city, search by name, and filter to the parishes within a chosen distance of their ZIP code — with every parish plotted on a map. No login required, no mapping API key, no billing account.
What the page does
The widget reads your Congregations where Available Online is Yes, follows each one to its Location record and that Location's Address, and uses the address coordinates to place a pin on the map and to measure distance.
- Browse A–Z — grouped under sticky letter headings with a jump bar across the top.
- Browse by city — grouped by city, with a count beside each city name.
- Search — narrows the list as the visitor types, matching parish name, location name, street, city, state, ZIP and county. Accents are folded, so avila finds Ávila.
- Find parishes near me — a ZIP code, city or full address, or one tap on Use my location. Results re-sort nearest-first, numbered 1, 2, 3 to match the map pins, and the chosen radius is drawn as a ring on the map.
- Map — clicking a pin opens the parish name, address, phone and a Get directions link. Hovering a card highlights its pin; Show on map works the other way round. On phones the list and map become tabs.
- Diocesan offices — congregations whose name contains Diocese , Archdiocese or Eparchy are shown in their own section pinned above the parish list, so the chancery never appears as the "nearest parish."
The page is entirely public. Nothing here requires a login, and no personal data is read or written.
What you need before starting
SQL Server Management Studio access to the MinistryPlatform database, edit access to the diocesan website, and the two files that ship with this guide:
deploy_ParishFinder.sql
— creates and registers the stored procedure.parish-finder-embed.html
— the entire front end: markup, styling, logic and the widget tag.Skip the SQL for a moment if you like.
Open parish-finder-embed.html
, change demoMode: false
to demoMode: true
, and paste it into a draft page. The finder renders with built-in sample
parishes so you can settle the colours and headings before the database work is done. Set it back to false
when you are ready to point at real data.
If you do not have a dedicated hosting plan or the required SQL Server skills, reach out to the professional services team for assistance. Normal hourly rates will apply.
Step 1 Run the database script
Open deploy_ParishFinder.sql
in SSMS, confirm the database dropdown shows the MinistryPlatform database
and not master
, and execute it. The script does three
things, all required:
- Creates
dbo.api_custom_ParishFinder, which returns the Available Online congregations with their location, address and coordinates. - Registers the procedure in
dp_API_Procedures, without which the MinistryPlatform API will not call it. - Links the procedure to the Administrators
security role in
dp_Role_API_Procedures. This step is the one most often missed, and the widget will not work without it — the API checks role links, not SQL permissions.
The script ends with verification queries. The first three must each return a row: Proc exists , API registered , Role linked. The fourth prints the parish rows the widget will receive, which is the quickest way to spot a parish with a missing address. It is safe to re-run the script; it will not create duplicates.
If your widget API client uses a role other than Administrators
Change @RoleName
— it appears in two places in the script, in the registration block and
again in the verification block. Change both.
Why the script looks old-fashioned
Plenty of MinistryPlatform databases still run at a SQL Server 2008 compatibility level even on a modern
server, which quietly removes functions you would otherwise reach for. The script therefore avoids TRY_CONVERT
, STRING_SPLIT
, CREATE OR ALTER
, DROP … IF EXISTS
, IIF
and CONCAT
. It also inspects dp_API_Procedures
and dp_Role_API_Procedures
before inserting, because the key column
is named API_Procedure_ID
on some versions and Procedure_ID
on others, and some
versions require a Domain_ID
that others do not have. The script prints which column names and
domain it found, which is a useful line to keep if you ever need to open a support ticket.
The practical consequence for you: coordinates arrive at the browser as the strings MinistryPlatform stores, and the widget parses them. A parish with a blank or malformed latitude is simply left off the map rather than breaking the query.
Step 2 Verify the API can reach the procedure
In a browser, open the following, replacing yourdiocese
with your MinistryPlatform host prefix:
https://yourdiocese.cloudapps.ministryplatform.cloud/sky/api/CustomWidget?storedProcedure=api_custom_ParishFinder
You should see JSON listing your congregations. If the response complains that a parameter was not
supplied, append &@DomainID=1
and try again.
If instead you see "Procedure … does not exist or user does not have access to it" , go to Troubleshooting below — this is almost always a missed registration step rather than a SQL permission problem.
Step 3 Add the page and configure it
Create a new page on the website — /parishes
or /find-a-parish
— and add a single
HTML embed containing the full contents
of parish-finder-embed.html
. Everything
an administrator normally touches lives in one place: the PF_CONFIG
block at the very top
of the file. You should not need to read past it.
The settings you will actually change
| Setting | What it does |
|---|---|
dataHost
|
Required.
Your MP host prefix — the part of your Platform URL before .ministryplatform.net
. Launch the Add/Edit Family Tool and take the first element of the
hostname if you are unsure. |
congregationIDs
|
""
for every Available Online congregation (the usual choice for a diocese), "5"
for one, or "5,8,12"
for a cluster. Because each page can carry a
different value, one deployment can serve a diocesan finder and a separate page per deanery from the
same stored procedure. |
pageTitle
, pageIntro
, officesTitle
|
The headings. Set pageIntro
to ""
to drop the introductory line. |
brandColor
, brandColorDark
, accentColor
|
Buttons, map pins, focus rings and the distance badge. brandColorDark
is used for hover
states — a noticeably darker shade of the same hue works best. |
mapStyle
|
"light"
is a clean greyscale basemap that lets the pins carry the colour. "street"
is classic OpenStreetMap; "terrain"
shows relief. |
mapCenter
, mapZoom
|
Only used for the instant before the parishes are plotted; the map then fits itself to your pins. Setting them near your diocese avoids a visible jump. |
ignoreLeadingTitles
|
true
files St. Mary
under M and Our Lady of Lavang
under L. Leave it
on unless your diocese publishes a strict A–Z: in a typical diocese a literal sort puts most of the
parishes under S and the letter index stops being useful. |
radiusOptions
, defaultRadius
, units
|
The distance dropdown. Use units: "km"
outside the United States and set geocodeCountry
to the matching two-letter country code. |
showLogos
, showPhone
, showDescription
, showGivingLink
|
Optional card content, drawn from Congregation Logo URL, Location Phone, Congregation Description and Congregation Giving URL respectively. Logos and phone are on by default. |
parishDetailPage
|
Everything up to the parish identifier, for example "https://www.example.org/parish?id="
. The Congregation ID is appended automatically, the
parish name becomes a link, and a Parish details
button appears on each card. Leave ""
to hide it. |
demoMode
, debug
|
Testing aids. demoMode: true
renders sample parishes without touching MinistryPlatform; debug: true
logs the widget's activity to the browser console. Both should be false
in production. |
Do not set showLogos: true
if every congregation shares one diocesan logo.
Identical thumbnails on every card add visual weight without adding information. Either give each parish its own Logo URL in the Platform or turn the option off.
Step 4 Test
- Open the page. You should see the toolbar, the parish list grouped under letter headings, and a map with one pin per parish.
- Type part of a parish name. The list and the map should both narrow, and a removable chip should appear showing the active search.
- Switch to By City. Sections should become city names with counts.
- Enter a ZIP code, choose a radius, and press Search. The list should re-sort nearest-first with numbered badges, the count line should read N parishes within X miles of … , and a ring should be drawn on the map. Widening the radius should bring more parishes in.
- Click a pin. The popup should show the address, the phone number if you publish one, the distance, and a working Get directions link.
- Narrow the browser to phone width. List and Map should become tabs.
- Press Reset filters. Everything should return to the full A–Z list.
MinistryPlatform configuration
The widget is only as good as the Congregation records behind it. For each parish that should appear:
| Field | Requirement |
|---|---|
| Congregations → Available Online | Yes. This is the only switch that controls whether a parish appears. Anything set to No is invisible to the widget. |
| Congregations → Congregation Name | What visitors see, and what the search matches. Consistent naming pays off: pick St. or Saint and stay with it. |
| Congregations → Location | Must point at the parish's Location record. A congregation with no Location still appears in the list, labelled Address not published , but cannot be mapped or measured. |
| Locations → Address | Street, city, state and postal code. The full address is also what the Directions button hands to Google Maps. |
| Addresses → Latitude / Longitude | Required for the map and the distance search. If these are empty the parish is listed but not pinned. Clear Do Not Validate and let MinistryPlatform geocode the address, or enter the coordinates by hand. |
| Locations → Phone | Optional. Shown as a tap-to-call link when showPhone
is on. |
| Congregations → Online Sort Order | Optional. Used only as a tie-breaker; the widget's own A–Z, city and distance ordering takes precedence on the page. |
| Congregations → End Date, Coming Soon | The procedure hides congregations with a past End Date and those flagged Coming Soon. This is how you retire a closed or merged parish from the page — set the End Date rather than deleting the record. |
The quickest audit is the last verification query in the deploy script. Any row with a blank Latitude or Longitude is a parish that will list but not map.
Troubleshooting
Blocks of documentation text appear on the page, or labels like "Filter by city" are visible
Both are website-builder side effects, and both are already handled in the current embed — if you are seeing them, you have an earlier copy of the file.
- Several builders, Duda among them, strip the
<!--and-->markers from an HTML embed and render what was inside as ordinary page text. The embed therefore contains no HTML comments at all; every note lives in a JavaScript or CSS comment instead. If you add commentary of your own, do the same. - The finder uses visually-hidden
<label>elements so that screen-reader users know what each field is. Host stylesheets frequently reset those to normal positioning, which dumps Search parishes by name or city and Filter by city onto the page. The rule is now forced. Do not delete the labels to work around it — that removes the accessibility they provide.
Everything is centred, the fonts are wrong, or the icon overlaps the text in a search box
The host theme is winning the specificity contest. Every rule in the embed is now scoped under the #pf-root
ID, which beats any selector that does not itself contain an ID, and alignment, font size
and form-control padding are re-asserted rather than inherited. If your theme still breaks through, it is using !important
or its own ID selector; add #pf-root
to the front of the offending rule in
the embed's stylesheet.
The page says "dataHost has not been set"
Exactly what it says: dataHost
at the top of the configuration block is still empty. Note that
the widget tag is configured by a small inline script that sits directly beneath it, deliberately, because customWidgetV1.js
initialises on DOMContentLoaded
— configuring the tag any later
means the widget fires first, with no host, and returns nothing. Do not move or remove that script.
"'TRY_CONVERT' is not a recognized built-in function name" or "'STRING_SPLIT' … invalid object name"
You are running an older version of the deploy script against a database at a low compatibility level. The current script does not use either function. If you see these errors, you have an earlier copy — take a fresh one. Do not raise the database compatibility level to work around it; that is a decision for whoever owns the MinistryPlatform instance, not a side effect of installing a widget.
"Cannot insert the value NULL into column 'Domain_ID', table '…dp_Role_API_Procedures'"
Your MP version requires a domain on the role link. The current script detects this and supplies it. Note that when this insert fails, the script may still print "Linked … to role" — the print statement runs even though the insert was rolled back, so trust verification query 4c, not the messages. If 4c returns no row, the link is not there.
"Could not find stored procedure 'dbo.api_custom_ParishFinder'" at the end of the script
The CREATE PROCEDURE
in Step 1 failed, so the preview at the end had nothing to run. Scroll up
in the messages pane to the first error — that is the real one. Everything after it is fallout.
"Procedure … does not exist or user 'apiuser' does not have access to it."
This message comes from the MinistryPlatform API, not SQL Server, and almost always means a missed registration step. Check in order:
- The procedure exists in the right database and in the
dboschema:SELECT SCHEMA_NAME(schema_id), name FROM sys.procedures WHERE name LIKE 'api_custom%' - A row exists in
dp_API_Procedureswith the exact name and no trailing spaces:SELECT QUOTENAME(Procedure_Name), LEN(Procedure_Name) FROM dp_API_Procedures— expect a length of 23. - A row links it to a role in
dp_Role_API_Procedures.
The deploy script's verification queries check all three.
The page shows "The parish list could not be loaded."
The widget did not return data within twelve seconds. Nearly always dataHost
is wrong. Confirm
it, then open the Step 2 URL directly — the error message on the page includes the exact URL to try. Setting debug: true
logs the widget's request and response to the browser console (F12).
The page loads but says no parishes were returned.
The widget reached MinistryPlatform and got an empty set. Either no congregation has Available
Online
set to Yes, or congregationIDs
lists IDs that do not match. Run the last
verification query in the deploy script to see what the database actually returns.
A parish is in the list but has no pin, and never appears in a distance search.
Its address has no coordinates. Open the Address record in the Platform, clear Do Not Validate , and let MinistryPlatform geocode it, or type the latitude and longitude in directly. Diocesan offices are deliberately exempt from the radius filter, so the office stays visible regardless of the search.
A pin is in the wrong place.
The coordinates on the Address record are wrong — commonly a geocode that landed on a street centroid, or a latitude and longitude entered the wrong way round. Compare against the parish's real position and correct the Address record; the widget will follow.
"We could not find that place" when a visitor enters a ZIP code.
Address lookup uses the OpenStreetMap Nominatim service, restricted to the country in geocodeCountry
. Confirm that code is right for your diocese. Nominatim also rate-limits heavy
automated use; ordinary visitor traffic is well within its terms, but if you are load-testing you will be
throttled.
The map is missing entirely, though the list works.
Leaflet did not load. Check that your site's content security policy allows scripts and styles from cdnjs.cloudflare.com
and map tiles from basemaps.cartocdn.com
(or tile.openstreetmap.org
if you chose mapStyle: "street"
). The finder is written to
degrade gracefully: the searchable, sortable list keeps working without a map.
Changes to the API registration don't take effect.
The API may cache its procedure list. Recycle the MinistryPlatform API application pool in IIS, or wait for the scheduled recycle. The widget caches responses for five minutes as well, so a hard refresh helps.
Customization notes
Colours come from the three settings in PF_CONFIG
; they are injected as CSS custom properties
at runtime, so there is no second place to keep in sync. If you want to go further, every rule in the
stylesheet is namespaced under #pf-root
and the custom properties are declared in one block at
the top of it — override --pf-radius
for squarer cards, or --pf-line
and --pf-bg-soft
to match a darker site theme.
Two behaviours are worth knowing about because they look like bugs until you know they are deliberate: scroll-wheel zoom on the map stays off until the visitor clicks the map, so that scrolling down the page is never hijacked; and the distance filter never hides a diocesan office, because people look for the chancery by name rather than by proximity.
The stored procedure is the place to change what data reaches the page. Its filters are plainly written and
commented — if your diocese wants Coming Soon parishes listed, or wants to include congregations regardless of
End Date, those are one-line edits. Adding a field means adding it to the SELECT
, to the Liquid
template's data attributes, and to the ingest
function in the embed, in that order.
Attribution
Map rendering uses Leaflet with tiles from CARTO and OpenStreetMap; address lookup uses OpenStreetMap Nominatim. The required attribution is displayed in the corner of the map and must not be removed. None of these services require an account, an API key or a billing relationship, which is the reason they were chosen over Google Maps for a widget that will be handed to many dioceses.