JsonifyWP is a WordPress plugin that displays data from external JSON APIs on your site. You define endpoints in the admin (API URL, list and detail templates, detail page…) and place them anywhere with a shortcode. Rendering is done by plain PHP templates, which you can override from your theme.
- Admin screen to create, edit, duplicate and delete endpoints, with a Test connection button that previews the API response
- List and detail templates, chosen per endpoint — plain PHP files
- Theme overrides: put templates in your theme and they survive plugin updates
- Two modes: list with detail pages, or list only with server-side pagination
- Stable detail links using an ID field from the API (optional)
- Caching with fallback: API responses are cached, and if the API goes down the last valid response keeps being shown
- Field labels to rename JSON fields in the generic templates without touching code
- Shortcodes that work in post content, widgets and page builders
- Catalan and Spanish translations included
- WordPress 6.3 or later
- PHP 8.0 or later
- Download the latest release and upload the
jsonifywpfolder towp-content/plugins/. - Activate the plugin from the WordPress admin panel.
- Go to JsonifyWP in the admin sidebar to add and manage endpoints.
Updating: replace the jsonifywp folder. Database changes are applied automatically, no need to deactivate/reactivate.
| Field | Description |
|---|---|
| Title | Display name for this endpoint |
| Language | For organisational purposes (ca, es, en) — does not affect the API call |
| API Domain | Base domain prepended to relative URLs (e.g. https://api.example.com) |
| API URL | Full URL of the list endpoint — do not include page or limit params |
| List Template | List template file (see Templates) |
| Detail Template | Detail template file, or No detail page for list-only mode |
| Detail Page URL | Relative URL of the WordPress page containing [jsonifywp_detail] (detail mode only) |
| Detail API Field | JSON field in each list item that holds the detail API URL (detail mode only) |
| Item ID Field | Optional. JSON field with a unique, stable ID for each item (e.g. id). See Detail links |
| Field labels | Optional JSON field → display label overrides for the generic templates (see Field labels) |
Use Test connection next to the API URL field to call the endpoint and preview its response (detected fields and the first item) before saving. Click a detected field to add it to the field labels table.
Each list item links to a WordPress page that shows the item's details, fetched from a second API call.
Setup:
- Create a WordPress page (e.g.
/person/) and add[jsonifywp_detail]to its content. - Set Detail Page URL to that page's relative path (e.g.
/person/). - Set Detail API Field to the JSON key in each list item that contains the detail URL (e.g.
profile_url). Relative URLs get the API Domain prepended.
Flow: [jsonifywp id="1"] → list API call → each item links to /person/?jsonifywp_id=1&item=… → [jsonifywp_detail] finds the item in the list, calls its detail URL and renders it with the detail template.
The list API may return either a plain array of items or an object with an items array.
By default, detail links identify the item by its position in the list (item=3). If the API changes the order or adds items, an old link could show a different record.
Set Item ID Field to a field that uniquely identifies each item (e.g. id) and links become item=<id>, which keep pointing to the same record. Existing endpoints keep working by position until you set it.
Select No detail page as the detail template. The plugin appends ?page=N&limit=X to the API URL, and your API must return:
{
"total": 42,
"page": 1,
"limit": 10,
"items": ["Item A", "Item B", "..."]
}Pagination links are rendered server-side. Each endpoint uses its own query parameter (?jsonifywp_page_<id>=2), so several paginated lists can share a page. Old ?jsonifywp_page=2 links still work.
JsonifyWP → Settings
| Option | Description | Default |
|---|---|---|
| Items per page | Items requested per page for list-only endpoints, and per page in the members.php client-side paginator |
5 |
| API cache duration (minutes) | How long API responses are cached. 0 disables the cache |
15 |
There's also a Clear API cache button to force fresh data on the next page view.
- Responses are cached for the configured duration (WordPress transients — works with persistent object caches too).
- The last valid response of each URL is kept. If the API fails, visitors see that copy instead of an error.
- After a failure, the API isn't called again for one minute, so a down API doesn't slow down every page view.
- Technical error messages (HTTP status, missing template…) are only shown to administrators. Visitors see nothing in lists, and a generic message on detail pages.
List:
[jsonifywp id="1"]
Short alias (equivalent, works anywhere shortcodes do — content, widgets, Elementor…):
[jsonifywp-1]
Detail page:
[jsonifywp_detail]
Reads jsonifywp_id and item from the URL. You can also fix them: [jsonifywp_detail id="1" item="a1"].
The shortcode for each endpoint is shown in the endpoints table, with a copy button.
Templates are looked up in this order:
wp-content/themes/<child-theme>/jsonifywp/list/(or/detail/)wp-content/themes/<parent-theme>/jsonifywp/list/(or/detail/)wp-content/plugins/jsonifywp/templates/list/(or/detail/)
Any .php file in these folders appears in the endpoint editor (theme templates are marked (theme)). A theme file with the same name as a plugin template overrides it. Put your custom templates in the theme — files added to the plugin folder are lost when the plugin is updated.
Developers can change the search paths with the jsonifywp_template_dirs filter:
add_filter('jsonifywp_template_dirs', function ($dirs, $type) {
array_unshift($dirs, WP_CONTENT_DIR . '/jsonifywp-templates/' . $type . '/');
return $dirs;
}, 10, 2);| Variable | Type | Contents |
|---|---|---|
$json |
array |
Decoded JSON response from the API (list response in list templates, detail response in detail templates) |
$item_obj |
object |
Endpoint configuration row (title, api_url, detail_page_url, detail_api_field, item_id_field, …) |
$type_id |
int |
ID of the current endpoint |
$list_item |
array |
Detail templates only: the item from the list that was clicked |
| Function | Returns |
|---|---|
jsonifywp_get_list_items($json) |
The items array, whether the API returns a plain array or { items: [...] } |
jsonifywp_get_detail_url($item_obj, $index, $item) |
Detail page URL for an item ('' if there's no detail page). Escape it with esc_url() |
jsonifywp_pagination($json, $type_id) |
Server-side pagination links (<ul class="page-numbers">) for list-only responses, '' if one page |
jsonifywp_get_field_labels($item_obj) |
[json_field => label] array from the endpoint's Field labels |
Minimal list template:
<?php foreach (jsonifywp_get_list_items($json) as $index => $item): ?>
<h3><?php echo esc_html($item['name'] ?? ''); ?></h3>
<?php if ($url = jsonifywp_get_detail_url($item_obj, $index, $item)): ?>
<a href="<?php echo esc_url($url); ?>">View detail</a>
<?php endif; ?>
<?php endforeach; ?>
<?php echo jsonifywp_pagination($json, $type_id); ?>The generic templates (default.php, default_detail.php) render every JSON field as key: value. Define Field labels in the endpoint editor to rename fields without editing the template; unmapped fields show the raw key.
Custom templates (members.php, publications.php, employee_detail.php or your own) hardcode their fields and labels to match a theme's markup. To use the configured labels in your own template, call jsonifywp_get_field_labels($item_obj).
Enqueue scripts from the template with wp_enqueue_script(). Use an absolute URL — JSONIFYWP_URL for files shipped with the plugin, or get_stylesheet_directory_uri() for files in your theme — and pass data through data-* attributes on a wrapper element, so several lists on the same page don't share state. See members.php and assets/js/members.js for an example.
| Template | Description |
|---|---|
list/default.php |
Generic list, every field as label: value. Supports both modes and paginates list-only endpoints |
list/members.php |
People directory with client-side pagination (all items in one API call). Expects fullname, office, direct_phone, extension |
list/publications.php |
Publications list for list-only mode (items is an array of strings), with server-side pagination |
detail/default_detail.php |
Generic detail, every field as label: value |
detail/employee_detail.php |
Employee profile: fullname, contact data, research_lines, research_description, publications. Allows basic HTML in text fields |
members.php, publications.php and employee_detail.php use the markup of a specific theme (classes jws_*); copy them to your theme and adapt them as needed.
Endpoints are created by users with the manage_options capability (site admins), and the plugin fetches whatever API URL and API Domain they configure, server-side. This is by design, but it means:
- Only grant admin access to people you trust to configure endpoints responsibly.
- Don't let endpoint URLs be influenced by untrusted input.
- Template files run as PHP with full site privileges — only install templates from a source you trust.
- Data from the API is escaped by the included templates; do the same in yours (
esc_html(),esc_url(),wp_kses()).
To report a vulnerability, see SECURITY.md.
Deleting the plugin from the admin removes its database table, settings and cached API responses. Templates in your theme are not touched.
GPL v2 or later. See LICENSE for details.
Developed by Oscar Periche · Metalinked