Automatyczne otwieranie zewnętrznych odnośników w nowej karcie przeglądarki
Moim preferowanym zachowaniem jest otwieranie zewnętrznych linków w nowej karcie przeglądarki. Oznacza to, że gdy kliknę odnośnik kierujący do strony internetowej innej niż aktualnie przeglądana, oczekuję, iż otworzy się on w nowej karcie. W dzisiejszym wpisie przedstawię, w jaki sposób za pomocą skryptu PHP automatycznie przekonwertować wszystkie odnośniki zewnętrzne w taki sposób, by otwierały się w nowej karcie.
Swoje preferencje respektuję również na własnych stronach internetowych, gdzie zawsze dbam o to, aby linki poza moją witrynę otwierały się w oddzielnej karcie. To rozwiązanie ma swoje wady i zalety. Ja jestem jego zwolennikiem, ale uczciwie zaznaczam, iż warto przed jego wprowadzeniem zapoznać się z argumentami za i przeciw. Serdecznie polecam artykuł „Opening External Links: Same Tab or New?”, który te kwestie dość dobrze objaśnia.
W moim blogu opartym na WordPressie dotychczas politykę otwierania linków zewnętrznych w nowej karcie realizowałem ręcznie — po prostu definiując każdy link, żmudnie wskakiwałem w opcje zaawansowane edytora WYSIWG i zaznaczałem odpowiedniego checkboksa. Uświadomiłem sobie jednak, że sposób ten jest nieefektywny. Nie dość, że zawsze muszę o odpowiedniej zmianie pamiętać i wprowadzać ją ręcznie, to jeszcze, jeśli w przyszłości zechcę zmienić swoją decyzję, będę musiał modyfikować wiele wpisów hurtowo (np. na poziomie bazy danych).
Napisałem więc prosty skrypt, który owe zadanie wykonuje obecnie za mnie. Skrypt jest zbudowany w formie filtra dla WordPressa, jednak bardzo łatwo można go przekształcić tak, by stał się reużywalny poza tym brzydko zaprojektowanym CMS-em. ;-)
Poniższy kod można wrzucić do functions.php swojego motywu, czego nie polecam, lub do własnej wtyczki systemowej — co bardzo rekomenduję. Oto owe cudo.
<?php
function external_anchors_target_blank($html)
{
$DOMPart = new class($html) extends \DOMDocument
{
public function __construct($html)
{
@$this->loadHTML(
'<meta charset="utf-8"><body>' . $html . '</body>',
LIBXML_NOERROR | LIBXML_NOWARNING
);
}
public function saveHTML(...$args)
{
if ($args) {
return parent::saveHTML(...$args);
}
return str_replace(['<body>', '</body>'], '',
parent::saveHTML($this->getElementsByTagName('body')[0])
);
}
};
$siteDomain = parse_url(site_url(), PHP_URL_HOST);
$anchors = $DOMPart->getElementsByTagName('a');
foreach ($anchors as $anchor) {
$anchorDomain = parse_url($anchor->getAttribute('href'), PHP_URL_HOST);
if ($anchorDomain and $anchorDomain != $siteDomain and !$anchor->getAttribute('target')) {
$anchor->setAttribute('target', '_blank');
$anchor->setAttribute('rel', trim($anchor->getAttribute('rel') . ' noopener'));
}
}
return $DOMPart->saveHTML();
};
add_filter('the_content', 'external_anchors_target_blank');
add_filter('comment_text', 'external_anchors_target_blank');
Jak widać powyżej, nie mam się z czego spowiadać. Nie zgrzeszyłem — nie zmodyfikowałem kodu HTML wyrażeniem regularnym. Zamiast tego wykorzystałem dość wygodny, choć nieidealny, wbudowany w PHP parser HTML i XML, a dokładniej obiekt DOMDocument owrapperowany przeze mnie w celu uniknięcia drobnych kłopotów z kodowaniem znaków i uzyskiwaniem wynikowego kodu HTML. Oczywiście mógłbym posłużyć się jedną z wielu bibliotek parserów HTML, jednak do tak prostego zadania nie chciałem zaciągać wielkich kombajnów.
Skrypt iteruje po wszystkich odnośnikach znalezionych w treści wpisów i komentarzy, a następnie dodaje atrybut target="_blank" do tych linków, które mają określoną domenę inną niż domena mojej witryny. Dla zwiększenia bezpieczeństwa skrypt dodaje także atrybut rel="noopener" zapobiegający modyfikacji mojej witryny przez obcą stronę otwartą w nowej karcie.
Zostawiłem też sobie tylną furtkę — jeżeli zechcę, aby wybrany odnośnik pomimo zewnętrznej domeny otwierał się w tej samej karcie, mogę manualnie wprowadzić atrybut target="_self".
Kod wykorzystuje klasę anonimową, dlatego zadziała wyłącznie w PHP 7.x.
Żeby całość była spójna, musiałem wprowadzić zmiany w bazie danych WordPressa. Aby pozbyć się z już napisanych wpisów atrybutów target="_blank" manualnie dodanych w edytorze graficznym, musiałem wykonać na bazie witryny zapytania SQL podobne do poniższych.
UPDATE wp_posts SET post_content = REPLACE(post_content, "target=\"_blank\"", ""); UPDATE wp_posts SET post_content = REPLACE(post_content, "rel=\"noopener\"", "");
Nie polecam jednak wprowadzania zmian w bazie danych WordPressa bez posiadania odpowiedniej wiedzy oraz, oczywiście, kopii zapasowej!
Komentarze (3)
?
Głupi pomysł. To użytkownik decyduje gdzie chce otworzyć link, a nie autor strony. Za takie praktyki (podobnie jak za outline: none) powinien być dół z wapnem.
Tomasz Gąsior
To kontrowersyjna sprawa i obydwie strony mają swoje argumenty. Obydwie perspektywy zostały dość dobrze opisane w podlinkowanym przeze mnie artykule. Ja osobiście lubię target blank na zewnętrznych linkach ze względu na czytelność i swego rodzaju marketing, dlatego na swoich stronach taką praktykę uprawiam.
Nie jest do końca prawdą, że użytkownik decyduje. Tak, decyduje, ale w zakresie wyznaczonym przez autora strony. To programiści tworzący dany program czy aplikację www decydują, o czym może decydować użytkownik — i moim zdaniem jest to ok, dopóki wszystko poukładane jest rozsądnie.
SpeX
Jak dla mnie, instynktownie jest iż jak chcę sobie coś otworzyć w nowej karcie, to korzystam z środkowego przycisku myszy. I to działa chyba we wszystkich przeglądarkach.
No chyba oprócz Mac’ów, gdzie nie ma środkowego klawisza myszy.
Dodaj komentarz