{"id":313494,"date":"2026-05-20T07:24:19","date_gmt":"2026-05-20T07:24:19","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/geoforge-schema\/"},"modified":"2026-06-12T14:16:05","modified_gmt":"2026-06-12T14:16:05","slug":"geoforge-schema","status":"publish","type":"plugin","link":"https:\/\/ko.wordpress.org\/plugins\/geoforge-schema\/","author":23498805,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.4.0","stable_tag":"1.4.0","tested":"6.9.4","requires":"5.6","requires_php":"7.4","requires_plugins":null,"header_name":"GEOforge Schema","header_author":"Hop AI","header_description":"Emits JSON-LD schema markup generated by GEOforge into the &lt;head&gt; of single posts and pages, and opens up the SEO post-meta keys used by Yoast SEO and Rank Math so GEOforge can write meta descriptions on publish. Required for schema and meta-description delivery on GEOforge-published content \u2014 WordPress strips inline &lt;script&gt; tags from post bodies and underscore-prefixed meta is hidden from REST by default. Also ships a small scoped stylesheet that constrains GEOforge-published content to a readable column width on themes that don't apply a content container.","assets_banners_color":"","last_updated":"2026-06-12 14:16:05","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/getgeoforge.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":165,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.2.0":{"tag":"1.2.0","author":"delchostanimirov","date":"2026-05-20 07:24:06"},"1.3.0":{"tag":"1.3.0","author":"delchostanimirov","date":"2026-06-11 08:26:16"},"1.4.0":{"tag":"1.4.0","author":"delchostanimirov","date":"2026-06-12 14:16:05"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3538484,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3538484,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.2.0","1.3.0","1.4.0"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[2591,2516,1117,186],"plugin_category":[49,55],"plugin_contributors":[263624],"plugin_business_model":[],"class_list":["post-313494","plugin","type-plugin","status-publish","hentry","plugin_tags-geo","plugin_tags-json-ld","plugin_tags-schema","plugin_tags-seo","plugin_category-maps-and-location","plugin_category-seo-and-marketing","plugin_contributors-delchostanimirov","plugin_committers-delchostanimirov"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/geoforge-schema\/assets\/icon-128x128.png?rev=3538484","icon_2x":"https:\/\/ps.w.org\/geoforge-schema\/assets\/icon-256x256.png?rev=3538484","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>GEOforge generates JSON-LD schema markup and meta descriptions for the articles it publishes. WordPress strips inline <code>&lt;script&gt;<\/code> tags from post bodies (KSES sanitization) and hides underscore-prefixed meta from the REST API by default, so neither can be set by an external publishing tool without a companion plugin.<\/p>\n\n<p>This plugin solves that by:<\/p>\n\n<ol>\n<li>Registering a <code>_geoforge_jsonld<\/code> post-meta key, exposed via the REST API for every public REST-enabled post type, that GEOforge writes to when publishing or updating an article.<\/li>\n<li>Printing the stored JSON-LD inside a proper <code>&lt;script type=\"application\/ld+json\"&gt;<\/code> tag in the page <code>&lt;head&gt;<\/code> on any singular view \u2014 posts, pages, and custom post types.<\/li>\n<li>Registering the SEO post-meta keys used by Yoast SEO (<code>_yoast_wpseo_metadesc<\/code>), Rank Math (<code>rank_math_description<\/code>), and The SEO Framework (<code>_genesis_title<\/code> \/ <code>_genesis_description<\/code>) for REST API write access, so GEOforge can sync SEO titles and meta descriptions on publish. Each registration uses an <code>edit_post<\/code> auth check and <code>sanitize_text_field<\/code>-based sanitization capped at 320 characters. Registration is idempotent \u2014 if the SEO plugin already exposes the key for REST, our registration is a no-op.<\/li>\n<\/ol>\n\n<p>No configuration required. Install, activate, and any GEOforge-published article will get its schema markup rendered correctly and its meta description handed to whichever SEO plugin is active.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin zip via Plugins \u2192 Add New \u2192 Upload Plugin.<\/li>\n<li>Activate.<\/li>\n<li>Publish from GEOforge as normal \u2014 schema will appear in <code>&lt;head&gt;<\/code> on each article.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20geoforge%20to%20use%20this%20plugin%3F\"><h3>Do I need GEOforge to use this plugin?<\/h3><\/dt>\n<dd><p>The plugin is designed to render JSON-LD that GEOforge writes during publish. It will work with any tool that writes a JSON-encoded string to the <code>_geoforge_jsonld<\/code> post-meta key via the REST API, but on its own it does nothing \u2014 there is no admin UI for entering schema by hand.<\/p><\/dd>\n<dt id=\"will%20this%20conflict%20with%20yoast%20seo%2C%20rank%20math%2C%20the%20seo%20framework%2C%20or%20all%20in%20one%20seo%3F\"><h3>Will this conflict with Yoast SEO, Rank Math, The SEO Framework, or All in One SEO?<\/h3><\/dt>\n<dd><p>No. Multiple <code>&lt;script type=\"application\/ld+json\"&gt;<\/code> blocks per page are valid Schema.org and supported by Google \u2014 search engines merge the data. If both your SEO plugin and GEOforge emit schema, both will appear in the page head.<\/p>\n\n<p>For SEO titles and meta descriptions, the plugin registers the Yoast, Rank Math, and The SEO Framework meta keys for REST so the active plugin renders GEOforge's values instead of auto-generating its own. The registration calls are idempotent \u2014 if the SEO plugin has already registered the key itself, our call is a no-op. The auth callback restricts writes to users with <code>edit_post<\/code> capability on the target post. All in One SEO stores its data in a custom table rather than post meta, so it is not covered.<\/p><\/dd>\n<dt id=\"why%20is%20the%20meta%20key%20prefixed%20with%20an%20underscore%3F\"><h3>Why is the meta key prefixed with an underscore?<\/h3><\/dt>\n<dd><p>WordPress treats underscore-prefixed meta as \"protected\" \u2014 hidden from the default Custom Fields UI in the post editor. This prevents accidental editing of the JSON blob while still allowing the REST API (and this plugin) to read and write it.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20i%20deactivate%20the%20plugin%3F\"><h3>What happens if I deactivate the plugin?<\/h3><\/dt>\n<dd><p>The stored schema data is preserved in post meta. Re-activating restores schema rendering on the front end. Uninstalling the plugin does not remove the meta.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Register The SEO Framework's <code>_genesis_title<\/code> and <code>_genesis_description<\/code> post-meta keys for REST write access, alongside the existing Yoast and Rank Math keys, so GEOforge can sync the SEO title and meta description to sites using The SEO Framework. Same idempotent registration and <code>edit_post<\/code> auth check as the other SEO keys.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Register the <code>_geoforge_jsonld<\/code>, <code>_yoast_wpseo_metadesc<\/code>, and <code>rank_math_description<\/code> meta keys for every public REST-enabled post type (previously posts and pages only), so GEOforge can publish into custom post types with full schema and meta-description delivery. Registration runs at <code>init<\/code> priority 20 so post types registered by themes\/plugins at the default priority are included.<\/li>\n<li>Enqueue the scoped <code>.geoforge-content<\/code> stylesheet on all singular views, not just posts and pages, matching the JSON-LD emitter.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>JSON-LD output: decode the stored value and re-encode via <code>wp_json_encode<\/code> with <code>JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT<\/code> (plus <code>JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES<\/code>) before emitting. Every HTML-sensitive character is emitted as a <code>\\uXXXX<\/code> escape, replacing the prior <code>str_replace('&lt;\/', '&lt;\\\/', $json)<\/code> approach.<\/li>\n<li>Register <code>_yoast_wpseo_metadesc<\/code> (Yoast SEO) and <code>rank_math_description<\/code> (Rank Math) post-meta keys for REST write access. Both use <code>show_in_rest<\/code>, an <code>edit_post<\/code> auth callback, and a <code>sanitize_text_field<\/code>-based sanitizer capped at 320 characters. Idempotent \u2014 no-op when the SEO plugin already exposes the key.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Readme: rewrite the short description so the wp.org renderer doesn't strip the literal <code>&lt;head&gt;<\/code> tag and leave the sentence incomplete. Functionality unchanged.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Enqueue a small scoped stylesheet on single posts and pages that constrains <code>.geoforge-content<\/code> to a 768px max-width and makes inline images responsive. Fixes edge-to-edge text on themes that don't apply a content container around <code>the_content()<\/code>. No typography or color rules \u2014 host theme keeps full control of look-and-feel.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Renders GEOforge-generated JSON-LD schema in the page head and opens Yoast SEO \/ Rank Math \/ The SEO Framework SEO meta for REST writes.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/313494","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=313494"}],"author":[{"embeddable":true,"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/delchostanimirov"}],"wp:attachment":[{"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=313494"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=313494"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=313494"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=313494"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=313494"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ko.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=313494"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}