Screens API Reference
The NativePress Screens API delivers fully-composed home screen layouts from WordPress to your Expo React Native app. Each screen is a named configuration containing an ordered list of blocks — sections of posts drawn from a WordPress category, rendered using a specific layout type (carousel, list, or hero).
Screens are configured visually in WP Admin → NativePress → App Screens Builder. The API reflects exactly what is saved there: block order, enabled/disabled state, post counts, and category assignments. No code changes are needed in the app when a screen is reconfigured in the admin.
Base URL — all endpoints are relative to your WordPress installation.
Set WP_BASE_URL in constants/config.ts to your site root.
The {slug} segment matches the screen name you configure in the Screens Builder —
for example home, discover, or trending.
Endpoints
GET /screens/{slug}
Returns the full screen object, including all enabled blocks and their resolved post objects. Use this as the primary data source for rendering a dynamic screen in your app.
Example: GET /wp-json/nativepress/v1/screens/home
{
"slug": "home",
"label": "Home",
"blocks": [
{
"id": "1773330986098",
"type": "carousel",
"label": "Featured",
"category_id": 48,
"category_name": "Featured",
"post_count": 10,
"posts": [
{
"id": 12444,
"title": "Love me tender, this song make you miss someone?",
"slug": "love-me-tender-this-song-make-you-miss-someone",
"date": "2026-03-12T05:12:07+00:00",
"modified": "2026-03-12T05:16:00+00:00",
"excerpt": "",
"link": "https://toniai.com/featured/love-me-tender-this-song-make-you-miss-someone/",
"author": {
"id": 1,
"display_name": "Toni",
"avatar": "https://secure.gravatar.com/avatar/ae63c0e...?s=96&d=mm&r=g"
},
"categories": [
{ "id": 48, "name": "Featured", "slug": "featured" }
],
"featured_image": {
"thumbnail": "https://toniai.com/wp-content/uploads/2025/02/img_3447-1-150x150.png",
"medium": "https://toniai.com/wp-content/uploads/2025/02/img_3447-1-138x300.png",
"large": "https://toniai.com/wp-content/uploads/2025/02/img_3447-1-473x1024.png",
"full": "https://toniai.com/wp-content/uploads/2025/02/img_3447-1.png",
"alt": ""
},
"show_featured_image": true
}
]
},
{
"id": "1773333068082",
"type": "hero",
"label": "Hero",
"category_id": 36,
"category_name": "Entertainment",
"post_count": 1,
"posts": [
{
"id": 10307,
"title": "18 Highest-Rated TV Seasons on IMDb",
"slug": "18-highest-rated-tv-seasons-on-imdb",
"date": "2026-03-12T04:52:56+00:00",
"modified": "2026-03-12T05:16:00+00:00",
"excerpt": "Television seasons that have received high ratings...",
"link": "https://toniai.com/entertainment/18-highest-rated-tv-seasons-on-imdb/",
"author": {
"id": 1,
"display_name": "Toni",
"avatar": "https://secure.gravatar.com/avatar/ae63c0e...?s=96&d=mm&r=g"
},
"categories": [
{ "id": 36, "name": "Entertainment", "slug": "entertainment" }
],
"featured_image": {
"thumbnail": "https://toniai.com/wp-content/uploads/...-150x150.png",
"medium": "https://toniai.com/wp-content/uploads/...-300x168.png",
"large": "https://toniai.com/wp-content/uploads/...-1024x574.png",
"full": "https://toniai.com/wp-content/uploads/....png",
"alt": ""
},
"show_featured_image": true
}
]
}
]
}
Append ?structure_only=1 to receive block metadata without post data.
Useful for prefetching layout before content loads.
Example: GET /wp-json/nativepress/v1/screens/home?structure_only=1
{
"slug": "home",
"label": "Home",
"blocks": [
{
"id": "1773330986098",
"type": "carousel",
"label": "Featured",
"category_id": 48,
"category_name": "Featured",
"post_count": 10
},
{
"id": "1773333068082",
"type": "hero",
"label": "Hero",
"category_id": 36,
"category_name": "Entertainment",
"post_count": 1
}
]
}
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| slug | string | — | Required. URL path segment identifying the screen (e.g. home). |
| structure_only | 0 | 1 | 0 |
When 1, returns block metadata only. The posts array is omitted from every block. |
Search Endpoint
Full-text search across posts and categories. Supports relevance-ranked results, match snippets, and a lightweight suggest mode for autocomplete.
Example: GET /wp-json/nativepress/v1/search?q=love&mode=full
{
"query": "love",
"total": 24,
"pages": 3,
"results": {
"posts": [
{
"id": 12909,
"title": "Love me tender, this song make you miss someone?",
"slug": "love-me-tender-this-song-make-you-miss-someone",
"date": "2026-03-12T05:12:07+00:00",
"modified": "2026-03-12T05:12:07+00:00",
"excerpt": "A short excerpt about the post content.",
"snippet": "...this **love** song will make you miss someone you left behind...",
"link": "https://toniai.com/featured/love-me-tender/",
"author": {
"id": 1,
"display_name": "Toni",
"avatar": "https://secure.gravatar.com/avatar/..."
},
"categories": [
{ "id": 48, "name": "Featured", "slug": "featured" }
],
"featured_image": {
"thumbnail": "https://toniai.com/wp-content/uploads/.../img-150x150.png",
"medium": "https://toniai.com/wp-content/uploads/.../img-300x300.png",
"large": "https://toniai.com/wp-content/uploads/.../img-1024x1024.png",
"full": "https://toniai.com/wp-content/uploads/.../img.png",
"alt": ""
},
"show_featured_image": true,
"relevance": "title"
}
],
"categories": [
{
"id": 48,
"name": "Featured",
"slug": "featured",
"description": "",
"count": 120
}
]
}
}
Example: GET /wp-json/nativepress/v1/search?q=love&mode=suggest
{
"query": "love",
"results": {
"posts": [
{
"id": 12909,
"title": "Love me tender, this song make you miss someone?",
"thumbnail": "https://toniai.com/wp-content/uploads/.../img-300x300.png"
},
{
"id": 12890,
"title": "Loving the quiet moments",
"thumbnail": null
}
],
"categories": [
{ "id": 48, "name": "Featured" }
]
}
}
Example: GET /wp-json/nativepress/v1/search?q=a — query under 2 chars returns HTTP 400
{
"code": "search_query_too_short",
"message": "Search query must be at least 2 characters.",
"data": {
"status": 400
}
}
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| q | string | — | Required. Search query. Minimum 2 characters. Returns HTTP 400 if shorter. |
| mode | string | full |
full — ranked results with snippets and full post shape. suggest — minimal payload (id, title, thumbnail) for live autocomplete. Cached for 2 min. |
| per_page | integer | 10 |
Results per page. Maximum 50. |
| page | integer | 1 |
Page number for pagination. Use with total and pages in the response. |
Response fields (mode=full)
| Field | Type | Description |
|---|---|---|
| query | string | The search query that was used. |
| total | integer | Total number of matching posts. |
| pages | integer | Total number of pages. |
| results.posts[].snippet | string|null | ±80 character context around the match. The matched term is wrapped in **bold** Markdown. |
| results.posts[].relevance | string | title — matched in post title (ranked first). content — matched in post body. |
| results.categories | array | Categories whose names match the query. |
JSON Schema
All field types and descriptions for the three objects returned by the Screens API.
Screen object
| Field | Type | Description |
|---|---|---|
| slug | string | Screen identifier matching the URL slug (e.g. "home"). |
| label | string | Human-readable screen name displayed in the app header. |
| blocks | Block[] | Ordered array of enabled blocks as configured in the Screens Builder. |
Block object
| Field | Type | Description |
|---|---|---|
| id | string | Unique block identifier (timestamp-based string). Stable across renames. |
| type | "carousel" | "list" | "hero" | Block layout type. Controls which component renders this block in the app. |
| label | string | Section heading shown above the block in the app. |
| category_id | number | WordPress category term ID. 0 means all categories. |
| category_name | string | Resolved category name. "All Posts" when category_id is 0. |
| post_count | number | Number of posts configured for this block (1–20). |
| posts | Post[] | Resolved post objects. Omitted when structure_only=1 is passed. |
Post object
| Field | Type | Description |
|---|---|---|
| id | number | WordPress post ID. |
| title | string | Post title (decoded HTML entities). |
| slug | string | URL-friendly post slug. |
| date | string | Publish date in ISO 8601 format. |
| modified | string | Last modified date in ISO 8601 format. |
| excerpt | string | Post excerpt. May be empty string if no excerpt is set. |
| link | string | Full canonical permalink on the WordPress site. |
| author.id | number | Author user ID. |
| author.display_name | string | Author display name. |
| author.avatar | string | Gravatar URL at 96px. Always present (falls back to default Gravatar). |
| categories | {id, name, slug}[] | All categories this post belongs to. |
| featured_image | object | null | Image URLs for four sizes (thumbnail, medium, large, full) plus alt text. null if no featured image is set. |
| show_featured_image | boolean | Whether the app should display the featured image in the post detail view. |
Block Types
Each block has a type field that tells the app which layout component to render.
The three types cover the most common news/blog feed patterns.
Carousel
Horizontal scrollable card strip. Ideal for browsable topic categories or featured content.
List
Vertical post cards with a section header. Standard chronological feed layout.
Hero
Single large feature card occupying the full width. Best for a highlighted or pinned article.
Dispatching block types — in the app, components/BlockRenderer.tsx
switches on the block.type value and renders the appropriate component.
Adding a new block type requires adding a new case to that switch and a corresponding component.
TypeScript Types
Drop this file into types/screens.ts in your Expo project. All API service
functions and hooks reference these interfaces.
export type BlockType = 'carousel' | 'list' | 'hero';
export interface PostAuthor {
id: number;
display_name: string;
avatar: string;
}
export interface PostCategory {
id: number;
name: string;
slug: string;
}
export interface FeaturedImage {
thumbnail: string;
medium: string;
large: string;
full: string;
alt: string;
}
export interface ScreenPost {
id: number;
title: string;
slug: string;
date: string;
modified: string;
excerpt: string;
link: string;
author: PostAuthor;
categories: PostCategory[];
featured_image: FeaturedImage | null;
show_featured_image: boolean;
}
export interface ScreenBlock {
id: string;
type: BlockType;
label: string;
category_id: number;
category_name: string;
post_count: number;
posts?: ScreenPost[]; // omitted when structure_only=1
}
export interface Screen {
slug: string;
label: string;
blocks: ScreenBlock[];
}
API Service
Add getScreen() to your services/api.ts file. It fetches a screen
by slug and returns a typed Screen promise. Errors are thrown so callers can
handle them with try/catch or via the hook below.
import { WP_BASE_URL } from '../constants/config';
import { Screen } from '../types/screens';
export async function getScreen(slug: string): Promise<Screen> {
const response = await fetch(`${WP_BASE_URL}/wp-json/nativepress/v1/screens/${slug}`);
if (!response.ok) {
throw new Error(`Screen fetch failed: ${response.status}`);
}
return response.json();
}
WP_BASE_URL is the only value buyers need to change — set it to your
WordPress site root (e.g. https://yoursite.com) in constants/config.ts.
No trailing slash.
useScreen() Hook
A React hook that wraps getScreen() with loading, error, and refresh state.
Place this in hooks/useScreen.ts and call it from any screen component.
The refresh() function re-fetches without remounting the component.
import { useState, useEffect } from 'react';
import { Screen, ScreenBlock } from '../types/screens';
import { getScreen } from '../services/api';
interface UseScreenResult {
screen: Screen | null;
blocks: ScreenBlock[];
loading: boolean;
error: string | null;
refresh: () => void;
}
export function useScreen(slug: string): UseScreenResult {
const [screen, setScreen] = useState<Screen | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [tick, setTick] = useState(0);
useEffect(() => {
let cancelled = false;
setLoading(true);
setError(null);
getScreen(slug)
.then((data) => { if (!cancelled) setScreen(data); })
.catch((err) => { if (!cancelled) setError(err.message ?? 'Failed to load screen'); })
.finally(() => { if (!cancelled) setLoading(false); });
return () => { cancelled = true; };
}, [slug, tick]);
return {
screen,
blocks: screen?.blocks ?? [],
loading,
error,
refresh: () => setTick((t) => t + 1),
};
}
Return values
| Property | Type | Description |
|---|---|---|
| screen | Screen | null | The full screen object once loaded; null while loading or on error. |
| blocks | ScreenBlock[] | Convenience shorthand for screen.blocks. Empty array before load. |
| loading | boolean | true while the request is in flight (including on refresh). |
| error | string | null | Error message string if the request failed; otherwise null. |
| refresh | () => void | Call to re-fetch the screen. Triggers loading: true again. |
Quick Reference
Everything you need at a glance.
| Task | Where / What | |
|---|---|---|
| Configure screens & blocks | WP Admin → NativePress → App Screens Builder | |
| View endpoint URLs | Screens Builder → select screen tab → "API Endpoints" box | |
| Screen endpoint | GET /wp-json/nativepress/v1/screens/{slug} | |
| Structure-only endpoint | GET /wp-json/nativepress/v1/screens/{slug}?structure_only=1 | |
| TypeScript types | types/screens.ts | |
| API function | services/api.ts → getScreen(slug) | |
| Data hook | hooks/useScreen.ts → useScreen(slug) | |
| Block dispatch | components/BlockRenderer.tsx | |
| Full screen component | screens/DynamicScreen.tsx | |
| WP option key | nativepress_screens | |
| GET | /search | Search posts and categories. Params: q (required), mode (full|suggest), per_page, page |