0 php /** * SEO i porządki (18.10.2026): * - alt zdjęć w treści wpisu i w zdjęciu głównym (zamiast „- fraza kluczowa” z Rank Math Image SEO), * - opis meta stron wypraw i strony bloga (wyjazdowo_meta_opis_wyprawy() + uzupełnienie w locie, gdy pole puste), * - schema TouristTrip dla stron wypraw (zamiast BlogPosting), sameAs z ustawień kontaktu, * - kategorie kontynentów → strony /europa/, /azja/… (linki + przekierowanie 301 archiwów). */ defined( 'ABSPATH' ) || exit; /* ============================== Alt zdjęć ============================== */ /** Tekst alternatywny zdjęć wpisu: tytuł bez dopisku wyprawy („Lodowiec Perito Moreno z dziećmi”). */ function wyjazdowo_alt_wpisu( int $id ): string { $t = function_exists( 'wyjazdowo_wyprawy_krotki_tytul' ) ? wyjazdowo_wyprawy_krotki_tytul( $id ) : get_the_title( $id ); return trim( preg_replace( '/\s+/u', ' ', wp_strip_all_tags( $t ) ) ); } /** Puste alt="" (albo brak alt) w zdjęciach treści wpisu → podpis zdjęcia, a bez podpisu tytuł wpisu. */ add_filter( 'the_content', function ( $html ) { if ( ! is_singular( 'post' ) || ! in_the_loop() || false === strpos( $html, '……
Podpis
- podpis ma pierwszeństwo. $html = preg_replace_callback( '#]*>(?:(?!).)*?]*>(.*?)\s*#su', function ( $m ) { $pod = trim( wp_strip_all_tags( $m[1] ) ); if ( '' === $pod ) { return $m[0]; } return preg_replace( '#(]*?)\salt=""#u', '$1 alt="' . esc_attr( $pod ) . '"', $m[0], 1 ); }, $html ); $html = preg_replace( '#(]*?)\salt=""#u', '$1 alt="' . esc_attr( $alt ) . '"', $html ); return preg_replace_callback( '#]*\balt=)[^>]*>#u', fn( $m ) => substr( $m[0], 0, 4 ) . ' alt="' . esc_attr( $alt ) . '"' . substr( $m[0], 4 ), $html ); }, 30 ); /** Zdjęcie główne na stronie wpisu (nagłówek) bez alt → tytuł wpisu. */ add_filter( 'post_thumbnail_html', function ( $html, $post_id ) { if ( ! $html || ! is_singular() || (int) $post_id !== (int) get_queried_object_id() || ! preg_match( '#\salt=""#', $html ) ) { return $html; } return preg_replace( '#\salt=""#', ' alt="' . esc_attr( wyjazdowo_alt_wpisu( (int) $post_id ) ) . '"', $html, 1 ); }, 10, 2 ); /* ============================== Opis meta ============================== */ /** Opis meta strony wyprawy: pierwszy akapit opisu, a bez niego zdanie z danych wyprawy (typ, rok, kraje). */ function wyjazdowo_meta_opis_wyprawy( int $id ): string { $w = function_exists( 'wyjazdowo_wyprawa_dane' ) ? wyjazdowo_wyprawa_dane( $id ) : null; if ( ! $w ) { return ''; } $tekst = ''; foreach ( parse_blocks( (string) get_post_field( 'post_content', $id ) ) as $b ) { if ( 'core/paragraph' === $b['blockName'] ) { $t = trim( preg_replace( '/\s+/u', ' ', wp_strip_all_tags( render_block( $b ) ) ) ); if ( mb_strlen( $t ) >= 50 ) { $tekst = $t; break; } } } if ( '' === $tekst ) { $nazwa = function_exists( 'wyjazdowo_wyprawa_nazwa' ) ? wyjazdowo_wyprawa_nazwa( $w + [ 'tytul' => get_the_title( $id ) ] ) : get_the_title( $id ); $nazwa = trim( preg_replace( '/\s*\b(19|20)\d\d\b\s*/u', ' ', $nazwa ) ); $brak = array_filter( $w['kraje'], fn( $k ) => false === mb_stripos( $nazwa, $k ) ); // kraje, których nie ma w nazwie $kraje = $brak ? ', ' . implode( ', ', $brak ) : ''; $ma = function_exists( 'wyjazdowo_wpisy_strony_wyprawy' ) && wyjazdowo_wpisy_strony_wyprawy( $id, false ); $glowa = in_array( $w['typ'], [ 'meska', 'mamowa' ], true ) ? sprintf( '%s (%d%s).', $nazwa, $w['rok'], $kraje ) : sprintf( 'Rodzinna wyprawa: %s %d%s.', $nazwa, $w['rok'], $kraje ); $tekst = $glowa . ' ' . ( $ma ? 'Relacje dzień po dniu, zdjęcia, trasa na mapie i kilometry całej wyprawy.' : 'Trasa na mapie, transport i kilometry wyprawy.' ); } return wyjazdowo_meta_przytnij( $tekst ); } /** * Opis meta wpisu (20.10.2026), gdy Rank Math nie ma opisu ani zajawki: pierwszy akapit treści (min. 50 znaków), * a we wpisach złożonych z samej galerii - zdanie z danych wyprawy: miejsce, wyprawa, numer wpisu, liczba zdjęć. */ function wyjazdowo_meta_opis_wpisu( int $id ): string { foreach ( parse_blocks( (string) get_post_field( 'post_content', $id ) ) as $b ) { if ( 'core/paragraph' !== $b['blockName'] ) { continue; } $t = trim( preg_replace( '/\s+/u', ' ', wp_strip_all_tags( render_block( $b ) ) ) ); if ( mb_strlen( $t ) >= 50 ) { return wyjazdowo_meta_przytnij( $t ); } } $miejsce = function_exists( 'wyjazdowo_wyprawy_krotki_tytul' ) ? wyjazdowo_wyprawy_krotki_tytul( $id ) : get_the_title( $id ); $miejsce = html_entity_decode( wp_strip_all_tags( $miejsce ), ENT_QUOTES, 'UTF-8' ); $w = function_exists( 'wyjazdowo_wyprawa_wpisu' ) ? wyjazdowo_wyprawa_wpisu( $id ) : null; $zdjecia = function_exists( 'wyjazdowo_liczba_zdjec' ) ? wyjazdowo_liczba_zdjec( $id ) : 0; $odm = ( $zdjecia % 10 >= 2 && $zdjecia % 10 <= 4 && ( $zdjecia % 100 < 12 || $zdjecia % 100 > 14 ) ) ? 'zdjęcia' : 'zdjęć'; $foto = $zdjecia >= 5 ? sprintf( '%d %s z drogi', $zdjecia, $odm ) : 'Zdjęcia z drogi'; if ( $w && ! empty( $w['tytul'] ) ) { $poz = array_search( $id, array_map( 'intval', (array) ( $w['ids'] ?? [] ) ), true ); $nr = false !== $poz ? sprintf( ' (wpis %d z %d)', $poz + 1, count( $w['ids'] ) ) : ''; $t = sprintf( '%s – relacja z rodzinnej wyprawy %s%s. %s, miejsce na mapie i trasa całej wyprawy.', $miejsce, $w['tytul'], $nr, $foto ); } else { $kraj = function_exists( 'wyjazdowo_kraj' ) ? wyjazdowo_kraj( $id ) : null; $t = sprintf( '%s%s – relacja z rodzinnej podróży. %s i miejsce na mapie.', $miejsce, $kraj ? ', ' . $kraj->name : '', $foto ); } return wyjazdowo_meta_przytnij( $t ); } function wyjazdowo_meta_przytnij( string $t, int $max = 160 ): string { $t = trim( $t ); if ( mb_strlen( $t ) <= $max ) { return $t; } $c = mb_substr( $t, 0, $max - 1 ); $c = preg_replace( '/[\s,;:–—-]+[^\s]*$/u', '', $c ); return rtrim( $c, " ,;:–—-" ) . '…'; } const WYJAZDOWO_OPIS_BLOGA = 'Wszystkie relacje z naszych rodzinnych wypraw: dzień po dniu, z trasą na mapie, zdjęciami i komentarzami całej ekipy. Europa, Azja, Ameryka i Afryka.'; add_filter( 'rank_math/frontend/description', function ( $d ) { if ( '' !== trim( (string) $d ) ) { return $d; } if ( is_home() ) { return WYJAZDOWO_OPIS_BLOGA; } if ( is_page() && ( $o = wyjazdowo_meta_opis_wyprawy( (int) get_queried_object_id() ) ) ) { return $o; } if ( is_singular( 'post' ) && ( $o = wyjazdowo_meta_opis_wpisu( (int) get_queried_object_id() ) ) ) { return $o; } return $d; } ); /* ============================== Schema ============================== */ add_filter( 'rank_math/json_ld', function ( $data ) { if ( ! is_array( $data ) ) { return $data; } // sameAs organizacji/osoby: profile z ustawień kontaktu. $profile = function_exists( 'wyjazdowo_kontakt' ) ? array_values( array_filter( array_column( wyjazdowo_kontakt()['profile'], 'url' ) ) ) : []; if ( $profile ) { foreach ( $data as &$n ) { if ( is_array( $n ) && isset( $n['@id'] ) && ( str_ends_with( (string) $n['@id'], '/#person' ) || str_ends_with( (string) $n['@id'], '/#organization' ) ) ) { $n['sameAs'] = $profile; } } unset( $n ); } if ( ! is_page() || ! function_exists( 'wyjazdowo_wyprawa_dane' ) ) { return $data; } $id = (int) get_queried_object_id(); $w = wyjazdowo_wyprawa_dane( $id ); if ( ! $w ) { return $data; } foreach ( $data as $k => $n ) { if ( ! is_array( $n ) || ! isset( $n['@id'] ) || ! str_ends_with( (string) $n['@id'], '#richSnippet' ) ) { continue; } $url = get_permalink( $id ); $trip = [ '@type' => 'TouristTrip', '@id' => $n['@id'], 'name' => html_entity_decode( get_the_title( $id ), ENT_QUOTES, 'UTF-8' ), 'description' => wyjazdowo_meta_opis_wyprawy( $id ), 'url' => $url, 'inLanguage' => 'pl-PL', 'touristType' => [ 'meska' => 'Ojciec z synami', 'mamowa' => 'Mama z synami' ][ $w['typ'] ] ?? 'Rodzina z dziećmi', 'mainEntityOfPage' => [ '@id' => $url . '#webpage' ], 'provider' => [ '@id' => home_url( '/#organization' ) ], ]; if ( ! empty( $n['image'] ) ) { $trip['image'] = $n['image']; } if ( $w['rok'] ) { $trip['temporalCoverage'] = (string) $w['rok']; } $dom = function_exists( 'wyjazdowo_transport_dom' ) ? wyjazdowo_transport_dom() : null; if ( $dom ) { $trip['tripOrigin'] = [ '@type' => 'Place', 'name' => $dom['m'] ?? 'Warszawa' ]; } $el = []; if ( function_exists( 'wyjazdowo_trasa_strony' ) ) { foreach ( wyjazdowo_trasa_strony( $id, false ) as $x ) { if ( ! empty( $x['dom'] ) || empty( $x['p'] ) ) { continue; } $pl = [ '@type' => 'Place', 'name' => (string) $x['m'], 'geo' => [ '@type' => 'GeoCoordinates', 'latitude' => $x['p'][0], 'longitude' => $x['p'][1] ] ]; if ( ! empty( $x['w'] ) ) { $pl['url'] = get_permalink( (int) $x['w'] ); } $el[] = [ '@type' => 'ListItem', 'position' => count( $el ) + 1, 'item' => $pl ]; } } if ( $el ) { $trip['itinerary'] = [ '@type' => 'ItemList', 'numberOfItems' => count( $el ), 'itemListElement' => $el ]; } if ( $w['czesc'] ) { $trip['partOfTrip'] = [ '@type' => 'TouristTrip', 'url' => get_permalink( $w['czesc'] ) ]; } $data[ $k ] = $trip; break; } return $data; }, 999 ); // po Rank Math (dokłada richSnippet z wysokim priorytetem) /* ============================== Kontynenty: strony zamiast kategorii ============================== */ /** Kategorie, które mają własną stronę (slug kategorii => ścieżka strony). Archiwum kategorii przekierowuje na stronę. */ function wyjazdowo_kategorie_stron(): array { // Wydajność (19.10.2026): mapa liczona raz na żądanie i trzymana w cache razem z danymi wypraw // (filtr stron krajów szuka kategorii 33 krajów — bez cache to setki zapytań na każdą stronę z kartami). static $mem = null; if ( null !== $mem ) { return $mem; } $klucz = 'wy_kat_stron_' . ( function_exists( 'wyjazdowo_wyprawy_wersja' ) ? wyjazdowo_wyprawy_wersja() : 0 ); $c = get_transient( $klucz ); if ( is_array( $c ) ) { return $mem = $c; } $mem = apply_filters( 'wyjazdowo_kategorie_stron', [ 'europa' => 'europa', 'azja-wyjazdy' => 'azja', 'ameryka' => 'ameryka', 'afryka' => 'afryka', 'polska' => 'europa/polska', 'meski-wyjazd' => 'trzy-czwarte/meskie', ] ); set_transient( $klucz, $mem, DAY_IN_SECONDS ); return $mem; } function wyjazdowo_strona_kategorii( $term ): string { static $mem = []; if ( ! $term instanceof WP_Term || 'category' !== $term->taxonomy ) { return ''; } if ( isset( $mem[ $term->slug ] ) ) { return $mem[ $term->slug ]; } $sciezka = wyjazdowo_kategorie_stron()[ $term->slug ] ?? ''; if ( '' === $sciezka ) { return $mem[ $term->slug ] = ''; } $p = get_page_by_path( $sciezka ); return $mem[ $term->slug ] = ( $p && 'publish' === $p->post_status ) ? get_permalink( $p ) : ''; } add_filter( 'term_link', function ( $link, $term ) { if ( is_admin() && ! wp_doing_ajax() ) { return $link; } // kokpit: zwykłe linki kategorii $u = wyjazdowo_strona_kategorii( $term ); return $u ?: $link; }, 30, 2 ); add_action( 'template_redirect', function () { if ( ! is_category() || is_feed() || is_admin() ) { return; } $u = wyjazdowo_strona_kategorii( get_queried_object() ); if ( $u ) { wp_safe_redirect( $u, 301 ); exit; } }, 5 ); /** Mapa witryny: bez kategorii, które przekierowują na stronę (strona jest już w page-sitemap). */ add_filter( 'rank_math/sitemap/entry', function ( $url, $type, $obj ) { return ( 'term' === $type && $obj instanceof WP_Term && wyjazdowo_strona_kategorii( $obj ) ) ? false : $url; }, 20, 3 ); /* * Zwykłe strony (20.10.2026): Rank Math daje im BlogPosting (domyślny typ stron = artykuł, potrzebny, bo z tego węzła * powstają TouristTrip wypraw i dane stron krajów). Gdy węzeł nadal jest artykułem - usuwamy go, strona zostaje WebPage * wydawcy Wyjazdowo; znika też osierocony węzeł autora. */ add_filter( 'rank_math/json_ld', function ( $data ) { if ( ! is_array( $data ) || ! is_page() || is_front_page() ) { return $data; } $usuniety = false; foreach ( $data as $k => $n ) { if ( ! is_array( $n ) || ! str_ends_with( (string) ( $n['@id'] ?? '' ), '#richSnippet' ) ) { continue; } if ( array_intersect( (array) ( $n['@type'] ?? [] ), [ 'BlogPosting', 'Article', 'NewsArticle' ] ) ) { unset( $data[ $k ] ); $usuniety = true; } } if ( $usuniety ) { $json = wp_json_encode( $data ); foreach ( $data as $k => $n ) { if ( is_array( $n ) && 'Person' === ( $n['@type'] ?? '' ) && ! empty( $n['@id'] ) && substr_count( $json, '"' . str_replace( '/', '\/', $n['@id'] ) . '"' ) <= 1 ) { unset( $data[ $k ] ); } } } return $data; }, 1000 ); // wyjazdowo_schema_stron_bez_artykulu - po zamianie na TouristTrip (999) /** * Rank Math: spis treści wpisu renderuje blok wyjazdowo/panel-boczny (z nagłówków H2/H3), * więc analiza treści ma traktować wtyczkę wyjazdowo-blocks jako wtyczkę spisu treści. */ add_filter( 'rank_math/researches/toc_plugins', function ( $wtyczki ) { $wtyczki['wyjazdowo-blocks/wyjazdowo-blocks.php'] = 'Wyjazdowo – spis treści'; return $wtyczki; } ); Nina — Ekipa Wyjazdowo - Wyjazdowo
NinaEkipa Wyjazdowo

Szefowa wszystkich szefów

Nina

„Dobra przygoda zaczyna się od przekąski.”

Wyprawy
42
Kraje
28
Km w drodze
335 897
Loty
96

W drodze od 2003 roku

Parametry postaci

Odporność na zmęczenie4/54/5
Entuzjazm o 5 rano2/52/5
Jedzenie lokalne4/54/5
Jeszcze tylko 2 km3/53/5
Spanie w podróży4/54/5
Pora na przekąskę5/55/5

✦ Mocna stronaSpokój w plecaku. I coś na mały głód.

⚑ Klątwa podróżnikaPamięta wszystkie „ostatnie” dwa kilometry.

O mnie

Szefowa wszystkich szefów, również tego, któremu wydaje się, że prowadzi ekspedycję. W plecaku ma spokój, przekąski i ograniczoną cierpliwość do kolejnych „ostatnich dwóch kilometrów”. Pamięta, kto jadł, kto nie jadł i kto za chwilę zacznie twierdzić, że umiera z głodu. Potrafi sprowadzić ambitny plan zwiedzania do rzeczywistości jednym pytaniem: „A kiedy właściwie zjemy?”. Dzięki niej nasze wyprawy mają szansę zakończyć się wspólnym powrotem, bez konieczności wymieniania części ekipy.

Moje wyprawy z wyjazdowo

Każda wyprawa dopisuje kolejny rozdział. Tutaj znajdziesz podróże, w których biorę udział — miejsca, wspomnienia i relacje ze szlaku.

Mapa odwiedzonych miejsc — Nina
  1. Chorwacja
  2. Chorwacja
  3. Tunezja
  4. Litwa
  5. Indie
  6. Chorwacja
  7. Chiny
  8. Gruzja
  9. Meksyk
  10. Francja
  11. Norwegia
  12. Szkocja
  13. Indonezja
  14. Czechy
  15. Białoruś
  16. Gruzja
  17. Hiszpania – Lanzarote
  18. Chorwacja
  19. Gruzja i Armenia
  20. Włochy – Mediolan
  21. Włochy – Toskania
  22. Tajlandia
  23. Grecja – Zakynthos
  24. Tajlandia
  25. Iran
  26. Białoruś
  27. Cypr
  28. Jordania
  29. Finlandia
  30. Gruzja
  31. I Mamowy wyjazd – Węgry
  32. Finlandia – Rovaniemi
  33. Turcja
  34. Czechy – Praga
  35. Włochy – Sycylia
  36. Egipt
  37. Islandia
  38. III Mamowy wyjazd – Egipt
  39. Chile i Argentyna
  40. IV Mamowy wyjazd – Alicante
  41. Chiny
  42. V Mamowy wyjazd – Alicante

Jeszcze tyle świata

Marzenia na kolejne wyprawy i te, które już udało się spełnić.

  • PeruMarzenie
  • JaponiaMarzenie
  • WietnamMarzenie
  • KambodżaMarzenie
  • Korea PołudniowaMarzenie
  • KubaMarzenie
  • BrazyliaMarzenie
  • RPAMarzenie
  • Islandia✓ Zrobione · 2024
  • Chiny✓ Zrobione · 2025
Cała lista marzeń ↗

Świat moim okiem