{"id":297289,"date":"2026-04-14T10:32:43","date_gmt":"2026-04-14T10:32:43","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/42flows-seo-meta\/"},"modified":"2026-05-06T16:43:25","modified_gmt":"2026-05-06T16:43:25","slug":"42flows-seo-meta","status":"publish","type":"plugin","link":"https:\/\/mn.wordpress.org\/plugins\/42flows-seo-meta\/","author":23476136,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.2.1","stable_tag":"1.2.1","tested":"6.9.4","requires":"5.6","requires_php":"7.4","requires_plugins":null,"header_name":"42flows SEO Meta","header_author":"42flows","header_description":"Registers SEO meta fields (Yoast, Rank Math, AIOSEO) for WordPress REST API write access. Required for 42flows content delivery.","assets_banners_color":"","last_updated":"2026-05-06 16:43:25","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/42flows.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":272,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"42flows","date":"2026-04-14 10:31:36"},"1.1.0":{"tag":"1.1.0","author":"42flows","date":"2026-04-21 11:03:46"},"1.2.0":{"tag":"1.2.0","author":"42flows","date":"2026-05-04 18:11:27"},"1.2.1":{"tag":"1.2.1","author":"42flows","date":"2026-05-06 16:43:25"}},"upgrade_notice":[],"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","1.1.0","1.2.0","1.2.1"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[5943,174175,23853,186,2227],"plugin_category":[55],"plugin_contributors":[260168],"plugin_business_model":[],"class_list":["post-297289","plugin","type-plugin","status-publish","hentry","plugin_tags-aioseo","plugin_tags-rank-math","plugin_tags-rest-api","plugin_tags-seo","plugin_tags-yoast","plugin_category-seo-and-marketing","plugin_contributors-42flows","plugin_committers-42flows"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/42flows-seo-meta.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p>42flows SEO Meta enables REST API write access to SEO meta fields for posts and pages. It auto-detects your active SEO plugin (Yoast SEO, Rank Math, or All in One SEO) and registers only the relevant meta fields with <code>show_in_rest<\/code>.<\/p>\n\n<p>This plugin is required if you use <a href=\"https:\/\/42flows.com\">42flows<\/a> to publish SEO-optimized content to your WordPress site. Without it, SEO titles, meta descriptions, and focus keyphrases cannot be set via the REST API.<\/p>\n\n<h4>Supported SEO plugins<\/h4>\n\n<ul>\n<li><strong>Yoast SEO<\/strong> \u2014 <code>_yoast_wpseo_title<\/code>, <code>_yoast_wpseo_metadesc<\/code>, <code>_yoast_wpseo_focuskw<\/code><\/li>\n<li><strong>Rank Math<\/strong> \u2014 <code>rank_math_title<\/code>, <code>rank_math_description<\/code>, <code>rank_math_focus_keyword<\/code><\/li>\n<li><strong>All in One SEO<\/strong> \u2014 <code>_aioseo_title<\/code>, <code>_aioseo_description<\/code>, <code>_aioseo_keywords<\/code><\/li>\n<\/ul>\n\n<h4>What it does<\/h4>\n\n<ul>\n<li>Detects which SEO plugin is active on your site<\/li>\n<li>Registers that plugin's meta fields with <code>show_in_rest =&gt; true<\/code> for posts and pages<\/li>\n<li>Adds <code>sanitize_callback<\/code> (sanitize_text_field) and <code>auth_callback<\/code> (requires edit_posts capability)<\/li>\n<li>Does nothing if no supported SEO plugin is detected<\/li>\n<\/ul>\n\n<h4>What it does NOT do<\/h4>\n\n<ul>\n<li>Does not modify your existing SEO data<\/li>\n<li>Does not add any admin pages, settings, or UI<\/li>\n<li>Does not load any JavaScript or CSS<\/li>\n<li>Does not store any data<\/li>\n<\/ul>\n\n<h4>Companion plugin installation and upgrades<\/h4>\n\n<p>When your site is connected to <a href=\"https:\/\/42flows.com\">42flows<\/a>, 42flows may request that this plugin install, activate, or upgrade a companion plugin (<code>42flows-content<\/code>) that enables render-time features for posts delivered by the 42flows pipeline (schema markup, attribution footer, page-optimizer REST surface). The companion plugin is downloaded from <code>https:\/\/42flows.com\/plugins\/42flows-content-latest.zip<\/code> via the <code>\/wp-json\/42flows\/v1\/install-companion<\/code> REST route.<\/p>\n\n<p>The route requires the requesting user to hold:<\/p>\n\n<ul>\n<li><code>install_plugins<\/code> and <code>activate_plugins<\/code> for fresh installs (typically Administrator role)<\/li>\n<li><code>delete_plugins<\/code> additionally when a <code>min_version<\/code> parameter is supplied that exceeds the currently-installed companion version, because the upgrade path deletes the existing companion folder before reinstalling<\/li>\n<\/ul>\n\n<p>The companion zip URL is hard-coded in the plugin source \u2014 it is never user-supplied \u2014 so the route presents no SSRF surface. No installation, upgrade, or deletion occurs unless your site is connected to 42flows and the request is authenticated by an administrator-capability user.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install the plugin from the WordPress plugin directory, or upload the ZIP file via Plugins &gt; Add New &gt; Upload Plugin.<\/li>\n<li>Activate the plugin.<\/li>\n<li>No configuration needed \u2014 the plugin auto-detects your SEO plugin.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20this%20plugin%3F\"><h3>Do I need this plugin?<\/h3><\/dt>\n<dd><p>Only if you use 42flows to publish content to your WordPress site and want SEO meta fields (title, description, focus keyphrase) set automatically via the REST API.<\/p><\/dd>\n<dt id=\"what%20if%20i%20don%27t%20have%20an%20seo%20plugin%3F\"><h3>What if I don't have an SEO plugin?<\/h3><\/dt>\n<dd><p>The plugin does nothing if no supported SEO plugin (Yoast, Rank Math, or AIOSEO) is detected. It is safe to keep installed.<\/p><\/dd>\n<dt id=\"is%20it%20safe%3F\"><h3>Is it safe?<\/h3><\/dt>\n<dd><p>Yes. It only registers existing meta fields for REST API access with proper sanitization and authentication. Only users with the <code>edit_posts<\/code> capability can write to these fields. All input is sanitized with <code>sanitize_text_field<\/code>.<\/p>\n\n<p>The companion-install REST route requires <code>install_plugins<\/code> + <code>activate_plugins<\/code> capabilities, and additionally <code>delete_plugins<\/code> for in-place upgrades. The companion plugin source URL is hard-coded \u2014 never accepted from request input \u2014 so there is no SSRF surface. The optional <code>min_version<\/code> parameter is validated against a strict <code>X.Y.Z<\/code> regex before being passed to PHP's <code>version_compare<\/code>.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20custom%20post%20types%3F\"><h3>Does it work with custom post types?<\/h3><\/dt>\n<dd><p>Currently it registers meta fields for posts and pages. Support for custom post types can be added in a future version.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.2.1<\/h4>\n\n<ul>\n<li><strong>Auto-enable WordPress plugin auto-updates for 42flows plugins.<\/strong> On every successful <code>\/install-companion<\/code> call, both <code>42flows-seo-meta<\/code> and <code>42flows-content<\/code> are added to WordPress's <code>auto_update_plugins<\/code> site option so future feature\/security\/fix releases reach the customer site without a manual click. Idempotent \u2014 safe to call repeatedly. Customers retain control: the WP admin Plugins page still shows a \"Disable auto-updates\" link.<\/li>\n<li>Why: customers connect their site to 42flows specifically so 42flows manages the meta + render layer; asking them to also manually toggle plugin auto-updates per plugin is onboarding friction with no upside (every WP-side plugin update of these two plugins comes from us anyway).<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Add optional <code>min_version<\/code> parameter to <code>\/wp-json\/42flows\/v1\/install-companion<\/code>. When supplied (semver <code>X.Y.Z<\/code>), the route compares the installed companion version against <code>min_version<\/code> and performs an in-place upgrade (deactivate \u2192 delete \u2192 reinstall \u2192 activate) if the installed version is older. Required because WordPress's <code>Plugin_Upgrader::install<\/code> refuses to overwrite an existing plugin folder. Without this parameter, behavior is unchanged: idempotent ensure-installed-and-active.<\/li>\n<li>Upgrade path additionally requires the authenticated user to hold the <code>delete_plugins<\/code> capability, in line with the principle of least privilege.<\/li>\n<li><code>min_version<\/code> is validated as <code>^\\d+\\.\\d+\\.\\d+$<\/code> before reaching <code>version_compare()<\/code> to reject arbitrary input.<\/li>\n<li>Code refactored: install logic deduplicated into a shared helper used by both fresh-install and upgrade paths.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Add REST route <code>\/wp-json\/42flows\/v1\/install-companion<\/code> for authenticated companion-plugin installation (requires <code>install_plugins<\/code> capability). Used only when the site is connected to 42flows.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Support for Yoast SEO, Rank Math, and All in One SEO.<\/li>\n<li>Meta fields registered for posts and pages.<\/li>\n<\/ul>","raw_excerpt":"Registers SEO meta fields for WordPress REST API write access. Required for 42flows content delivery.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/297289","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=297289"}],"author":[{"embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/42flows"}],"wp:attachment":[{"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=297289"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=297289"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=297289"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=297289"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=297289"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/mn.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=297289"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}