Skip to content

docs: investigate and document custom fields (meta) support#426

Open
Copilot wants to merge 4 commits intomainfrom
copilot/investigate-custom-fields-support
Open

docs: investigate and document custom fields (meta) support#426
Copilot wants to merge 4 commits intomainfrom
copilot/investigate-custom-fields-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 7, 2026

WordPress exposes custom fields via an opt-in meta property on posts, pages, comments, users, and media. The library already models this as JsonElement? on all relevant types; what was missing was documentation, correct code examples, and integration tests.

Changes

  • New docs/v3/entities/customFields.md — dedicated custom fields reference covering:

    • Why meta is empty by default and how to opt in server-side (register_post_meta, register_rest_field, ACF)
    • Supported models (Post, Page, Comment, MediaItem, PostRevision, User)
    • Reading via JsonElement? (raw access + strongly-typed deserialization)
    • Writing via JsonSerializer.SerializeToElement()
    • Handling top-level REST fields (e.g. ACF's acf key) via CustomRequest
  • mkdocs.yml — registered the new page in v3 navigation

  • Bug fix in docs/v2/entities/posts.md and docs/v3/entities/posts.md — both had Meta = new Dictionary<string, string> { ... } which doesn't compile; Meta is JsonElement?. Corrected to:

Post post = new Post
{
    Id = 123,
    Meta = JsonSerializer.SerializeToElement(new Dictionary<string, object?>
    {
        ["my-custom-key"] = "some value"
    }),
};
await client.Posts.UpdateAsync(post);
  • .gitignore fixsite/ was concatenated onto a previous line, making it ineffective; split to its own line

  • Integration tests — two new self-hosted integration tests in tests/WordPressPCL.Tests.Selfhosted/Posts_Tests.cs:

    • Posts_Meta_Write_And_Read — creates a post with a registered meta key set to a unique value and asserts the value is returned on the next fetch
    • Posts_Meta_Update — creates a post, updates only its meta field via a partial Post object, and verifies the new value is reflected on the next fetch

    The self-hosted test environment is prepared in dev/init-wordpress.sh by writing a mu-plugin that calls register_post_meta('post', 'wordpresspcl_test_meta', ['show_in_rest' => true, ...]), making the key available through the REST API for all test runs.

Copilot AI linked an issue Apr 7, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Investigate support for custom fields via REST API docs: investigate and document custom fields (meta) support Apr 7, 2026
Copilot AI requested a review from ThomasPe April 7, 2026 13:31
@ThomasPe
Copy link
Copy Markdown
Member

ThomasPe commented Apr 7, 2026

@copilot are there sufficien integration tests for the custom fields support?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot are there sufficien integration tests for the custom fields support?

Added two integration tests in commit e9e33b5:

  • Posts_Meta_Write_And_Read — creates a post with wordpresspcl_test_meta set to a unique value, fetches it back, and asserts the value round-trips correctly.
  • Posts_Meta_Update — creates a post with an initial meta value, then updates only the meta field via a partial Post object, and verifies the new value is returned on the next fetch.

The test environment is prepared via a mu-plugin written by dev/init-wordpress.sh that calls register_post_meta() with show_in_rest: true for the wordpresspcl_test_meta key on post objects — exactly the server-side setup documented in the new custom fields page.

@ThomasPe ThomasPe marked this pull request as ready for review April 7, 2026 13:48
Copilot AI review requested due to automatic review settings April 7, 2026 13:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds/updates documentation and self-hosted integration tests to clarify and validate WordPress custom fields (“meta”) usage in WordPressPCL, aligning code examples with the existing JsonElement? Meta model shape.

Changes:

  • Added a dedicated v3 documentation page describing opt-in REST meta exposure, reading/writing patterns, and CustomRequest usage for top-level fields.
  • Fixed v2/v3 posts docs examples to use JsonSerializer.SerializeToElement(...) for Meta (instead of a non-compiling Dictionary<string,string> assignment) and linked to the new custom fields doc.
  • Added self-hosted integration tests for writing and updating registered post meta; updated .gitignore to correctly ignore site/.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/WordPressPCL.Tests.Selfhosted/Posts_Tests.cs Adds two integration tests covering post meta write/read and meta-only updates.
dev/init-wordpress.sh Registers a REST-exposed test meta key via a mu-plugin for repeatable integration tests.
docs/v3/entities/customFields.md New reference doc for custom fields/meta, including top-level field guidance via CustomRequest.
docs/v3/entities/posts.md Fixes Meta update example to use JsonElement serialization; links to custom fields doc.
docs/v2/entities/posts.md Fixes Meta update example to use JsonElement serialization.
mkdocs.yml Adds the new “Custom Fields” page to v3 navigation.
.gitignore Splits site/ onto its own line so it’s actually ignored.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +246 to +249
// Act — create then fetch back (edit context to ensure meta is returned)
Post createdPost = await _clientAuth.Posts.CreateAsync(post, TestContext.CancellationToken);
Post fetchedPost = await _clientAuth.Posts.GetByIdAsync(createdPost.Id, cancellationToken: TestContext.CancellationToken);

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetByIdAsync defaults to useAuth: false and also doesn’t let you request context=edit. Since meta fields are often only returned in edit context for authenticated requests, this test can intermittently read an empty/omitted Meta even though the write succeeded. Consider fetching the created post via Posts.QueryAsync with new PostsQueryBuilder { Include = [createdPost.Id], Context = Context.Edit } and useAuth: true (or use CustomRequest against wp/v2/posts/{id}?context=edit with useAuth: true).

Copilot uses AI. Check for mistakes.
Comment on lines +251 to +253
Assert.IsNotNull(fetchedPost.Meta, "Meta should not be null when a registered key was written");
string? readValue = fetchedPost.Meta.Value.GetProperty("wordpresspcl_test_meta").GetString();
Assert.AreEqual(metaValue, readValue, "Meta value read back should equal the value written");
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetchedPost.Meta.Value.GetProperty("wordpresspcl_test_meta") will throw if WordPress returns an empty {} (or the key is absent) even when Meta itself is non-null. To make failures clearer and avoid an unhandled KeyNotFoundException, use TryGetProperty and assert the property exists before reading the string value.

Copilot uses AI. Check for mistakes.
await _clientAuth.Posts.UpdateAsync(updateRequest, TestContext.CancellationToken);

// Assert — fetch back and verify
Post fetchedPost = await _clientAuth.Posts.GetByIdAsync(createdPost.Id, cancellationToken: TestContext.CancellationToken);
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as above: the verification fetch uses GetByIdAsync without useAuth: true and can’t set context=edit, which may prevent the updated meta from being returned. Prefer querying by Include with Context = Context.Edit and useAuth: true (or a CustomRequest to ...?context=edit).

Suggested change
Post fetchedPost = await _clientAuth.Posts.GetByIdAsync(createdPost.Id, cancellationToken: TestContext.CancellationToken);
List<Post> fetchedPosts = (await _clientAuth.Posts.QueryAsync(new PostsQueryBuilder
{
Include = new List<int> { createdPost.Id },
Context = Context.Edit
}, useAuth: true, cancellationToken: TestContext.CancellationToken)).ToList();
Post fetchedPost = fetchedPosts.Single();

Copilot uses AI. Check for mistakes.
Comment on lines +76 to +78
| `PostRevision` | `/wp/v2/revisions` |
| `User` | `/wp/v2/users` |

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table lists the PostRevision endpoint as /wp/v2/revisions, but this library’s revisions client routes under the parent post (e.g. wp/v2/posts/{postId}/revisions). Please update the endpoint column (and consider adding a short note that revisions are nested under posts).

Suggested change
| `PostRevision` | `/wp/v2/revisions` |
| `User` | `/wp/v2/users` |
| `PostRevision` | `/wp/v2/posts/{postId}/revisions` |
| `User` | `/wp/v2/users` |
> **Note:** Revisions are nested under their parent post, so the revisions route includes the post ID.

Copilot uses AI. Check for mistakes.
| `Comment` | `/wp/v2/comments` |
| `MediaItem` | `/wp/v2/media` |
| `PostRevision` | `/wp/v2/revisions` |
| `User` | `/wp/v2/users` |
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section claims the Meta property is available only on the listed models, but the codebase also exposes Meta on term models like Category and Tag. Either expand the list to include those models/endpoints (term meta) or clarify that the list is limited to the primary entities covered by this doc.

Suggested change
| `User` | `/wp/v2/users` |
| `User` | `/wp/v2/users` |
| `Category` | `/wp/v2/categories` |
| `Tag` | `/wp/v2/tags` |

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Investigate Custom Fields Support

3 participants