{"id":282103,"date":"2026-03-03T18:42:18","date_gmt":"2026-03-03T18:42:18","guid":{"rendered":"https:\/\/en-ca.wordpress.org\/plugins\/half-baked-link-injection\/"},"modified":"2026-03-04T23:00:46","modified_gmt":"2026-03-04T23:00:46","slug":"half-baked-link-injection","status":"publish","type":"plugin","link":"https:\/\/bo.wordpress.org\/plugins\/half-baked-link-injection\/","author":13445502,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"2.0.8","stable_tag":"3.0.10","tested":"6.9.4","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Half Baked Link Injection","header_author":"Half Baked Idea","header_description":"Inject links into post\/page content based on user-defined rules.","assets_banners_color":"","last_updated":"2026-03-04 23:00:46","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/halfbakedidea.ca\/","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":372,"num_ratings":0,"support_threads":1,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"3.0.10":{"tag":"3.0.10","author":"emrysh","date":"2026-03-04 23:00:46"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3473941,"resolution":"128x128","location":"assets","locale":""},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3473941,"resolution":"256x256","location":"assets","locale":""},"icon.svg":{"filename":"icon.svg","revision":3473941,"resolution":false,"location":"assets","locale":false}},"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["3.0.10"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3474173,"resolution":"1","location":"assets","locale":""},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3474173,"resolution":"2","location":"assets","locale":""},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3474173,"resolution":"3","location":"assets","locale":""}},"screenshots":{"1":"The rules list screen, showing priority, phrase, destination, and scope.","2":"Adding or editing a rule, including whole-word and occurrence options.","3":"Internal link picker for selecting posts and pages."},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[529,6681,175,186],"plugin_category":[55],"plugin_contributors":[254343],"plugin_business_model":[],"class_list":["post-282103","plugin","type-plugin","status-publish","hentry","plugin_tags-content","plugin_tags-internal-links","plugin_tags-links","plugin_tags-seo","plugin_category-seo-and-marketing","plugin_contributors-emrysh","plugin_committers-emrysh"],"banners":[],"icons":{"svg":"https:\/\/ps.w.org\/half-baked-link-injection\/assets\/icon.svg?rev=3473941","icon":"https:\/\/ps.w.org\/half-baked-link-injection\/assets\/icon.svg?rev=3473941","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/half-baked-link-injection\/assets\/screenshot-1.png?rev=3474173","caption":"The rules list screen, showing priority, phrase, destination, and scope."},{"src":"https:\/\/ps.w.org\/half-baked-link-injection\/assets\/screenshot-2.png?rev=3474173","caption":"Adding or editing a rule, including whole-word and occurrence options."},{"src":"https:\/\/ps.w.org\/half-baked-link-injection\/assets\/screenshot-3.png?rev=3474173","caption":"Internal link picker for selecting posts and pages."}],"raw_content":"<!--section=description-->\n<p>Half Baked Link Injection lets you define simple rules that automatically replace whole-word phrases with links when WordPress renders post and page content.<\/p>\n\n<p>It is designed for clean, predictable linking that stays out of your way. Rules are applied only to <code>the_content<\/code>, and existing links are never modified. This makes it useful for SEO hygiene, internal linking, and turning recurring terms into consistent references without editing each post manually.<\/p>\n\n<h4>How it works<\/h4>\n\n<p>Create one or more injection rules. Each rule includes:\n* A phrase (whole-word matching is always used)\n* A destination URL (internal relative links or external URLs)\n* Optional settings like case sensitivity, where it applies, and how often it triggers<\/p>\n\n<p>When a post or page is displayed, the plugin scans only the text portions of the content and injects links where appropriate. It will not touch phrases inside existing <code>&lt;a&gt;<\/code> tags, and it skips script and style blocks to avoid breaking markup.<\/p>\n\n<h4>Targeting and control<\/h4>\n\n<p>Rules can be scoped and prioritized so you stay in control when phrases overlap or your site grows.\n* Post type targeting: apply a rule to Posts, Pages, or both\n* Priority ordering: lower numbers win when multiple rules could match the same spot\n* Tie-breaking: if priorities match, newer rules win<\/p>\n\n<h4>Occurrence options<\/h4>\n\n<p>Control how frequently each phrase is linked:\n* First\n* First + every Nth\n* Every Nth\n* All<\/p>\n\n<p>This is useful when you want a light touch on long articles.<\/p>\n\n<h4>External links done properly<\/h4>\n\n<p>When a rule points to an external URL, the plugin:\n* Adds <code>target=\"_blank\"<\/code>\n* Ensures <code>rel<\/code> includes <code>noopener noreferrer<\/code>\n* Lets you append additional rel tokens like <code>nofollow<\/code> or <code>sponsored<\/code><\/p>\n\n<p>Relative URLs stay relative and do not get <code>target=\"_blank\"<\/code>.<\/p>\n\n<h4>Built for safety and performance<\/h4>\n\n<ul>\n<li>No recursion into <code>the_content<\/code><\/li>\n<li>Processes content safely by splitting HTML and touching only text tokens<\/li>\n<li>Skips existing <code>&lt;a&gt;<\/code> tags<\/li>\n<li>Skips <code>&lt;script&gt;<\/code> and <code>&lt;style&gt;<\/code> blocks<\/li>\n<\/ul>\n\n<h4>Privacy and data<\/h4>\n\n<p>This plugin does not send any data off-site. Rules are stored locally in your WordPress database in a single option.<\/p>\n\n<h4>Uninstall<\/h4>\n\n<p>Uninstalling the plugin removes stored rules from your database.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin files to the <code>\/wp-content\/plugins\/half-baked-link-injection<\/code> directory, or install the plugin through the WordPress plugins screen directly.<\/li>\n<li>Activate the plugin through the Plugins screen in WordPress.<\/li>\n<li>Go to Settings and open Half Baked Link Injection.<\/li>\n<li>Add one or more injection rules and save.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20change%20existing%20links%3F\"><h3>Does it change existing links?<\/h3><\/dt>\n<dd><p>No. If a phrase appears inside an existing <code>&lt;a&gt;<\/code> tag, it is ignored and not replaced.<\/p><\/dd>\n<dt id=\"does%20it%20work%20on%20excerpts%2C%20titles%2C%20or%20widgets%3F\"><h3>Does it work on excerpts, titles, or widgets?<\/h3><\/dt>\n<dd><p>No. Rules are applied to post and page content only via <code>the_content<\/code>.<\/p><\/dd>\n<dt id=\"what%20does%20whole-word%20matching%20mean%3F\"><h3>What does whole-word matching mean?<\/h3><\/dt>\n<dd><p>It uses whole-word boundaries, so it will not match partial words. For example, \u201ccat\u201d will not match \u201ccatch\u201d.<\/p><\/dd>\n<dt id=\"how%20are%20conflicts%20handled%20when%20multiple%20rules%20could%20match%3F\"><h3>How are conflicts handled when multiple rules could match?<\/h3><\/dt>\n<dd><p>Rules are evaluated by priority (lower wins). If priorities match, newer rules win. Existing links are never modified, and the plugin will not create nested links.<\/p><\/dd>\n<dt id=\"can%20i%20add%20nofollow%20or%20sponsored%20to%20external%20links%3F\"><h3>Can I add nofollow or sponsored to external links?<\/h3><\/dt>\n<dd><p>Yes. Add tokens in the rule\u2019s Rel field. For external URLs, <code>noopener noreferrer<\/code> are always added.<\/p><\/dd>\n<dt id=\"where%20are%20rules%20stored%3F\"><h3>Where are rules stored?<\/h3><\/dt>\n<dd><p>Rules are stored locally in your WordPress database in a single option.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>3.0.10<\/h4>\n\n<ul>\n<li>Docs: Clarify data storage\/privacy and uninstall behavior.<\/li>\n<\/ul>\n\n<h4>3.0.9<\/h4>\n\n<ul>\n<li>Fix: Remove discouraged load_plugin_textdomain() call (translations auto-load on WordPress.org).<\/li>\n<\/ul>\n\n<h4>3.0.8<\/h4>\n\n<ul>\n<li>Tweak: Align admin\/AJAX capability checks (edit_posts).<\/li>\n<li>Tweak: Load translations via load_plugin_textdomain().<\/li>\n<\/ul>\n\n<h4>3.0.7<\/h4>\n\n<ul>\n<li>Fix: Plugin Check nonce\/sanitization warnings in rules save handler.<\/li>\n<\/ul>\n\n<h4>3.0.6<\/h4>\n\n<ul>\n<li>Fix: Add plugin owner to Contributors in readme.<\/li>\n<li>Fix: Sanitize\/validate posted rules earlier to satisfy review + Plugin Check.<\/li>\n<li>Fix: Prefix plugin class name to satisfy Plugin Check.<\/li>\n<\/ul>\n\n<h4>3.0.5<\/h4>\n\n<ul>\n<li>Fix: Plugin Check input-sanitization warnings in admin handlers.<\/li>\n<\/ul>\n\n<h4>3.0.4<\/h4>\n\n<ul>\n<li>Fix: Overlay N value now saves correctly (occurrence mode value alignment).<\/li>\n<\/ul>\n\n<h4>3.0.3<\/h4>\n\n<ul>\n<li>Fix: Show N input in Add New Rule overlay for Nth modes; correct N value saving.<\/li>\n<\/ul>\n\n<h4>3.0.2<\/h4>\n\n<ul>\n<li>Fix: Show\/hide N input in Add New Rule overlay (correct field IDs).<\/li>\n<\/ul>\n\n<h4>3.0.1<\/h4>\n\n<ul>\n<li>Admin: Add New Rule overlay now includes N value for Nth occurrence modes.<\/li>\n<\/ul>\n\n<h4>3.0.0<\/h4>\n\n<ul>\n<li>Version bump.<\/li>\n<\/ul>\n\n<h4>2.0.36<\/h4>\n\n<ul>\n<li>Change: Occurrence modes updated to: First, First + every Nth (1-10), Every Nth (1-10), All.<\/li>\n<\/ul>\n\n<h4>2.0.35<\/h4>\n\n<ul>\n<li>Fix: harden Add rule (overlay) save handler to avoid fatals (safe fallbacks for UUID, limits, and sanitizers).<\/li>\n<\/ul>\n\n<h4>2.0.34<\/h4>\n\n<ul>\n<li>Fix: resolve critical error on save (missing sanitize_post_types and MAX_RULES constant).<\/li>\n<\/ul>\n\n<h4>2.0.33<\/h4>\n\n<ul>\n<li>Fix: restore stable admin JS (Remove buttons work again) and make Add rule overlay submit via admin-post without breaking the page.<\/li>\n<\/ul>\n\n<h4>2.0.32<\/h4>\n\n<ul>\n<li>Fix: Add rule overlay save form is no longer nested (nested forms prevented submission in some browsers).<\/li>\n<\/ul>\n\n<h4>2.0.31<\/h4>\n\n<ul>\n<li>Admin: Add Injection overlay now saves via admin-post with a minimal payload (no AJAX, no full settings form submit) to avoid timeouts.<\/li>\n<\/ul>\n\n<h4>2.0.30<\/h4>\n\n<ul>\n<li>Fix: Add Injection overlay AJAX save now includes its own nonce (previous build never localized addRuleNonce).<\/li>\n<\/ul>\n\n<h4>2.0.29<\/h4>\n\n<ul>\n<li>Admin: Add Injection overlay now saves the new rule via AJAX to avoid full-page submits\/timeouts.<\/li>\n<\/ul>\n\n<h4>2.0.26<\/h4>\n\n<ul>\n<li>Fix: Add Injection overlay now uses the same row-creation logic as the main screen, so new rules are populated correctly and save reliably.<\/li>\n<\/ul>\n\n<h4>2.0.25<\/h4>\n\n<ul>\n<li>Fix: enqueue wp-util on settings screen so the Add Injection overlay can render new rows.<\/li>\n<\/ul>\n\n<h4>2.0.24<\/h4>\n\n<ul>\n<li>Fix: wire up Add rule and Cancel buttons inside the Add Injection overlay.<\/li>\n<\/ul>\n\n<h4>2.0.23<\/h4>\n\n<ul>\n<li>Fix: Add rule overlay now reliably adds rows (ensure wp-util dependency and add a fallback Add button inside the modal).<\/li>\n<\/ul>\n\n<h4>2.0.22<\/h4>\n\n<ul>\n<li>Fix: ensure link picker modal appears above the Add Injection overlay.<\/li>\n<\/ul>\n\n<h4>2.0.21<\/h4>\n\n<ul>\n<li>Fix: link picker now works inside the Add Injection overlay; selected URLs populate the overlay URL field.<\/li>\n<\/ul>\n\n<h4>2.0.20<\/h4>\n\n<ul>\n<li>Fix: Add New Rule now opens the overlay dialog (previous build still appended a new row directly).<\/li>\n<\/ul>\n\n<h4>2.0.19<\/h4>\n\n<ul>\n<li>Admin: add new injections via an overlay dialog (instead of appending a new row at the bottom).<\/li>\n<\/ul>\n\n<h4>2.0.18<\/h4>\n\n<ul>\n<li>Admin: block saving duplicate phrases (case-insensitive). If duplicates are detected, nothing is saved.<\/li>\n<\/ul>\n\n<h4>2.0.17<\/h4>\n\n<ul>\n<li>Hotfix: revert admin UI enhancements that caused timeouts on some hosts. Core injection behavior unchanged.<\/li>\n<\/ul>\n\n<h4>2.0.14<\/h4>\n\n<ul>\n<li>Enhancement: prevent self-link injections; Admin: block saving duplicate phrases (case-insensitive) with an error.<\/li>\n<\/ul>\n\n<h4>2.0.7<\/h4>\n\n<ul>\n<li>Plugin Checker: fix escaping for dynamic name attributes; add translators comment; harden request method check; add PHPCS annotation for sanitized POST arrays.<\/li>\n<\/ul>\n\n<h4>2.0.6<\/h4>\n\n<ul>\n<li>Fix: correct admin asset gating without request vars; resolve activation WSOD in 2.0.5.<\/li>\n<\/ul>\n\n<h4>2.0.4<\/h4>\n\n<ul>\n<li>Compliance: update Tested up to header; minor i18n cleanup for admin UI text.<\/li>\n<\/ul>\n\n<h4>2.0.3<\/h4>\n\n<ul>\n<li>Performance: avoid expensive regex runs when phrase not present; add per-request replacement cap; faster internal token splitting.<\/li>\n<\/ul>\n\n<h4>2.0.2<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Automatically replace whole-word phrases with links when WordPress renders your content, without touching existing links.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/282103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=282103"}],"author":[{"embeddable":true,"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/emrysh"}],"wp:attachment":[{"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=282103"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=282103"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=282103"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=282103"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=282103"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/bo.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=282103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}