Greeklish addresses for Greek titles
New posts, pages, products, categories and tags with Greek titles get addresses in Latin letters: “Καλοκαιρινά φορέματα” becomes kalokairina-foremata. Existing addresses don’t change.
<?php
// Greek letters in the addresses (slugs) WordPress makes for new posts,
// pages, products and terms become Latin letters. Other text, other slugs and
// addresses that already exist are left as they are.
$greeklish = static function ( string $text ): string {
return (string) preg_replace_callback(
'/\p{Greek}+/u',
static function ( array $m ): string {
$word = strtr( mb_strtolower( $m[0], 'UTF-8' ), array( 'ου' => 'ou', 'ού' => 'ou' ) );
return strtr(
$word,
array(
'α' => 'a', 'ά' => 'a', 'β' => 'v', 'γ' => 'g', 'δ' => 'd', 'ε' => 'e', 'έ' => 'e',
'ζ' => 'z', 'η' => 'i', 'ή' => 'i', 'θ' => 'th', 'ι' => 'i', 'ί' => 'i', 'ϊ' => 'i',
'ΐ' => 'i', 'κ' => 'k', 'λ' => 'l', 'μ' => 'm', 'ν' => 'n', 'ξ' => 'x', 'ο' => 'o',
'ό' => 'o', 'π' => 'p', 'ρ' => 'r', 'σ' => 's', 'ς' => 's', 'τ' => 't', 'υ' => 'y',
'ύ' => 'y', 'ϋ' => 'y', 'ΰ' => 'y', 'φ' => 'f', 'χ' => 'ch', 'ψ' => 'ps', 'ω' => 'o',
'ώ' => 'o',
)
);
},
$text
);
};
// WordPress cuts %-encoded slugs at 200 characters (a few dozen Greek letters),
// so the title or name the slug was made from is kept to transliterate in full.
$source = '';
add_filter(
'wp_insert_post_empty_content',
static function ( $maybe_empty, $postarr = array() ) use ( &$source ) {
$source = (string) ( $postarr['post_title'] ?? '' );
return $maybe_empty;
},
10,
2
);
add_filter(
'pre_insert_term',
static function ( $term ) use ( &$source ) {
$source = is_string( $term ) ? $term : '';
return $term;
}
);
// A slug with Greek letters (WordPress stores them %-encoded) in Latin letters,
// or null when there's nothing to change.
$latin_slug = static function ( string $slug ) use ( $greeklish, &$source ): ?string {
$decoded = urldecode( $slug );
if ( ! preg_match( '/\p{Greek}/u', $decoded ) ) {
return null;
}
if ( '' !== $source && '' !== $slug && str_starts_with( sanitize_title_with_dashes( $source, '', 'save' ), $slug ) ) {
$decoded = $source; // The slug was made from this text: use all of it.
}
$latin = sanitize_title_with_dashes( $greeklish( $decoded ), '', 'save' );
return '' === $latin ? null : $latin;
};
// Posts, pages, products…: when WordPress makes a post's address unique.
$post_slug = null;
$post_slug = static function ( $slug, $post_id = 0, $status = '', $type = '', $parent = 0 ) use ( $latin_slug, &$post_slug ) {
if ( $post_id && '' !== (string) get_post_field( 'post_name', $post_id ) && get_post_field( 'post_name', $post_id ) === $slug ) {
return $slug; // An address the post already has stays.
}
$latin = $latin_slug( (string) $slug );
if ( null === $latin ) {
return $slug;
}
remove_filter( 'wp_unique_post_slug', $post_slug, 10 );
$slug = wp_unique_post_slug( $latin, $post_id, $status, $type, $parent );
add_filter( 'wp_unique_post_slug', $post_slug, 10, 5 );
return $slug;
};
add_filter( 'wp_unique_post_slug', $post_slug, 10, 5 );
// Categories, tags and other terms: when WordPress makes a new term's slug unique.
$term_slug = null;
$term_slug = static function ( $slug, $term = null ) use ( $latin_slug, &$term_slug ) {
$latin = $latin_slug( (string) $slug );
if ( null === $latin || ! is_object( $term ) ) {
return $slug;
}
remove_filter( 'wp_unique_term_slug', $term_slug, 10 );
$slug = wp_unique_term_slug( $latin, $term );
add_filter( 'wp_unique_term_slug', $term_slug, 10, 2 );
return $slug;
};
add_filter( 'wp_unique_term_slug', $term_slug, 10, 2 );
In these packs
- Greek e-shop: For shops in Greece: receipt or invoice with a checked VAT number (ΑΦΜ), Greek phone and postcode checks, a cash on delivery fee, and greeklish addresses.