Skip to content

Commit 554a2e5

Browse files
authored
[Website] Open external links in a new tab/window (#2468)
## Motivation for the change, related issues Adds `target="_blank"` to external links in Playground web (not CLI). This ensures external links are loaded in a new tab and not inside the Playground iframe. ## Implementation details Adds `a.target = '_blank';` via a `<script>` echoed by an mu-plugin. ## Testing Instructions (or ideally a Blueprint) Go to wp-admin and click the `WordPress` link in this part of the footer: > Thank you for creating with [WordPress](https://wordpress.org/).Version 6.8.2 cc @fellyph – While looking at your Blueprint I realized this is something we should solve at the platform level. cc @JanJakes for reviews
1 parent 3157080 commit 554a2e5

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

packages/playground/remote/src/lib/playground-mu-plugin/0-playground.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,61 @@ function networking_disabled() {
9191
<?php
9292
});
9393

94+
/**
95+
* Adds target="_blank" to external links when clicked to open them in a new tab.
96+
* This prevents users from loading non-Playground pages inside the Playground iframe.
97+
*/
98+
function playground_add_target_blank_to_external_links() {
99+
// Only run on frontend and admin pages, not during AJAX requests or CLI
100+
if (empty($_SERVER['REQUEST_URI']) || wp_doing_ajax() || wp_doing_cron()) {
101+
return;
102+
}
103+
104+
?>
105+
<script>
106+
function addTargetBlankToExternalLinks() {
107+
function addTargetBlank(a) {
108+
const url = new URL(a.href, location);
109+
if (url.origin !== location.origin) {
110+
a.target = '_blank';
111+
}
112+
}
113+
114+
// Set target="_blank" for existing external links – this
115+
// covers keyboard navigation.
116+
document.querySelectorAll('a[href]').forEach(a => {
117+
addTargetBlank(a);
118+
});
119+
120+
// Set target="_blank" for external links when clicked.
121+
// This covers links that are added after the page has loaded.
122+
document.addEventListener('click', e => {
123+
const a = e.target.closest('a[href]');
124+
if (!a) return;
125+
addTargetBlank(a);
126+
});
127+
128+
// Also handle focus events to cover keyboard navigation on
129+
// links that are added after the page has loaded.
130+
document.addEventListener('focus', e => {
131+
const a = e.target.closest('a[href]');
132+
if (!a) return;
133+
addTargetBlank(a);
134+
}, true);
135+
}
136+
137+
if (document.readyState === 'loading') {
138+
document.addEventListener('DOMContentLoaded', addTargetBlankToExternalLinks);
139+
} else {
140+
addTargetBlankToExternalLinks();
141+
}
142+
</script>
143+
144+
<?php
145+
}
146+
add_action('wp_head', 'playground_add_target_blank_to_external_links');
147+
add_action('admin_head', 'playground_add_target_blank_to_external_links');
148+
94149
/**
95150
* The default WordPress requests transports have been disabled
96151
* at this point. However, the Requests class requires at least

0 commit comments

Comments
 (0)