Install
Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/johnlockefoundation/carolina-election-map/releases/download/v1.0.4/carolina-election-map.zipCarolina Election Map — WordPress plugin
Embeds the Carolina Election Map in WordPress: North Carolina's 2026 U.S. House, U.S. Senate, NC Senate and NC House races, with prediction-market prices, poll averages, fundraising totals and district demographics.
Install
Upload carolina-election-map.zip through Plugins → Add New → Upload Plugin,
or unzip it into wp-content/plugins/. Then put [jce_map] in a page, or add the
Carolina Election Map block.
[jce_map]
[jce_map height="900px"]
What is in this repository, and what is not
This is the WordPress half. The plugin and the GitHub Pages site are one frontend built twice.
| This repository | nc26 | |
|---|---|---|
| PHP wrapper, shortcode, block | yes | no |
tools/build.sh, packaging checks |
yes | no |
| React frontend and its styles | no — built from there | yes |
| Race data, candidates, geometry | no — built from there | yes |
| Data pipeline | no | yes |
The split follows property-tax-demo → property-tax-bill. Nothing here reaches
into nc26's pipeline; the build consumes nc26's built output, the same way
property-tax-bill consumes the demo's.
Building
nc26 must be a sibling checkout:
git clone https://github.com/johnlockefoundation/nc26.git
cd carolina-election-map
bash tools/build.sh
Or point at it elsewhere with NC26_DIR=/path/to/nc26 bash tools/build.sh.
The build runs nc26's ingest and plugin build itself, because backend/db/ and
frontend/public/data/ are gitignored there and a clean checkout has neither.
What the build checks
tools/build.sh verifies the extracted zip, not the source tree. A bundler
never executes the code it emits, so "the build was green" only ever meant the
artifact was well-formed — and this project shipped a blank page through three
green checks before that distinction was made to bite. So the checks run against
what actually ships:
- no volatile key and no
is_mockmarker anywhere in the bundled reference layer php -lon every PHP file,node --checkon the bundle- the plugin version agrees between the header and
package.json, and the version in the zip matches the source - only
.php .md .css .js .json .pngship, and no dev files leak - every file the frontend requests at runtime is present
- the shortcode renders from the extracted zip and the output carries exactly one
[data-jce-root]in the parsed DOM
That last one is the check a green build cannot make. main.jsx in nc26 mounts on
[data-jce-root] and throws otherwise; renaming the attribute in the template
would render an empty div on every install with no error anywhere.
php tests/render-smoke.php is the same assertions against the source tree, for
when you are editing the PHP and do not need a full build.
Configuration
Defaults live in Carolina_Election_Map::config() and cover the Supabase endpoint,
the anon key, the cycle and the asset base. Override them with the jce_config
filter, from a theme's functions.php or a must-use plugin:
add_filter( 'jce_config', function ( $c ) {
$c['endpoint'] = 'https://your-project.supabase.co';
return $c;
} );
On the anon key
It is committed on purpose and it is not a credential. It identifies the project,
it is meant to ship in client bundles, and it grants nothing on its own: every
table has RLS enabled with SELECT-only policies for the anon role, so the most
anyone can do with it is read rows the page already displays. Rotating it is a
code change, not a leak response.
Why the bundled data is only the invariant part
The zip carries names, districts, the Census demographic profile and geometry. It deliberately does not carry poll averages, market prices, fundraising totals, registration or ballot-request figures, or news — all of those are read from Supabase at page load.
A figure baked into a plugin install reads as live for as long as the plugin is
installed, with no timestamp on it to say otherwise. This project shipped
fabricated registration and ballot counts on sixty seats that way before the
split was made. tools/build.sh fails the build if any of those keys reappears in
a bundled file, so the mistake cannot be repeated quietly.
License
GPL-2.0-or-later, matching the plugin header.
Releases
5 releases. Each count is every asset in that release; expand a row for the breakdown.