{"slug":"translatepress-url-seo-compatibility","title":"translatepress-url-seo-compatibility","summary":"Audit or implement TranslatePress-compatible URLs, routing, slugs, SEO metadata, sitemaps, hreflang, canonical links, redirects, AJAX URLs, REST routes, WooCommerce permalinks, and Different Domain per Language behavior. Use when plugin/theme code builds links, parses REQUEST_URI","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-16T14:52:14.117899Z","repo":{"url":"https://github.com/Lonsdale201/wp-agent-skills","stars":22,"forks":2,"license":"MIT","updatedAt":"2026-09-26T23:03:36Z"},"bodyHtml":"<hr>\n<h2>name: translatepress-url-seo-compatibility\ndescription: Audit or implement TranslatePress-compatible URLs, routing, slugs, SEO metadata, sitemaps, hreflang, canonical links, redirects, AJAX URLs, REST routes, WooCommerce permalinks, and Different Domain per Language behavior. Use when plugin/theme code builds links, parses REQUEST_URI, registers CPT/taxonomy rewrites, emits SEO tags or sitemaps, caches absolute URLs, handles forms on translated URLs, or must work with the TranslatePress SEO Pack and Multiple Domains add-ons.\nlicense: GPLv2-or-later\nmetadata:\nwp-skills-author: \"Soczó Kristóf\"\nwp-skills-contact: \"mailto:lonsdale201@hotmail.com\"\nwp-skills-plugin: \"translatepress-multilingual + translatepress-business\"\nwp-skills-plugin-version-tested: \"TranslatePress Multilingual 3.2.1 + Business 1.8.2\"\nwp-skills-wp-version-tested: \"7.0\"\nwp-skills-php-min: \"7.4\"\nwp-skills-last-updated: \"2026-06-17\"</h2>\n<h1>TranslatePress URL, SEO, And Domain Compatibility</h1>\n<p>TranslatePress rewrites internal URLs for the active language. The Business SEO Pack can translate slugs and extend sitemaps; Different Domain per Language can map each language to another host. Plugin/theme code must use WordPress URL APIs, avoid manual language-prefix logic, and vary caches by language and host.</p>\n<h2>When to use this skill</h2>\n<p>Trigger when ANY of the following is true:</p>\n<ul>\n<li>Code calls <code>home_url()</code>, <code>site_url()</code>, <code>get_permalink()</code>, <code>get_term_link()</code>, <code>post_type_link</code>, <code>term_link</code>, <code>rest_url()</code>, <code>admin_url()</code>, or manually builds absolute links.</li>\n<li>Code parses <code>$_SERVER['REQUEST_URI']</code>, performs redirects, registers rewrites, or handles forms on translated pages.</li>\n<li>The task mentions TranslatePress SEO Pack, URL Slug Translation, <code>trp_get_url_for_language</code>, <code>trp_translate_slugs_on_internal_links</code>, <code>trp_hreflang</code>, Different Domain per Language, multilingual sitemap, translated WooCommerce slugs, CORS, canonical, or hreflang.</li>\n</ul>\n<h2>Generate URLs safely</h2>\n<p>Prefer WordPress URL functions and let TranslatePress filter them:</p>\n<pre><code>$url = get_permalink( $post_id );\n</code></pre>\n<p>When a URL is output in an unusual place or must target a specific language, use the documented URL converter:</p>\n<pre><code>if ( class_exists( 'TRP_Translate_Press' ) ) {\n    $trp = TRP_Translate_Press::get_trp_instance();\n    $url_converter = $trp-&gt;get_component( 'url_converter' );\n    $url = $url_converter-&gt;get_url_for_language( 'de_DE', $source_url, '' );\n}\n</code></pre>\n<p>Keep the third parameter as an empty string unless you have source-confirmed reasons to do otherwise.</p>\n<p>Never manually prepend <code>/en/</code>, strip the first path segment, or concatenate language slugs from settings. That breaks translated slugs, default-language subdirectory mode, unpublished languages, and domain mapping.</p>\n<h2>External links</h2>\n<p>TranslatePress can inspect external links for URL translation. If an external link must never be rewritten, mark it explicitly:</p>\n<pre><code>echo '&lt;a href=\"https://facebook.com/example\" data-no-translation-href&gt;Facebook&lt;/a&gt;';\n</code></pre>\n<p>For JS-generated external links, use <code>trp_skip_strings_from_dynamic_translation_for_substrings</code> to exclude URL substrings from dynamic href translation.</p>\n<h2>SEO Pack behavior</h2>\n<p>The SEO Pack source wires these behaviors:</p>\n<ul>\n<li>adds SEO node accessors for image alt, meta description/open graph/Twitter tags, page title, and selected schema.org JSON-LD keys;</li>\n<li>registers String Translation types for taxonomy, term, post slug, post type base slug, and WooCommerce slug translation;</li>\n<li>hooks <code>plugins_loaded</code> priority <code>3</code> to translate <code>REQUEST_URI</code> back to default-language slugs so WordPress can resolve the request;</li>\n<li>filters internal link hooks such as <code>post_type_link</code>, <code>page_link</code>, <code>post_link</code>, <code>post_type_archive_link</code>, <code>term_link</code>, <code>get_pagenum_link</code>, <code>attachment_link</code>, and WooCommerce URL hooks;</li>\n<li>filters <code>trp_get_url_for_language</code> through slug translation;</li>\n<li>extends Yoast, Rank Math, SEOPress, AIOSEO, and related sitemap output with alternate language URLs;</li>\n<li>checks public post/term slug uniqueness against TranslatePress slug tables.</li>\n</ul>\n<p>Audit plugin/theme code against this behavior. If code bypasses WordPress link APIs or parses original slugs directly, it can fail on translated slugs.</p>\n<h2>CPT and taxonomy rules</h2>\n<p>Register public post types and taxonomies early and deterministically:</p>\n<pre><code>register_post_type( 'event', array(\n    'public'             =&gt; true,\n    'publicly_queryable' =&gt; true,\n    'rewrite'            =&gt; array( 'slug' =&gt; 'events' ),\n    'has_archive'        =&gt; true,\n) );\n</code></pre>\n<p>Do not change rewrite slugs per language in your plugin/theme. SEO Pack owns translated slugs. After changing CPT/taxonomy rewrite definitions, flush permalinks through normal deployment/admin activation flow, not on every request.</p>\n<p>Private/non-public post types should stay non-public. SEO Pack skips slug uniqueness changes for non-public post types because modifying private editor/template slugs can break WordPress internals.</p>\n<h2>Request parsing and redirects</h2>\n<p>Avoid direct <code>$_SERVER['REQUEST_URI']</code> routing. TranslatePress SEO Pack may temporarily rewrite it so WordPress resolves translated slug requests.</p>\n<p>Use WP conditionals and query vars:</p>\n<pre><code>add_action( 'template_redirect', static function (): void {\n    if ( ! is_singular( 'event' ) ) {\n        return;\n    }\n    // Safe page-specific logic here.\n} );\n</code></pre>\n<p>If your plugin has a custom front-end endpoint that SEO Pack misidentifies as a translatable slug path, use source-confirmed filters:</p>\n<ul>\n<li><code>trp_is_rest_api</code> for REST-like/custom API requests.</li>\n<li><code>trp_is_admin_link</code> for admin/login-like URLs.</li>\n<li><code>trp_is_form_for_request_uri</code> for POST/form requests that should not redirect.</li>\n<li><code>trp_allow_redirect_to_translated_url</code> to stop a translated-slug redirect for a specific URL.</li>\n<li><code>trp_redirect_status</code> or <code>trp_redirect_to_translated_slug_url</code> only when changing redirect behavior intentionally.</li>\n</ul>\n<p>Do not add broad filters that disable slug translation sitewide.</p>\n<h2>WooCommerce URL details</h2>\n<p>SEO Pack has special handling for WooCommerce gettext slugs:</p>\n<ul>\n<li><code>product</code></li>\n<li><code>product-category</code></li>\n<li><code>product-tag</code></li>\n</ul>\n<p>It reads actual WooCommerce permalink settings, handles custom bases, and avoids unsafe replacement of composite bases such as <code>%product_cat%</code> paths. If your WooCommerce extension builds product/category/tag links, use WooCommerce and WordPress URL APIs, not hardcoded <code>/product/</code> paths.</p>\n<p>For account/reset-password flows, test translated My Account URLs. SEO Pack adjusts reset password cookie paths for translated account URLs.</p>\n<h2>Different Domain per Language</h2>\n<p>Different Domain per Language is Business/Developer-only and, in Business 1.8.2, requires main TranslatePress <code>3.0.3+</code>.</p>\n<p>Source behavior to account for:</p>\n<ul>\n<li>domain mappings are stored in <code>trp_settings['trp-multiple-domains']</code>;</li>\n<li>mapped domains are normalized to protocol + host;</li>\n<li>default-language subdirectory mode is disabled while domain mapping is active;</li>\n<li>current language is set from host on <code>plugins_loaded</code> priority <code>2</code>;</li>\n<li>language-slug URLs redirect to mapped domains on priority <code>3</code>;</li>\n<li>admin/login requests on secondary domains redirect to the main domain on priority <code>4</code>;</li>\n<li>WordPress URL, asset URL, upload, srcset, AJAX, sitemap, and some builder/font URLs are filtered to the current host;</li>\n<li>Yoast and Rank Math sitemap caching is disabled when mapped domains are active because sitemap output must vary by hostname.</li>\n</ul>\n<p>Do not bake the main domain into cached CSS, JS config, sitemap XML, schema JSON, canonical tags, or REST responses. Vary by host or generate late.</p>\n<h2>AJAX, REST, and CORS</h2>\n<p>For public front-end endpoints:</p>\n<ul>\n<li>Prefer same-origin REST URLs generated at render time.</li>\n<li>Do not assume <code>admin_url( 'admin-ajax.php' )</code> is valid from every language domain.</li>\n<li>Avoid absolute asset URLs in static CSS generated on the main domain; use relative URLs where possible.</li>\n<li>If you must cache endpoint URLs in JS config, vary by host and language.</li>\n</ul>\n<p>Different Domain per Language includes specific fixes for Elementor fonts/CSS, Breakdance fonts, file blocks, srcset, upload URLs, and Automatic Language Detection AJAX URLs. Your plugin does not automatically get that coverage for custom hardcoded URLs.</p>\n<h2>Sitemaps, canonical, and hreflang</h2>\n<p>If your plugin emits SEO output:</p>\n<ul>\n<li>Use the final translated URL for canonical and <code>og:url</code>.</li>\n<li>Include all published language alternates when generating a sitemap-like feed.</li>\n<li>Do not cache sitemap output without varying by hostname and language/domain mapping.</li>\n<li>Respect <code>trp_disable_languages_sitemap</code>, <code>trp_add_language_url_to_sitemap</code>, <code>trp_hreflang</code>, <code>trp_add_country_hreflang_tags</code>, and <code>trp_add_region_independent_hreflang_tags</code> when integrating with SEO Pack.</li>\n</ul>\n<p>If your plugin registers its own sitemap provider, test with SEO Pack active and translated slugs enabled.</p>\n<h2>Critical rules</h2>\n<ul>\n<li>Do not manually build language-prefixed URLs.</li>\n<li>Do not parse translated slugs as stable identifiers.</li>\n<li>Do not redirect POST requests because a slug looks untranslated.</li>\n<li>Do not cache absolute URLs, canonical tags, sitemap XML, or JSON-LD globally across languages/domains.</li>\n<li>Do not assume wp-admin works on secondary language domains.</li>\n<li>Do not overwrite SEO Pack sitemap filters unless you fully preserve alternate URLs and hreflang.</li>\n</ul>\n<h2>Cross-references</h2>\n<ul>\n<li>Run <strong><code>translatepress-output-compatibility</code></strong> for visible text, dynamic fragments, exclusions, and language-aware HTML caches.</li>\n<li>Run <strong><code>translatepress-language-ui-navigation</code></strong> for language switchers, per-language menus, translator roles, and language detection UI.</li>\n<li>Run <strong><code>translatepress-email-notification-compatibility</code></strong> for translated links inside emails and recipient-language notification flows.</li>\n</ul>\n<h2>References</h2>\n<ul>\n<li>SEO Pack source: <code>add-ons-advanced/seo-pack/class-seo-pack.php</code></li>\n<li>Core URL converter source: <code>wp-content/plugins/translatepress-multilingual/includes/class-url-converter.php</code></li>\n<li>Slug manager source: <code>add-ons-advanced/seo-pack/includes/class-slug-manager.php</code></li>\n<li>WooCommerce gettext slug source: <code>add-ons-advanced/seo-pack/includes/class-gettext-slugs.php</code></li>\n<li>Multiple Domains source: <code>add-ons-pro/multiple-domains/class-multiple-domains.php</code></li>\n<li>TranslatePress URL conversion docs: <a href=\"https://translatepress.com/docs/developers/translating-an-internal-url/\">https://translatepress.com/docs/developers/translating-an-internal-url/</a></li>\n<li>Different Domain per Language docs: <a href=\"https://translatepress.com/docs/developers/different-domain-per-language/\">https://translatepress.com/docs/developers/different-domain-per-language/</a></li>\n<li>SEO Pack docs: <a href=\"https://translatepress.com/docs/addons/seo-pack/\">https://translatepress.com/docs/addons/seo-pack/</a></li>\n<li>Official documentation: <a href=\"https://translatepress.com/docs/developers/excluding-translation-of-external-domain-links/\">https://translatepress.com/docs/developers/excluding-translation-of-external-domain-links/</a></li>\n<li>Verified source paths:\n<ul>\n<li><code>wp-content/plugins/translatepress-multilingual/index.php</code></li>\n<li><code>wp-content/plugins/translatepress-multilingual/readme.txt</code></li>\n<li><code>wp-content/plugins/translatepress-multilingual/includes/class-translation-render.php</code></li>\n<li><code>wp-content/plugins/translatepress-business/readme.txt</code></li>\n<li><code>wp-content/plugins/translatepress-business/add-ons-advanced/seo-pack/includes/class-slug-query.php</code></li>\n<li><code>wp-content/plugins/translatepress-business/add-ons-pro/multiple-domains/class-trp-language-domains-sso.php</code></li>\n</ul>\n</li>\n</ul>\n","files":[{"path":"SKILL.md","sizeBytes":11042,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-16T14:57:52.290132Z","sha256":"72529963D248FA8BECAC637AEF4DA49E28F1700BED75293958E6C3646D45193F","sizeBytes":4277},"review":null,"source":{"repositoryUrl":"https://github.com/Lonsdale201/wp-agent-skills","path":"translatepress/translatepress-url-seo-compatibility","license":"MIT","commit":"c51b571a259f0c4b5f5c0a3bc50ed580c6851f98","subtreeSha":"DCD34FE59F7CDA772A4C5FF16666D5673E532A535248FE08B2A863C02220F4E8","lastSyncedAt":"2026-09-29T23:33:03.303675Z"},"reviewedAt":"2026-09-16T15:17:08.814062Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/translatepress/translatepress-url-seo-compatibility"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart"},{"target":"git","command":"git clone https://github.com/Lonsdale201/wp-agent-skills.git"}]}