---
title: Fields
description: MediaPress Fields provides a block-editor integrated approach for managing custom fields, including registration of post meta and custom taxonomies.
url: https://developers.wpengine.com/docs/newsroom/mediapress/fields/
image: https://developers.wpengine.com/og/docs/newsroom/mediapress/fields.png
---

# Fields

MediaPress Fields provides a block-editor integrated approach for managing custom fields, including registration of post meta and custom taxonomies.

Fields are registered via a JSON file which can be used to configure both fields and field groups. They can then be accessed in a dedicated view within the block editor on supported post types.

The fields view can be opened by navigating to the Options menu in the top right of the block editor and selecting “MediaPress Fields” in the dropdown.

The following field types are supported:

- Attributes/Meta

  - text
  - textarea
  - toggle
  - select
  - multi_select
  - checkbox
  - tag
  - image
  - number
  - radio

- Taxonomies

  - checkbox
  - select
  - multi_select
  - tag
  - radio

## Additional Configuration

Fields must be activated via the “MediaPress” settings page.

Out of the box, it contains a sample config for testing purposes. You should replace this with your own JSON config file, and point to this file using the appropriate filter.

The exact format of the config file is documented in the plugin at `/wp-content/plugins/mediapress-core/packages/fields/config-schema.json` and may be accessed from the filesystem or web browser. `example-config.json` in the same directory shows how this can be implemented.

### Registering a field via config

A field is a piece of UI which can be linked to a particular data source to display and edit values.

The data source could be an existing value, or you can configure the field to register a new value.

```json
{
  "fields": [
    {
      "name": "attribute_text_field", // the name of the field, should be unique
      "type": "text", // the type of field to render
      "label": "Attribute Text Field", // the user-friendly name of the field
      "description": "A text field linked to a post attribute", // an optional description for the field
      "source": {
        // the data source that the field is linked to
        "type": "attribute", // supported source types are 'postMeta', 'taxonomy', 'attribute' and 'setting'
        "key": "post_title", // the name of the meta/taxonomy/setting
        "registerFor": ["post", "page"] // (optional) whether to register the source if it doesn't exist.
        // if source.key is 'attribute' - this is not applicable
        // if source.key is 'postMeta' - the name of the post types to register the meta for
        // if source.key is 'taxonomy' - the name of the post type(s) to register the taxonomies for
        // if source.key is 'setting' - the name of the settings group to register the setting for
      },
      "options": [] // (optional) used for certain field-types to define a list of options to choose from, or can be set to either "user" or "taxonomy-{slug}" to enable user or term autocomplete
    }
  ]
}
```

### Registering a field group via config

A field group is a representation of one or more fields to be rendered in a specific location, for example in post block editor or on a settings page.

Fields can be assigned to multiple field groups, and multiple field groups can be rendered in a single location.

> **Note**
>
> If a field type uses a `source` which is not available in the context it is being rendered, it will not be displayed. For example, if a field uses `postMeta`, you cannot render this on a settings page.

```json
{
  "fieldGroups": [
    {
      "name": "attributes", // the name of the field group, should be unique
      "label": "Attributes", // the user-friendly name of the field group
      "fields": ["attribute_text_field", "attribute_text_area"], // which fields to include in the field group
      "context": {
        // the location that the field group will be rendered
        "type": "postType", // supported types are 'postType' and 'settingsPage'
        "key": "post" // the specific instance of the postType or settingsPage where the field group will be rendered.
        // if context.type is 'postType' - the name of the post type, the field group will display in the fields panel within the block editor
        // if context.type is 'settingsPage' - the name of the settings page, which must be a MediaPress settings page registered by this config
        // key can support either a string, or an array of strings, in order to render a field group in multiple contexts
        // omitting the key will render the field group in all contexts (all postTypes or all settingsPages)
      }
    }
  ]
}
```

### Registering a settings page via config

A settings page is a page in the WordPress admin area that renders using our Gutenberg-based fields UI.

Settings pages can be top-level, or have a parent, which will cause them to render as sub-menu pages.

> **Caution**
>
> If configuring a sub-menu page, you must ensure the parent comes before it in the config.

```json
{
  "settingsPages": [
    {
      "name": "site-settings", // the name of the settings page, used to register the page, and also within field group contexts
      "label": "Site Settings" // the user-friendly name of the settings page
    },
    {
      "name": "more-settings",
      "label": "More Settings",
      "parent": "site-settings" // (optional) the name of the parent settings page, which will cause this page to render as a sub-menu page
    }
  ]
}
```

## Filters/Actions

### JavaScript

#### Slotfills

Slotfills allow you to render custom content in various locations within the plugin, for example:

```js
import { Fill } from '@wordpress/components';
import domReady from '@wordpress/dom-ready';
import { registerPlugin } from '@wordpress/plugins';


domReady(() => {
  registerPlugin('my-plugin-slotfills', {
    render: () => (
      <Fill name="mediapress_fields_fieldgroup_taxonomies_before">
        <div>
          This will render before the fields in the taxonomies field group
        </div>
      </Fill>
    ),
  });
});
```

##### `mediapress_fields_fieldgroup_{name}_before`

Allows rendering of content in the fields panel before a specific field group, using the group name defined in the config.

##### `mediapress_fields_fieldgroup_{name}_after`

Allows rendering of content in the fields panel after a specific field group, using the group name defined in the config.

#### Filters

##### `mediaPress.fields.editedMetadata`

Filters the metadata returned by the `getEditedMetadata` selector before it is used by the Save Metadata button.

This is useful when fields are linked to an external data store (e.g., Yoast SEO) whose changes are not tracked in the WordPress core-data entity store. The filter allows you to inject additional meta values so they are included in the save payload.

See [`saveMetadata`](https://developers.wpengine.com/docs/newsroom/mediapress/fields/#savemetadata) for which keys the server accepts.

**Parameters**

| Name           | Type   | Description                                                           |
| -------------- | ------ | --------------------------------------------------------------------- |
| editedMetadata | Object | The metadata object containing `meta`, `taxonomies`, and `attributes` |
| fields         | Array  | The field definitions for the currently active field group            |

**Return**

| Type   | Description                                 |
| ------ | ------------------------------------------- |
| Object | The (potentially augmented) edited metadata |

**Usage**

<!-- spell-checker:ignore wpseo,metadesc -->

```js
import { select } from '@wordpress/data';
import { addFilter } from '@wordpress/hooks';


addFilter(
  'mediaPress.fields.editedMetadata',
  'my-plugin/add-yoast-meta',
  (editedMetadata, fields) => {
    const yoastStore = select('yoast-seo/editor');


    if (!yoastStore) {
      return editedMetadata;
    }


    const snippetData = yoastStore.getSnippetEditorData();


    return {
      ...editedMetadata,
      meta: {
        ...editedMetadata.meta,
        _yoast_wpseo_title: snippetData.title,
        _yoast_wpseo_metadesc: snippetData.description,
      },
    };
  },
);
```

##### `mediaPress.fields.fieldComponent`

Allows for augmentation or replacement of a rendered field component.

This is useful if you want to render additional content, customize any of the field props, perform side-effects or render an entirely custom component.

**Parameters**

| Name              | Type        | Description                                                                           |
| ----------------- | ----------- | ------------------------------------------------------------------------------------- |
| OriginalComponent | JSX.Element | The rendered component to be replaced                                                 |
| Object            | args        | Arguments for the filter                                                              |
| string            | args.source | The field source from the schema, e.g: ‘postMeta’, ‘attribute’, ‘taxonomy’, ‘setting’ |
| string            | args.type   | The field type from the schema, e.g: ‘text’, ‘select’                                 |
| string            | args.name   | The field name from the schema                                                        |

**Usage**

```js
addFilter(
  'mediaPress.fields.fieldComponent',
  'my-plugin/wrap-field',
  (OriginalComponent, { name }) => {
    if ('my-field' !== name) {
      return OriginalComponent;
    }


    return <div className="wrapper">{OriginalComponent}</div>;
  },
);
```

### PHP

#### Filters

##### `mediapress_fields_config_path`

Allows the adjustment of the fields config JSON file location

**Parameters**

| Name | Type   | Description                      |
| ---- | ------ | -------------------------------- |
| path | string | The path to the config.json file |

**Usage**

```php
add_filter( 'mediapress_fields_config_path', 'my_plugin_fields_config_path' );
function my_plugin_fields_config_path( string $path ): string {
  $path = __DIR__ . '/config/my-fields-config.json';
  return $path;
}
```

##### `mediapress_fields_config`

Filters the config immediately after the JSON file is parsed. The outcome of this value is used to register any meta/taxonomies/settings pages as well as defining fields and field groups.

**Parameters**

| Name   | Type  | Description              |
| ------ | ----- | ------------------------ |
| config | Array | The parsed fields config |

**Usage**

```php
/**
 * Render an additional settings page with a text field within it
 */
add_filter( 'mediapress_fields_config', 'adjust_config', 10, 1 );
function adjust_config( $config ) {
  $config['fields'][] = [
    'name'   => 'my_api_key',
    'type'   => 'text',
    'label'  => __( 'My API Key', 'my-plugin' ),
    'source' => [
      'type'        => 'setting',
      'key'         => 'my_api_key',
      'registerFor' => 'my-settings',
    ],
  ];


  $config['fieldGroups'][] = [
    'name'    => 'api_keys',
    'label'   => __( 'API Keys', 'my-plugin' ),
    'fields'  => [
      'my_api_key',
    ],
    'context' => [
      'type' => 'settingsPage',
      'key'  => 'my-settings',
    ],
  ];


  $config['settingsPages'][] = [
    'name'  => 'my-settings',
    'label' => __('My Settings Page', 'my-plugin')
  ]




  return $config;
}
```

##### `mediapress_fields_field_groups`

Filters the field groups at the point where they are used to determine which groups/fields to show in a specific context - for example on a specific post type or settings page.

This allows you to customize which fields are rendered for a user, but doesn’t adjust which fields are registered as meta, taxonomies or settings.

**Parameters**

| Name                   | Type  | Description                                                                          |
| ---------------------- | ----- | ------------------------------------------------------------------------------------ |
| field_groups_with_data | Array | The current field groups containing fields to be rendered                            |
| type                   | Array | The type of the current field group context, e.g: `postType`, `settingsPage`         |
| key                    | Array | The key of the current field group context, i.e: the post type or settings page slug |

**Usage**

```php
/**
 * Avoid rendering a certain field unless the current user can edit options
 */
add_filter( 'mediapress_fields_field_groups', 'hide_fields', 10, 3 );
function hide_fields( $field_groups_with_data, $type, $key ) {
  if ( current_user_can( 'manage_options' ) ) {
    return $field_groups_with_data;
  }


  if ( 'postType' !== $type || 'post' !== $key ) {
    return $field_groups_with_data;
  }


  foreach ( $field_groups_with_data as $index => $field_group ) {
    if ( isset( $field_group['name'] ) && 'my_field' === $field_group['name'] ) {
      unset( $field_groups_with_data[ $index ] );
    }
  }


  return array_values( $field_groups_with_data );
}
```

## Store

This package exposes a redux store named `mediapress/fields` with the following methods available:

### Actions

#### `saveMetadata`

Used to trigger a save of post metadata (attributes, post meta and taxonomies) independently from a regular post save. The post that is saved is always the one in the request URL.

Attributes, taxonomies and REST-registered meta are saved by WordPress core’s REST posts controller for the post type, as the current user, so core decides what that user may change. For example, publishing needs the publish capability, changing the author needs `edit_others_posts`, and assigning terms needs the taxonomy’s `assign_terms` capability. A refusal from core is returned as it is.

- **Attributes** use `wp_insert_post()` column names: `post_title`, `post_excerpt`, `post_name`, `post_status`, `post_date`, `post_date_gmt`, `post_password`, `post_author`, `post_parent`, `menu_order`, `comment_status` and `ping_status`. They are translated to core’s REST field names. Any other post column is refused with a `400`, for example `ID`, `post_type` and `post_content`. A key that is not a post column, such as the REST spelling `excerpt`, or `meta_input` and `tax_input` (use `meta` and `taxonomies` instead), is ignored and the rest of the group still saves: send `post_excerpt`, not `excerpt`. An attribute the post type does not support is refused with a `400`.
- **Taxonomies** are keyed by taxonomy name. A taxonomy that is not exposed in REST for the post type, or whose `rest_base` is the name of another field such as `meta` or `author`, is refused with a `400`.
- **Meta** keys registered with `show_in_rest` for the post type are written by core, including the key’s `auth_callback` and the `edit_post_meta` capability. To save your own meta key through this route, register it with `show_in_rest` for the post type, and note that the post type needs `custom-fields` support for core to expose `meta` at all. Any other key is refused with a `400`. The route used to accept any meta key, so this is narrower than before, with one compatibility exception below.
  - **Compatibility allowlist for three Yoast SEO keys.** This is not general Yoast support. Existing integrations send Yoast values as raw keys in the generic `meta` payload, and these three keys are allowed so that keeps working: `_yoast_wpseo_title`, `_yoast_wpseo_metadesc` and `_yoast_wpseo_focuskw`. They can be saved on any post type, including pages and custom post types where Yoast does not register them with `show_in_rest`, but only while Yoast is active. Each value must be a string (an empty string is a valid value and clears the field), or the request is refused with a `400`. Anyone who can edit the post can save them, the same as Yoast’s own rule for these keys. Every other Yoast key (for example canonical, robots or the social keys) is refused with a `400` like any other unregistered key, and there is no filter to add keys. This is a stopgap: Yoast and ACF as distinct field sources are planned to replace it.

Everything is checked before anything is saved, so a request with a refused key saves nothing. The values are saved in one update of the post, so after-save hooks such as `save_post` run once and see the new values, and the post gets one revision under core’s usual rules. A request with nothing to save (for example an empty `meta`) succeeds without changing the post. The response is core’s REST item for the post in the `edit` context, or empty when there was nothing to save.

**Parameters**

| Name               | Type   | Description                                                                                                                        |
| ------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| options            | Object | Options object                                                                                                                     |
| options.meta       | Object | Key/values of metadata to be saved.                                                                                                |
| options.taxonomies | Object | Key/values of taxonomies to be saved. Keys should be the actual taxonomy name (not rest base). Values should be arrays of integers |
| options.attributes | Object | Key/values of post attributes to be saved, using `wp_insert_post()` column names.                                                  |

**Usage**

```js
function myPluginSaveMetadata() {
  const yoastData = select('yoast-seo/editor').getSnippetEditorData();


  const meta = {
    _yoast_wpseo_title: yoastData.title,
    _yoast_wpseo_metadesc: yoastData.description,
  };


  const postEdits = select('core/editor').getPostEdits();


  const taxonomies = {
    ...(postEdits?.categories && { category: postEdits.categories }),
    ...(postEdits?.tags && { post_tag: postEdits.tags }),
  };


  dispatch.saveMetadata({ meta, taxonomies });
}
```

#### `openFieldGroup`

Opens the fields sidebar panel in the block editor and optionally navigates to a specific field group by name.

If no `groupName` is provided, the sidebar opens at whichever group is currently active.

**Parameters**

| Name      | Type   | Description                                           |
| --------- | ------ | ----------------------------------------------------- |
| groupName | string | (Optional) The name of the field group to navigate to |

**Usage**

```js
import { dispatch } from '@wordpress/data';


// Open the fields sidebar and navigate directly to the 'seo' field group
dispatch('mediapress/fields').openFieldGroup('seo');


// Open the fields sidebar without changing the active group
dispatch('mediapress/fields').openFieldGroup();
```

### Selectors

#### `getIsSavingMetadata`

Returns `true` if currently saving metadata.

#### `getActiveFieldGroup`

Returns the name of the currently active field group, or `null` if none is set.

**Return**

| Type         | Description                            |
| ------------ | -------------------------------------- |
| string\|null | The active field group name, or `null` |

**Usage**

```js
import { select } from '@wordpress/data';


const activeFieldGroup = select('mediapress/fields').getActiveFieldGroup();
```

#### `getEditedMetadata`

Returns only the meta, taxonomy, and attribute values that have been edited (i.e. differ from the last saved values) for a given set of field definitions. Used internally by the Save Metadata button and by the `mediaPress.fields.editedMetadata` filter.

**Parameters**

| Name   | Type  | Description                                        |
| ------ | ----- | -------------------------------------------------- |
| fields | Array | The field definitions to check for unsaved changes |

**Return**

| Type   | Description                                                                                |
| ------ | ------------------------------------------------------------------------------------------ |
| Object | Object with `meta`, `taxonomies`, and `attributes` keys containing only the changed values |

**Usage**

```js
import { select } from '@wordpress/data';


const { meta, taxonomies, attributes } =
  select('mediapress/fields').getEditedMetadata(fields);
```

## Was this helpful?

Thanks for the feedback!

```json
{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://developers.wpengine.com/#website","name":"WP Engine Product Documentation","url":"https://developers.wpengine.com/","description":"Resources for developing, deploying, and scaling on WP Engine.","inLanguage":"en-US","keywords":["API documentation","product documentation","headless WordPress","managed WordPress hosting"],"publisher":{"@id":"https://wpengine.com/#organization"}}]}
```
