Aktualizacja:
Poniższe rozwiązanie dotyczy problemu, który wydaje się powstawać wyłącznie gdy w panelu administracyjnym w ustawienia/stałe linki użyjemy opcji /blog/%postname%/, wystarczy jednak zmienić na /blog/%year%/%postname%/ by problem rozwiązał się sam.


Temat wydaje się być banalny, bo dzieje się to niby automatycznie. W pewnych jednak sytuacjach automatyka zawodzi i trzeba wordpressowi zaaplikować coś ręcznie. (wpis dotyczy WordPressa w wersji 2.7.1 z włączonym mod_rewrite)

posts_nav_link()

Problem pojawił się, gdy ilość wpisów na stronie przekroczyła tę zadaną w ustawieniach. Oczywiście pojawił się link do starszych wpisów, jego semantyczna postać była poprawna, natomiast efekt – 404.

Błąd prawdopodobnie nie wyskoczyłby gdyby adres bloga był główną domeną. W omawianym przypadku pod adresem http://jakaś-strona.pl stoi strona firmowa, natomiast adres bloga to http://jakaś-strona.pl/blog. Z punktu widzenia logiki, paginacja stron powinna wyglądać np. http://jakaś-strona.pl/blog/page/2, taki też adres generowała funkcja posts_nav_link(), która to użyta jest w templatce pliku index.php. Jednakże wynikiem kliknięcia w link była strona błędu 404.

Przy powyższym podziale ról na stronie, właściwym adresem pozostałych stron wpisów jest np. http://jakaś-strona.pl/page/2 i taką też postać powinno się w linku uzyskać. Jest to rozwiązanie niezbyt eleganckie, ulatujące w niebyt po każdej aktualizacji WordPressa, ale działające w tym konkretnym przypadku.

.htaccess

Pozwoliłem by posts_nav_link() po swojemu generował sobie link, natomiast do odcięcia części /blog zatrudniłem plik .htaccess, w którym należy dodać:


RewriteRule ^.*blog/page/(.*)$ http://inite.pl/page/$1 [L]

reguła ta wyczyści wszystko co zawiera cośtam/page/ i przepisze na właściwy adres zostawiając jedynie numer strony. Czyli mamy dokładnie to o co chodziło. Stronicowanie wstecz działa poprawnie.

get_pagenum_link()

Zgodnie z prawami Murphiego rozwiązanie jednego błędu skutkuje pojawieniem się następnych. :)
Nawigacja działa poprawnie z wyjątkiem przejścia ze strony drugiej do pierwszej, czyli frontowej. Dotychczasowe zmiany doprowadziły do tego, że link do pierwszej strony zamiast do http://jakaś-strona.pl/blog/ kieruje do http://jakaś-strona.pl/ .
Obejście tego wymaga już ingerencji w kod pliku /wp-includes/link-template.php a konkretnie funkcji get_pagenum_link().


function get_pagenum_link($pagenum = 1) {
	global $wp_rewrite;
	$pagenum = (int) $pagenum;
	$request = remove_query_arg( 'paged' );
	$home_root = parse_url(get_option('home'));
	$home_root = ( isset($home_root['path']) ) ? $home_root['path'] : '';
	$home_root = preg_quote( trailingslashit( $home_root ), '|' );
	$request = preg_replace('|^'. $home_root . '|', '', $request);
	$request = preg_replace('|^/+|', '', $request);
	if ( !$wp_rewrite->using_permalinks() || is_admin() ) {
		$base = trailingslashit( get_bloginfo( 'home' ) );
		if ( $pagenum > 1 ) {
			$result = add_query_arg( 'paged', $pagenum, $base . $request );
		} else {
			$result = $base . $request;
		}
	} else {
		$qs_regex = '|\?.*?$|';
		preg_match( $qs_regex, $request, $qs_match );
		if ( !empty( $qs_match[0] ) ) {
			$query_string = $qs_match[0];
			$request = preg_replace( $qs_regex, '', $request );
		} else {
			$query_string = '';
		}
		$request = preg_replace( '|page/\d+/?$|', '', $request);
		$request = preg_replace( '|^index\.php|', '', $request);
		$request = ltrim($request, '/');
		$base = trailingslashit( get_bloginfo( 'url' ) );
		if ( $wp_rewrite->using_index_permalinks() && ( $pagenum > 1 || '' != $request ) )
			$base .= 'index.php/';
		if ( $pagenum > 1 ) {
			$request = ( ( !empty( $request ) ) ? trailingslashit( $request ) : $request ) . user_trailingslashit( 'page/' . $pagenum, 'paged' );
		}
		$result = $base . $request . $query_string;
	}
	$result = apply_filters('get_pagenum_link', $result);
	return $result;
}

Zaznaczoną na czerwono linię (u mnie 1020) zmieniamy na:

$base = trailingslashit( get_bloginfo( 'url' ) . "/blog" );

Teraz, co prawna link do starszych wpisów na głównej stronie bloga ma u mnie postać http://jakaś-strona.pl/blog/blog/page/2, ale i tak jest przycinany przez .htaccess, a działa także w drugą stronę, generując poprawny link z drugiej strony wpisów do głównej (pierwszej) strony bloga.

.htaccess – druga zmiana

W myśl przytoczonego już prawa Murphiego po powyższej zmianie przestają działać linki w archiwum, czyli te mające postać np. http://jakaś-strona.pl/blog/blog/2009/03/page/2. rozwiązaniem jest kolejna linijka w .htaccess:


RewriteRule ^.*blog/blog/([0-9]*)/(.*)$ http://inite.pl/blog/$1/$2 [L]

Teraz każdy link mający na początku /blog/blog/xxx/yyy gdzie xxx to cyfry, a yyy cokolwiek co może ale nie musi wystąpić, będzie zamieniany na /blog/xxx/yyy.

Tagged with →  
Share →

One Response to Stronicowanie wpisów w WordPressie

  1. Ad4m pisze:

    Osobiście miałem błąd ze stronicowaniem i dało się go rozwiązać wtyczką do wp bez większego kombinowania. Może komuś się przyda http://worth-it.pl/index.php/darmowe/wordpress-jak-naprawic-bledy-404-przy-paginacji/