Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,40 @@ jobs:
- name: Run ESLint (astro-payload-richtext-lexical)
run: cd astro-payload-richtext-lexical && pnpm lint

test-geocoding:
runs-on: ubuntu-latest
needs: format
name: test-geocoding

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Setup environment variables
run: |
echo "PAYLOAD_SECRET=test-secret-not-for-production" > geocoding/dev/.env
echo "SQLITE_URL=file:./payload-test.db" >> geocoding/dev/.env
echo "NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=test-api-key" >> geocoding/dev/.env

- name: Setup pnpm
uses: pnpm/action-setup@v5
with:
version: ^9.0.0

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install:all

- name: Run tests
run: cd geocoding && pnpm test:sqlite
env:
PAYLOAD_DATABASE: sqlite

test-pages-localized:
runs-on: ubuntu-latest
needs: format
Expand Down
64 changes: 64 additions & 0 deletions geocoding/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,70 @@ geocodingField({
}),
```

## Usage with AI Agents / API

The default UI-based autocomplete requires a browser, which makes it unusable for AI agents and other API consumers. The plugin provides two server-side mechanisms to solve this.

### Geocoding Search Endpoint

The plugin registers a `GET /api/geocoding-plugin/search` endpoint that geocodes addresses server-side. It is authenticated by default (requires a logged-in user), and supports a custom access function:

```ts
plugins: [
payloadGeocodingPlugin({
googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY!,
// Optional: customize who can access the endpoint
geocodingEndpoint: {
access: ({ req }) => Boolean(req.user),
},
}),
]
```

An agent can then search for locations and use the results to populate fields:

```bash
# 1. Search for an address
GET /api/geocoding-plugin/search?q=Alexanderplatz,+Berlin

# Response:
{
"results": [
{
"formattedAddress": "Alexanderplatz, 10178 Berlin, Germany",
"placeId": "ChIJp1l4uWBRqEcR2SPNRBMhtAI",
"location": { "lat": 52.5219, "lng": 13.4132 },
"addressComponents": [...],
"types": [...]
}
]
}

# 2. Use the result to create/update a document
POST /api/pages
{
"title": "My Page",
"location": [13.4132, 52.5219],
"location_googlePlacesData": { ... }
}
```

### Server-Side Address Geocoding (beforeChange Hook)

Every `geocodingField` automatically includes a hidden `{fieldName}_address` text field. When an address string is submitted via the API, a `beforeChange` hook geocodes it server-side and populates the point and geodata fields.

An agent can simply submit an address string — the coordinates and geodata are resolved automatically:

```bash
POST /api/pages
{
"title": "My Page",
"location_address": "Alexanderplatz, Berlin"
}
```

The hook geocodes the address, sets the `location` point field to `[lng, lat]`, populates `location_googlePlacesData` with the full geocoding result, and clears `location_address` (it is not persisted).

## About this plugin

This plugin uses the [react-google-places-autocomplete](https://www.npmjs.com/package/react-google-places-autocomplete) library to provide a Select/Search input for finding an address. The result of the Google Places API request is stored in a JSON field and the coordinates are stored in a Point Field.
Expand Down
3 changes: 2 additions & 1 deletion geocoding/dev/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -370,4 +370,5 @@ $RECYCLE.BIN/
/media
*.db
tsconfig.tsbuildinfo
/dist
/dist
src/test/databaseAdapter.ts
16 changes: 11 additions & 5 deletions geocoding/dev/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "payload-plugin-test-app",
"description": "A test app for the plugin",
"name": "payload-geocoding-plugin-test-app",
"description": "A test app for the geocoding plugin",
"version": "0.0.1",
"license": "MIT",
"type": "module",
Expand All @@ -12,14 +12,19 @@
"start": "cross-env NODE_OPTIONS=--no-deprecation next start",
"format": "prettier --write src",
"payload": "payload",
"generate:types": "payload generate:types",
"generate:types": "cross-env PAYLOAD_DATABASE=sqlite payload generate:types",
"generate:schema": "payload-graphql generate:schema",
"generate:importmap": "payload generate:importmap"
"generate:importmap": "payload generate:importmap",
"test": "pnpm test:sqlite",
"test:sqlite": "cross-env PAYLOAD_DATABASE=sqlite vitest run",
"test:watch": "vitest watch"
},
"dependencies": {
"@jhb.software/payload-geocoding-plugin": "workspace:*",
"@payloadcms/db-mongodb": "^3.79.0",
"@payloadcms/db-sqlite": "^3.79.0",
"@payloadcms/next": "^3.79.0",
"@payloadcms/richtext-lexical": "3.79.0",
"@payloadcms/ui": "^3.79.0",
"next": "15.4.11",
"payload": "^3.79.0",
Expand All @@ -30,6 +35,7 @@
"copyfiles": "^2.4.1",
"cross-env": "^10.1.0",
"dotenv": "^17.3.1",
"typescript": "5.9.3"
"vite": "^8.0.0",
"vitest": "^4.1.0"
}
}
30 changes: 0 additions & 30 deletions geocoding/dev/plugin.spec.ts

This file was deleted.

Loading