WP Manifestindependent plugin directory
manifest / forms / find-my-rep-plugin

Find My Rep

A WordPress plugin that will search for your local representative and provide a templated letter to send via email service

by Bones5 · github.com/bones5/find-my-rep-plugin · website

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/bones5/find-my-rep-plugin/archive/refs/heads/main.zip

A WordPress plugin that creates a Gutenberg block for contacting local representatives via templated letters sent through Resend.

Plugin Frontend Preview

Features

  • Gutenberg Block: Easy-to-use block that can be inserted on any page
  • Representative Lookup: Search for local representatives by postcode via API
  • Multiple Representative Types: Supports MPs, MSs, local councillors, and PCCs
  • Customizable Campaigns: Per-block recipients, an optional question, and an editable letter template
  • Multi-recipient: Editors choose which representative types each block contacts
  • Email Integration: Sends letters via Resend API
  • Abuse Protection: Blocks abusive language, excessive link spam, and repeated rapid submissions
  • Sender Confirmation: Requires users to confirm they are personally sending the message

Installation

  1. Upload the plugin folder to /wp-content/plugins/find-my-rep-plugin/
  2. Activate the plugin through the 'Plugins' menu in WordPress
  3. Configure the plugin settings under Settings > Find My Rep

Configuration

Admin Settings

Navigate to Settings > Find My Rep to configure:

  1. Representatives API URL: Enter the API endpoint that returns representative data based on postcode

    • The API should accept a postcode query parameter
    • Should return JSON with representative details including: name, email, title or type
  2. Resend API Key: Enter your Resend API key for sending emails

  3. Letter Template: Define the default letter template

    • Use {{representative_name}} as a placeholder for the representative's name
    • Use {{representative_title}} as a placeholder for the representative's title
  • Use {{question_response}} wherever the optional visitor response should appear
  1. Test Postcode: Configure a postcode handled entirely by the plugin without calling the representatives API
  • Set the postcode to use for testing, such as ZZ999ZZ
  • Enter separate email addresses for the generated test MP, MS, PCC, and councillor
  • Each populated email creates one representative of that type with the required fields filled with test information
  • Leave a representative email blank to omit that type from the test results

Example Letter Template

Dear {{representative_name}},

I am writing to you as your constituent regarding [issue].

[Your message here]

I would appreciate your support on this matter.

Sincerely,
[User's name will be added automatically]

Usage

Adding the Block

  1. Edit any page or post
  2. Click the '+' button to add a new block
  3. Search for "Find My Rep Contact Form"
  4. Insert the block
  5. In the block, choose the representative types to contact, optionally add a required question prompt, and customize the letter template

User Experience

  1. Enter Postcode: Users enter their postcode to find representatives
  2. Answer Question: Optionally answer the campaign question when the editor has enabled one
  3. Edit Letter: Review and customize the letter template
  4. Send: Submit to all representative types configured for the block

Development

Technology Stack

  • TypeScript: Type-safe development with full type definitions
  • React: Modern component-based UI framework
  • WordPress Blocks API: Gutenberg block integration
  • @wordpress/scripts: Build tooling and linting

Requirements

  • Node.js and npm
  • WordPress 5.0+
  • PHP 7.0+
  • Docker (for running wp-env)

Building from Source

The plugin is written in TypeScript and React. To build:

npm install
npm run build

This compiles TypeScript/React code to JavaScript bundles in the build/ directory.

Creating a Plugin Release

package.json is the canonical plugin version. To increment it, synchronize the WordPress plugin header and constant, build the assets, and create an installable ZIP in one command:

npm run release -- patch

Use minor, major, or an exact version such as 1.2.3 instead of patch when needed. The command updates package.json and package-lock.json, then creates dist/find-my-rep-plugin-<version>.zip. It does not create a Git commit or tag.

To rebuild a ZIP without changing the version:

npm run package

Upload the ZIP through Plugins > Add Plugin > Upload Plugin in WordPress and confirm replacing the existing plugin. Review and commit the version changes, then create a matching Git tag after testing the ZIP.

Development Mode

For hot-reloading during development:

npm start

Code Architecture

The plugin follows a modern React/TypeScript architecture:

Source Files (src/):

  • index.tsx - Gutenberg block registration (editor view)
  • frontend.tsx - Frontend React app initialization
  • types.ts - TypeScript type definitions
  • components/ - React components for the frontend UI
    • FindMyRepApp.tsx - Main app container with state management
    • PostcodeStep.tsx - Postcode input step
    • QuestionStep.tsx - Optional campaign question step
    • LetterStep.tsx - Letter editing and submission step
    • LoadingSpinner.tsx - Loading indicator component

Build Output (build/):

  • index.tsx.js - Compiled block editor script
  • frontend.tsx.js - Compiled frontend React app
  • *.asset.php - WordPress asset files with dependencies
  • style.css - Plugin styles

Linting and Formatting

Run linting checks:

npm run lint:js

Auto-fix linting issues:

npm run lint:js -- --fix

Email Transport Modes

The plugin supports multiple email transport modes for development and production:

  1. Resend API (default for production): Uses the Resend API to send emails
  2. SMTP (wp_mail): Uses WordPress's built-in wp_mail() function (useful with MailHog for local development)
  3. Test (Log to File): Logs emails to a file for testing without sending (stored in wp-content/uploads/find-my-rep-test-mails.log)

Configure the transport mode in Settings > Find My Rep > Email Transport.

For local development with MailHog, see docs/MAILHOG-DEV.md.

Testing

The plugin includes three types of tests:

PHPUnit Tests

Run PHP unit tests for the email service:

npm run test:phpunit
# or directly: vendor/bin/phpunit

Tests include:

  • Template rendering and placeholder replacement
  • Email transport behavior (resend, smtp, test)
  • Error handling and edge cases

Jest Tests

Run React component tests:

npm run test:jest

Tests include:

  • LetterStep component validation
  • User interaction flows
  • Button states and loading indicators

E2E Tests (Playwright)

Run end-to-end tests using wp-env and Playwright.

Setup

  1. Install dependencies:
npm install
  1. Install Playwright browsers:
npx playwright install

Running Tests

  1. Start the WordPress environment:
npm run env:start
  1. Run the tests:
npm run test:e2e
  1. Run tests in headed mode (see browser):
npm run test:e2e:headed
  1. Debug tests:
npm run test:e2e:debug
  1. Stop the WordPress environment when done:
npm run env:stop

Other wp-env Commands

  • Clean all data: npm run env:clean
  • Access WordPress at: http://localhost:8888
  • Admin credentials: admin / password

API Response Format

The Representatives API should return data in the following format:

{
  "postcode": "CF10 1EP",
  "councillors": [
    {
      "id": 1,
      "name": "John Smith",
      "party": "Conservative",
      "ward": "St James's",
      "council": "Westminster City Council",
      "email": "john.smith@westminster.gov.uk"
    }
  ],
  "pcc": {
    "id": 1,
    "name": "Sir Mark Rowley",
    "force": "Metropolitan Police",
    "area": "Greater London",
    "email": "mopac@london.gov.uk"
  },
  "mp": {
    "id": 1,
    "name": "Nickie Aiken",
    "party": "Conservative",
    "constituency": "Cities of London and Westminster",
    "email": "nickie.aiken.mp@parliament.uk"
  },
  "mss": [
    {
      "id": 1,
      "name": "Joel James",
      "party": "Conservative",
      "constituency": "Cardiff Central",
      "email": "joel.james@senedd.wales"
    }
  ],
  "areaInfo": {
    "constituency": {
      "id": 65659,
      "name": "Cities of London and Westminster",
      "code": "E14000639"
    },
    "localAuthority": {
      "id": 2247,
      "name": "Westminster",
      "type": "London borough",
      "code": "E09000033"
    },
    "ward": {
      "id": 144393,
      "name": "St James's",
      "type": "London borough ward",
      "code": "E05000644"
    },
    "region": {
      "id": 2247,
      "name": "London",
      "type": "Government Office Region",
      "code": "E12000007"
    }
  }
}

The plugin automatically transforms this response into an internal format for display. Geographic information is extracted from areaInfo and displayed to users before the list of representatives. See API-INTEGRATION.md for detailed documentation.

License

GPL v2 or later