Випадок не супер складний але я вирішила про нього написати. При роботі з мультимовними сайтами виникає проблема, ми не можем прописати однакові слаги на обох мовних версіях статті. Безкоштовна версія плагіну Polylang не дає такої можливості. Обійти цей недолік можна використанням іншого плагіна – Permalink Manager Lite. Після активації плагіна в адмінці зявляється поле, воно по замовчуванню дублює слаг з рідного поля для слагу в WordPress. Проте його можна змінювати і поле виглядає так:
Прикладом буде ця стаття, я її зробила з однаковими слагами в українській і англійській версіях:
https://victoriaweb.me/how-to-make-identical-slugs-in-wordpress/
https://victoriaweb.me/en/how-to-make-identical-slugs-in-wordpress/
Альтернативний метод роботи зі слагами
На сайті GitHub є плагін розробника Ulrich Pogson – Polylang Slug. Я його протестувала на блоковій темі Blockera і він працює добре. Нижче код плагіна без перевірки версій, він також працює якщо додати в файл functions.php:
function polylang_slug_unique_slug_in_language( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ){ // Return slug if it was not changed. if ( $original_slug === $slug ) { return $slug; } global $wpdb; // Get language of a post $lang = pll_get_post_language( $post_ID ); $options = get_option( 'polylang' ); // return the slug if Polylang does not return post language or has incompatable redirect setting or is not translated post type. if ( empty( $lang ) || 0 === $options['force_lang'] || ! pll_is_translated_post_type( $post_type ) ) { return $slug; } // " INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = ID". $join_clause = polylang_slug_model_post_join_clause(); // " AND pll_tr.term_taxonomy_id IN (" . implode(',', $languages) . ")". $where_clause = polylang_slug_model_post_where_clause( $lang ); // Polylang does not translate attachements - skip if it is one. // @TODO Recheck this with the Polylang settings if ( 'attachment' == $post_type ) { // Attachment slugs must be unique across all types. $check_sql = "SELECT post_name FROM $wpdb->posts $join_clause WHERE post_name = %s AND ID != %d $where_clause LIMIT 1"; $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $original_slug, $post_ID ) ); } elseif ( is_post_type_hierarchical( $post_type ) ) { // Page slugs must be unique within their own trees. Pages are in a separate // namespace than posts so page slugs are allowed to overlap post slugs. $check_sql = "SELECT ID FROM $wpdb->posts $join_clause WHERE post_name = %s AND post_type IN ( %s, 'attachment' ) AND ID != %d AND post_parent = %d $where_clause LIMIT 1"; $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $original_slug, $post_type, $post_ID, $post_parent ) ); } else { // Post slugs must be unique across all posts. $check_sql = "SELECT post_name FROM $wpdb->posts $join_clause WHERE post_name = %s AND post_type = %s AND ID != %d $where_clause LIMIT 1"; $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $original_slug, $post_type, $post_ID ) ); } if ( ! $post_name_check ) { return $original_slug; } return $slug; } add_filter( 'wp_unique_post_slug', 'polylang_slug_unique_slug_in_language', 10, 6 ); /** * Modify the sql query to include checks for the current language. * * @since 0.1.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $query Database query. * * @return string The modified query. */ function polylang_slug_filter_queries( $query ) { global $wpdb; // Query for posts page, pages, attachments and hierarchical CPT. This is the only possible place to make the change. The SQL query is set in get_page_by_path() $is_pages_sql = preg_match( "#SELECT ID, post_name, post_parent, post_type FROM {$wpdb->posts} .*#", polylang_slug_standardize_query( $query ), $matches ); if ( ! $is_pages_sql ) { return $query; } // Check if should contine. Don't add $query polylang_slug_should_run() as $query is a SQL query. if ( ! polylang_slug_should_run() ) { return $query; } $lang = pll_current_language(); // " INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = ID". $join_clause = polylang_slug_model_post_join_clause(); // " AND pll_tr.term_taxonomy_id IN (" . implode(',', $languages) . ")". $where_clause = polylang_slug_model_post_where_clause( $lang ); $query = preg_match( "#(SELECT .* (?=FROM))(FROM .* (?=WHERE))(?:(WHERE .*(?=ORDER))|(WHERE .*$))(.*)#", polylang_slug_standardize_query( $query ), $matches ); // Reindex array numerically $matches[3] and $matches[4] are not added together thus leaving a gap. With this $matches[5] moves up to $matches[4] $matches = array_values( $matches ); // SELECT, FROM, INNER JOIN, WHERE, WHERE CLAUSE (additional), ORBER BY (if included) $sql_query = $matches[1] . $matches[2] . $join_clause . $matches[3] . $where_clause . $matches[4]; /** * Disable front end query modification. * * Allows disabling front end query modification if not needed. * * @since 0.2.0 * * @param string $sql_query Database query. * @param array $matches { * @type string $matches[1] SELECT SQL Query. * @type string $matches[2] FROM SQL Query. * @type string $matches[3] WHERE SQL Query. * @type string $matches[4] End of SQL Query (Possibly ORDER BY). * } * @param string $join_clause INNER JOIN Polylang clause. * @param string $where_clause Additional Polylang WHERE clause. */ return apply_filters( 'polylang_slug_sql_query', $sql_query, $matches, $join_clause, $where_clause ); } add_filter( 'query', 'polylang_slug_filter_queries' ); /** * Extend the WHERE clause of the query. * * This allows the query to return only the posts of the current language * * @since 0.1.0 * * @param string $where The WHERE clause of the query. * @param WP_Query $query The WP_Query instance (passed by reference). * * @return string The WHERE clause of the query. */ function polylang_slug_posts_where_filter( $where, $query ) { // Check if should contine. if ( ! polylang_slug_should_run( $query ) ) { return $where; } $lang = empty( $query->query['lang'] ) ? pll_current_language() : $query->query['lang']; // " AND pll_tr.term_taxonomy_id IN (" . implode(',', $languages) . ")" $where .= polylang_slug_model_post_where_clause( $lang ); return $where; } add_filter( 'posts_where', 'polylang_slug_posts_where_filter', 10, 2 ); /** * Extend the JOIN clause of the query. * * This allows the query to return only the posts of the current language * * @since 0.1.0 * * @param string $join The JOIN clause of the query. * @param WP_Query $query The WP_Query instance (passed by reference). * * @return string The JOIN clause of the query. */ function polylang_slug_posts_join_filter( $join, $query ) { // Check if should contine. if ( ! polylang_slug_should_run( $query ) ) { return $join; } // " INNER JOIN $wpdb->term_relationships AS pll_tr ON pll_tr.object_id = ID". $join .= polylang_slug_model_post_join_clause(); return $join; } add_filter( 'posts_join', 'polylang_slug_posts_join_filter', 10, 2 ); /** * Check if the query needs to be adapted. * * @since 0.2.0 * * @param WP_Query $query The WP_Query instance (passed by reference). * * @return bool */ function polylang_slug_should_run( $query = '' ) { /** * Disable front end query modification. * * Allows disabling front end query modification if not needed. * * @since 0.2.0 * * @param bool false Not disabling run. * @param WP_Query $query The WP_Query instance (passed by reference). */ // Do not run in admin or if Polylang is disabled $disable = apply_filters( 'polylang_slug_disable', false, $query ); if ( is_admin() || is_feed() || ! function_exists( 'pll_current_language' ) || $disable ) { return false; } // The lang query should be defined if the URL contains the language $lang = empty( $query->query['lang'] ) ? pll_current_language() : $query->query['lang']; // Checks if the post type is translated when doing a custom query with the post type defined $is_translated = ! empty( $query->query['post_type'] ) && ! pll_is_translated_post_type( $query->query['post_type'] ); return ! ( empty( $lang ) || $is_translated ); } /** * Standardize the query. * * This makes the standardized and simpler to run regex on * * @since 0.2.0 * * @param string $query Database query. * * @return string The standardized query. */ function polylang_slug_standardize_query( $query ) { // Strip tabs, newlines and multiple spaces. $query = str_replace( array( "\t", " \n", "\n", " \r", "\r", " ", " " ), array( '', ' ', ' ', ' ', ' ', ' ', ' ' ), $query ); return trim( $query ); } /** * Fetch the polylang join clause. * * @since 0.2.0 * * @return string */ function polylang_slug_model_post_join_clause() { if ( function_exists( 'PLL' ) ) { return PLL()->model->post->join_clause(); } elseif ( array_key_exists( 'polylang', $GLOBALS ) ) { global $polylang; return $polylang->model->join_clause( 'post' ); } return ''; } /** * Fetch the polylang where clause. * * @since 0.2.0 * * @param string $lang The current language slug. * * @return string */ function polylang_slug_model_post_where_clause( $lang = '' ) { if ( function_exists( 'PLL' ) ) { return PLL()->model->post->where_clause( $lang ); } elseif ( array_key_exists( 'polylang', $GLOBALS ) ) { global $polylang; return $polylang->model->where_clause( $lang, 'post' ); } return ''; }