Manual hreflang Links for Translated Pages
Adds a box to the editor where you list the URLs of a page's translations; the matching hreflang tags (plus x-default) are printed in the page head, for multilingual sites that do not use a translation plugin.
Opens WPIDE on
Code
add_action( 'add_meta_boxes', function () {
add_meta_box( 'wpide-hreflang', __( 'Translations (hreflang)' ), function ( $post ) {
wp_nonce_field( 'wpide_hreflang_save', 'wpide_hreflang_nonce' );
printf(
'<textarea name="wpide_hreflang" rows="4" style="width:100%%" placeholder="en https://example.com/page/
fr https://example.com/fr/page/">%s</textarea>',
esc_textarea( get_post_meta( $post->ID, '_wpide_hreflang', true ) )
);
}, array( 'post', 'page' ), 'side' );
} );
add_action( 'save_post', function ( $post_id ) {
if ( ! isset( $_POST['wpide_hreflang_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['wpide_hreflang_nonce'] ), 'wpide_hreflang_save' ) || ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
$lines = array();
foreach ( preg_split( '/\R/', (string) wp_unslash( $_POST['wpide_hreflang'] ?? '' ) ) as $line ) {
$parts = preg_split( '/\s+/', trim( $line ), 2 );
if ( 2 === count( $parts ) && preg_match( '/^([a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})?|x-default)$/', $parts[0] ) && wp_http_validate_url( $parts[1] ) ) {
$lines[] = $parts[0] . ' ' . esc_url_raw( $parts[1] );
}
}
update_post_meta( $post_id, '_wpide_hreflang', implode( "\n", $lines ) );
} );
add_action( 'wp_head', function () {
if ( ! is_singular() ) {
return;
}
$raw = get_post_meta( get_queried_object_id(), '_wpide_hreflang', true );
foreach ( array_filter( explode( "\n", (string) $raw ) ) as $line ) {
list( $lang, $url ) = array_pad( explode( ' ', $line, 2 ), 2, '' );
if ( $url ) {
printf( '<link rel="alternate" hreflang="%1$s" href="%2$s">' . "\n", esc_attr( $lang ), esc_url( $url ) );
}
}
}, 2 );
Notes
One per line, as language code, a space, then the URL (e.g. "fr https://example.com/fr/page/"). Add "x-default URL" for the fallback version. List the page itself too.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.