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