Thay đổi tiêu đề trang WordPress

Cập nhật lần cuối vào

Bài này mình sẽ hướng dẫn cho các bạn cách thay đổi tiêu đề cho trang của WordPress thông qua các bộ lọc có sẵn. Mục đích là để bạn viết lại thẻ title phù hợp với SEO hoặc bạn cập nhật thêm những thông tin liên quan khác trong này ngoài tiêu đề mặc định của đối tượng.

Thẻ title HTML

Đầu tiên thì bạn sẽ xem qua các hàm mà WordPress hỗ trợ từ phiên bản 4.4 trở về sau. Trong phiên bản WordPress 4.4 thì WordPress đã hỗ trợ giao diện support title-tag, nếu giao diện có sử dụng add_theme_supports('title-tag'); để thêm tính năng tự động tạo thẻ title ở phần head thì bạn sẽ áp dụng được các bộ lọc liên quan.

/**
 * Displays title tag with content.
 *
 * @ignore
 * @since 4.1.0
 * @since 4.4.0 Improved title output replaced `wp_title()`.
 * @access private
 */
function _wp_render_title_tag() {
	if ( ! current_theme_supports( 'title-tag' ) ) {
		return;
	}

	echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}

Hàm bên trên sẽ có chức năng xuất thẻ title ra giữa thẻ head nếu giao diện có hỗ trợ tính năng title-tag. Như bạn thấy trong đoạn code bên trên thì WordPress sử dụng hàm wp_get_document_title() để lấy thông tin tiêu đề trang hiện tại.

/**
 * Returns document title for the current page.
 *
 * @since 4.4.0
 *
 * @global int $page  Page number of a single post.
 * @global int $paged Page number of a list of posts.
 *
 * @return string Tag with the document title.
 */
function wp_get_document_title() {

	/**
	 * Filter the document title before it is generated.
	 *
	 * Passing a non-empty value will short-circuit wp_get_document_title(),
	 * returning that value instead.
	 *
	 * @since 4.4.0
	 *
	 * @param string $title The document title. Default empty string.
	 */
	$title = apply_filters( 'pre_get_document_title', '' );
	if ( ! empty( $title ) ) {
		return $title;
	}

	global $page, $paged;

	$title = array(
		'title' => '',
	);

	// If it's a 404 page, use a "Page not found" title.
	if ( is_404() ) {
		$title['title'] = __( 'Page not found' );

	// If it's a search, use a dynamic search results title.
	} elseif ( is_search() ) {
		/* translators: %s: search phrase */
		$title['title'] = sprintf( __( 'Search Results for “%s”' ), get_search_query() );

	// If on the front page, use the site title.
	} elseif ( is_front_page() ) {
		$title['title'] = get_bloginfo( 'name', 'display' );

	// If on a post type archive, use the post type archive title.
	} elseif ( is_post_type_archive() ) {
		$title['title'] = post_type_archive_title( '', false );

	// If on a taxonomy archive, use the term title.
	} elseif ( is_tax() ) {
		$title['title'] = single_term_title( '', false );

	/*
	 * If we're on the blog page that is not the homepage or
	 * a single post of any post type, use the post title.
	 */
	} elseif ( is_home() || is_singular() ) {
		$title['title'] = single_post_title( '', false );

	// If on a category or tag archive, use the term title.
	} elseif ( is_category() || is_tag() ) {
		$title['title'] = single_term_title( '', false );

	// If on an author archive, use the author's display name.
	} elseif ( is_author() && $author = get_queried_object() ) {
		$title['title'] = $author->display_name;

	// If it's a date archive, use the date as the title.
	} elseif ( is_year() ) {
		$title['title'] = get_the_date( _x( 'Y', 'yearly archives date format' ) );

	} elseif ( is_month() ) {
		$title['title'] = get_the_date( _x( 'F Y', 'monthly archives date format' ) );

	} elseif ( is_day() ) {
		$title['title'] = get_the_date();
	}

	// Add a page number if necessary.
	if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() ) {
		$title['page'] = sprintf( __( 'Page %s' ), max( $paged, $page ) );
	}

	// Append the description or site title to give context.
	if ( is_front_page() ) {
		$title['tagline'] = get_bloginfo( 'description', 'display' );
	} else {
		$title['site'] = get_bloginfo( 'name', 'display' );
	}

	/**
	 * Filter the separator for the document title.
	 *
	 * @since 4.4.0
	 *
	 * @param string $sep Document title separator. Default '-'.
	 */
	$sep = apply_filters( 'document_title_separator', '-' );

	/**
	 * Filter the parts of the document title.
	 *
	 * @since 4.4.0
	 *
	 * @param array $title {
	 *     The document title parts.
	 *
	 *     @type string $title   Title of the viewed page.
	 *     @type string $page    Optional. Page number if paginated.
	 *     @type string $tagline Optional. Site description when on home page.
	 *     @type string $site    Optional. Site title when not on home page.
	 * }
	 */
	$title = apply_filters( 'document_title_parts', $title );

	$title = implode( " $sep ", array_filter( $title ) );
	$title = wptexturize( $title );
	$title = convert_chars( $title );
	$title = esc_html( $title );
	$title = capital_P_dangit( $title );

	return $title;
}

Như vậy, cái bạn cần thay đổi đó là kết quả trả về của hàm wp_get_document_title(), trong hàm này thì WordPress sử dụng 2 bộ lọc, cho phép bạn lọc kết quả trước và sau khi lấy title.

1. pre_get_document_title:
Đây là bộ lọc trước khi WordPress lấy thẻ title, nếu sau khi dùng bộ lọc này mà kết quả trả về là có giá trị khác rỗng thì hàm sẽ lấy giá trị trả về từ bộ lọc.

2. document_title_parts: Đây là bộ lọc sau khi thẻ title và các thành phần khác liên quan được lấy, kết quả sẽ là một mảng các giá trị, nếu bạn thay đổi nội dung của tiêu đề thì bạn sẽ dùng theo kiểu truy xuất mảng $title['title'].

Ngoài ra, trong hàm còn có sử dụng bộ lọc document_title_separator để thay đổi ký tự phân cách giữa các thành phần trong thẻ tiêu đề.

Bây giờ bạn sẽ thử dùng bộ lọc document_title_parts trước:

function hocwp_theme_custom_title_date( $title ) {
	if ( ! is_home() ) {
		if ( is_tax( 'store' ) ) {
			$title['title'] .= ' ' . date( 'F Y' );
		}
	}

	return $title;
}

add_filter( 'document_title_parts', 'hocwp_theme_custom_title_date', 99 );

Trong hàm bên trên, mình tạo bộ lọc để lọc thẻ tiêu đề, tự động thêm tháng năm vào sau tiêu đề cho trang lưu trữ các chuyên mục thuộc taxonomy store. Như bạn thấy trong đoạn code này, giá trị đầu vào là một mảng chứa các thành phần của tiêu đề, bạn chỉ cần chỉnh sửa nội dung chữ ở key title trong mảng.

function hocwp_theme_custom_pre_document_title( $title ) {
	if ( ! is_home() ) {
		if ( is_tax( 'store' ) ) {
			$title = single_term_title( '', false ) . ' ' . date( 'F Y' );
		}
	}

	return $title;
}

add_filter( 'pre_get_document_title', 'hocwp_theme_custom_pre_document_title', 99 );

Trong đoạn code ví dụ thứ 2 bên trên, bạn sẽ trả về một giá trị là chuỗi tiêu đề bằng cách sử dụng bộ lọc pre_get_document_title, lúc đầu tiêu đề đầu vào là giá trị rỗng nếu chưa có bộ lọc nào khác phía trước thay đổi nội dung của biến. Và dĩ nhiên thì bạn phải kiểm tra các hàm điều kiện của WordPress để biết trang hiện tại là gì, từ đó mới lấy thông tin thích hợp gán cho thẻ tiêu đề.

Lọc tiêu đề đối với phiên bản WordPress cũ

Trong phiên bản WordPress 4.3 trở về trước thì WordPress sẽ sử dụng hàm wp_title để xuất tiêu đề. Để thay đổi được thông tin tiêu đề ở các phiên bản cũ này thì bạn phải xem qua nội dung của hàm wp_title trước nhé.

/**
 * Display or retrieve page title for all areas of blog.
 *
 * By default, the page title will display the separator before the page title,
 * so that the blog title will be before the page title. This is not good for
 * title display, since the blog title shows up on most tabs and not what is
 * important, which is the page that the user is looking at.
 *
 * There are also SEO benefits to having the blog title after or to the 'right'
 * or the page title. However, it is mostly common sense to have the blog title
 * to the right with most browsers supporting tabs. You can achieve this by
 * using the seplocation parameter and setting the value to 'right'. This change
 * was introduced around 2.5.0, in case backwards compatibility of themes is
 * important.
 *
 * @since 1.0.0
 *
 * @global WP_Locale $wp_locale
 *
 * @param string $sep         Optional, default is '&raquo;'. How to separate the various items
 *                            within the page title.
 * @param bool   $display     Optional, default is true. Whether to display or retrieve title.
 * @param string $seplocation Optional. Direction to display title, 'right'.
 * @return string|null String on retrieve, null when displaying.
 */
function wp_title( $sep = '&raquo;', $display = true, $seplocation = '' ) {
	global $wp_locale;

	$m        = get_query_var( 'm' );
	$year     = get_query_var( 'year' );
	$monthnum = get_query_var( 'monthnum' );
	$day      = get_query_var( 'day' );
	$search   = get_query_var( 's' );
	$title    = '';

	$t_sep = '%WP_TITLE_SEP%'; // Temporary separator, for accurate flipping, if necessary

	// If there is a post
	if ( is_single() || ( is_home() && ! is_front_page() ) || ( is_page() && ! is_front_page() ) ) {
		$title = single_post_title( '', false );
	}

	// If there's a post type archive
	if ( is_post_type_archive() ) {
		$post_type = get_query_var( 'post_type' );
		if ( is_array( $post_type ) ) {
			$post_type = reset( $post_type );
		}
		$post_type_object = get_post_type_object( $post_type );
		if ( ! $post_type_object->has_archive ) {
			$title = post_type_archive_title( '', false );
		}
	}

	// If there's a category or tag
	if ( is_category() || is_tag() ) {
		$title = single_term_title( '', false );
	}

	// If there's a taxonomy
	if ( is_tax() ) {
		$term = get_queried_object();
		if ( $term ) {
			$tax   = get_taxonomy( $term->taxonomy );
			$title = single_term_title( $tax->labels->name . $t_sep, false );
		}
	}

	// If there's an author
	if ( is_author() && ! is_post_type_archive() ) {
		$author = get_queried_object();
		if ( $author ) {
			$title = $author->display_name;
		}
	}

	// Post type archives with has_archive should override terms.
	if ( is_post_type_archive() && $post_type_object->has_archive ) {
		$title = post_type_archive_title( '', false );
	}

	// If there's a month
	if ( is_archive() && ! empty( $m ) ) {
		$my_year  = substr( $m, 0, 4 );
		$my_month = $wp_locale->get_month( substr( $m, 4, 2 ) );
		$my_day   = intval( substr( $m, 6, 2 ) );
		$title    = $my_year . ( $my_month ? $t_sep . $my_month : '' ) . ( $my_day ? $t_sep . $my_day : '' );
	}

	// If there's a year
	if ( is_archive() && ! empty( $year ) ) {
		$title = $year;
		if ( ! empty( $monthnum ) ) {
			$title .= $t_sep . $wp_locale->get_month( $monthnum );
		}
		if ( ! empty( $day ) ) {
			$title .= $t_sep . zeroise( $day, 2 );
		}
	}

	// If it's a search
	if ( is_search() ) {
		/* translators: 1: separator, 2: search phrase */
		$title = sprintf( __( 'Search Results %1$s %2$s' ), $t_sep, strip_tags( $search ) );
	}

	// If it's a 404 page
	if ( is_404() ) {
		$title = __( 'Page not found' );
	}

	$prefix = '';
	if ( ! empty( $title ) ) {
		$prefix = " $sep ";
	}

	/**
	 * Filter the parts of the page title.
	 *
	 * @since 4.0.0
	 *
	 * @param array $title_array Parts of the page title.
	 */
	$title_array = apply_filters( 'wp_title_parts', explode( $t_sep, $title ) );

	// Determines position of the separator and direction of the breadcrumb
	if ( 'right' == $seplocation ) { // sep on right, so reverse the order
		$title_array = array_reverse( $title_array );
		$title       = implode( " $sep ", $title_array ) . $prefix;
	} else {
		$title = $prefix . implode( " $sep ", $title_array );
	}

	/**
	 * Filter the text of the page title.
	 *
	 * @since 2.0.0
	 *
	 * @param string $title Page title.
	 * @param string $sep Title separator.
	 * @param string $seplocation Location of the separator (left or right).
	 */
	$title = apply_filters( 'wp_title', $title, $sep, $seplocation );

	// Send it out
	if ( $display ) {
		echo $title;
	} else {
		return $title;
	}
}

Trong hàm bên trên sẽ có 2 bộ lọc chính cho bạn sử dụng đó là: wp_title_partswp_title. Cách sử dụng cũng tương tự như các ví dụ mình gửi ở đầu bài. Với bộ lọc wp_title_parts thì giá trị đầu vào và kết quả đầu ra là một mảng, còn bộ lọc wp_title thì cả đầu vào và đầu tra đều là giá trị kiểu chuỗi.

Khi áp dụng các bộ lọc để thay đổi thẻ tiêu đề của trang WordPress thì bạn sẽ kiểm tra xem phiên bản WordPress đang dùng là bao nhiêu, có hỗ trợ filter bạn định dùng hay không, từ đó mới áp dụng chọn bộ lọc nào cho thích hợp. Chúc bạn thành công.

Theo dõi
Thông báo của
guest

4 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất
Phản hồi nội tuyến
Xem tất cả bình luận
goldmark city
6 năm trước

bài chia sẻ rất hay. cảm ơn bạn

Nam Hải
4 năm trước

thay đổi tiêu đề cũng khá phưc tạp đối với người mới như mình, mình sẽ nghiên cứu thêm nữa rồi sẽ áp dụng xem sao.

Toancr
10 tháng trước

đúng cái mình đang cần, thank ad nhé