Skip to content
Sign in Get the free theme
Menu
Developer docs menu

Features REST route

Applies to Companion 0.6.0 Updated 30 October 2026 View as Markdown

LanternWP Companion's features (quick view, product badges, bot protection and the rest) are read and saved through one REST route, lanternwp/v1/features, part of the public API. It is what Companion's own Features screen (Appearance → LanternWP → Features) uses, so a script, a deployment tool or another plugin can set a store's features the same way. The names of the features, their groups and their fields come from the route itself; never hard-code a list.

Every request needs a user who can manage WooCommerce (manage_woocommerce, which shop managers have). Without one, the route answers 401 to a visitor who is not signed in and 403 to one who is.

Read the features

GET /wp-json/lanternwp/v1/features
GET /wp-json/lanternwp/v1/features?details=product-badges

The answer has the groups in their order and every feature. details names the feature whose settings you show: only its fields come with their notes, which can take queries of the store's products; without it, a field that has notes says null.

{
  "groups": [
    { "id": "cards", "label": "Product cards", "description": "On every product card: the catalog, search and related products.", "features": ["quick-view", "product-swatches", "hover-image", "product-badges"] }
  ],
  "features": [
    {
      "id": "product-badges",
      "group": "cards",
      "name": "Product badges",
      "description": "Bestseller and New badges on product cards and the product page.",
      "handbook": "https://lanternwp.com/docs/product-badges",
      "switch": { "on": true, "default": true },
      "states": [{ "kind": "on", "label": "On", "text": "", "url": "", "link": "" }],
      "needsSetup": false,
      "restore": false,
      "place": null,
      "details": true,
      "fields": [
        { "id": "new", "type": "toggle", "label": "Mark recently published products as New", "help": "", "default": false, "value": false, "fieldset": "New badge", "when": null, "notes": ["Now on Linen Shirt and 3 more."] },
        { "id": "new-days", "type": "number", "label": "Days", "help": "…", "default": 30, "value": 30, "min": 1, "max": 9999, "fieldset": "New badge", "when": "new", "notes": [] }
      ],
      "links": [
        { "title": "On each product", "text": "Show, Hide or Automatic for each badge, in Product data → General.", "url": "…", "label": "Products" }
      ]
    }
  ]
}
Key What it is
switch The feature's switch, or null for a feature without one (the contact form, which is on where its block stands)
states What the feature's state line says: on, off, setup (it needs something before it can work, with a link to where that is set) or removed (the store removed its block from the templates named)
needsSetup Whether a state is setup or removed
restore Whether the feature's block can be put back in templates (see below)
place Where the feature is set further, such as Products → Product sets: label, and url or null when that place has no address of its own (a product's tab); null for none
details Whether the Features screen has details for the feature: it has fields or links
fields The feature's settings beyond its switch, in the order they show. type is toggle, number (with min and max), select (with options, each value and label), text or secret. when names a toggle of the same feature that shows the field while it is on; fieldset is the label of the fields shown together; notes says what the saved value does in the store now, such as the products a badge rule marks: a list for the feature details names, an empty list for a field without notes, null otherwise
links What the feature uses that is set elsewhere, as it is now, with a link there: title, text (such as On), url and the link's label. Back-in-stock emails' double opt-in is the confirmation email in WooCommerce → Settings → Emails, so it is a link, not a field

A secret field, such as the Turnstile secret key, never comes back: its value is always empty and hasValue says whether one is saved.

Save

One request saves switches and fields, as the screen's Save button does:

POST /wp-json/lanternwp/v1/features
{
  "switches": { "quick-view": true, "product-badges": true },
  "fields": { "product-badges": { "new": true, "new-days": 14 } },
  "details": "product-badges"
}
  • switches maps feature ids to true or false; fields maps feature ids to their fields' new values by field id.
  • What the request leaves out stays as it is. Send a secret only to change it; an empty text or secret clears it.
  • details is as in GET: the answer's fields of that feature come with their notes.
  • A switch or field the store does not have refuses the whole request with 400 and saves nothing.
  • Every value its field accepts is saved. The others are not, and errors says why, by <feature>.<field>, in the order the fields show: a number out of its range, a value not among a select's options, a Turnstile secret key Cloudflare does not accept (asked before it is saved; while Cloudflare cannot be reached, the key is saved).

The answer is 200 with errors and the features as saved, in the shape GET gives:

{
  "errors": { "bot-protection.secret-key": "Cloudflare does not accept this secret key. Copy it again from your Turnstile widget." },
  "groups": [],
  "features": []
}

errors is {} when everything was saved.

Put a block back in templates

A feature whose block Block Hooks place (quick view, product badges, swatches and the others) shows removed while the store has removed its block from a saved template. This puts it back where it was removed, and leaves the rest of those templates as they are:

POST /wp-json/lanternwp/v1/features/<feature>/restore

It also needs a user who can edit the theme's templates (edit_theme_options). The answer has the titles of the templates that have the block again (restored), those that could not be saved (failed) and the features after it, as GET gives them (send details as in GET for their notes). A feature without a block answers 404.

From PHP

In a plugin, the same request without HTTP:

$request = new WP_REST_Request( 'POST', '/lanternwp/v1/features' );
$request->set_header( 'content-type', 'application/json' );
$request->set_body( wp_json_encode( array( 'switches' => array( 'quick-view' => true ) ) ) );
$response = rest_do_request( $request );

It runs as the current user, so it needs one who can manage WooCommerce.