';
@@ -43,14 +48,14 @@ function wplng_slug_meta_box_html_output( $post ) {
/**
- * Return HTML of slugs editor in modal
+ * This function prints the HTML of the slugs editor meta box in the WordPress admin interface.
*
- * @param WP_Post $post
- * @return void
+ * @param WP_Post $post The post object.
+ * @return string HTML The HTML of the meta box.
*/
function wplng_slug_editor_get_html( $post ) {
- //used later for security
+ // Used later for security
$html = wp_nonce_field(
basename( __FILE__ ),
'wplng_slug_meta_box_nonce',
@@ -290,8 +295,11 @@ function wplng_slug_editor_get_html( $post ) {
/**
* Save meta box data of wpLingua translations
*
- * @param int $post_id
- * @return void
+ * This function is responsible for saving the slug translations
+ * from the meta box in the WordPress admin interface.
+ *
+ * @param int $post_id The ID of the post being saved.
+ * @return bool Returns true if meta data is successfully updated, false otherwise.
*/
function wplng_slug_save_meta_boxes_data( $post_id ) {
@@ -304,12 +312,12 @@ function wplng_slug_save_meta_boxes_data( $post_id ) {
$nonce = $_POST['wplng_slug_meta_box_nonce'];
$nonce = sanitize_text_field( wp_unslash( $nonce ) );
- // Check for nonce to top xss
+ // Check for nonce to prevent XSS
if ( ! wp_verify_nonce( $nonce, basename( __FILE__ ) ) ) {
return false;
}
- // check for correct user capabilities - stop internal xss from customers
+ // Check for correct user capabilities - stop internal XSS from customers
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return false;
}
@@ -333,6 +341,7 @@ function wplng_slug_save_meta_boxes_data( $post_id ) {
$translations = array();
}
+ // Loop through all target languages and save the slug translations
foreach ( $languages_target as $language_target ) {
$is_in = false;
@@ -361,6 +370,7 @@ function wplng_slug_save_meta_boxes_data( $post_id ) {
}
}
+ // Save the slug translations - this part is run after the translations have been validated
foreach ( $translations as $key => $translation ) {
if ( empty( $translation['language_id'] )
@@ -444,6 +454,7 @@ function wplng_slug_save_meta_boxes_data( $post_id ) {
wplng_clear_slugs_cache();
+ // Save the translations in the post meta in JSON.
return true === update_post_meta(
$post_id,
'wplng_slug_translations',
@@ -455,9 +466,16 @@ function wplng_slug_save_meta_boxes_data( $post_id ) {
}
+
+
+
/**
* wpLingua AJAX function to get slugs on CPT edit page
*
+ * This function processes an AJAX request to generate a slug for a custom post type (CPT) edit page.
+ * It validates and sanitizes input data, checks language parameters, and calls an external API
+ * to translate the given text into a slug format.
+ *
* @return void
*/
function wplng_ajax_generate_slug() {
@@ -466,8 +484,6 @@ function wplng_ajax_generate_slug() {
* Check and sanitize data
*/
- // Check data
-
if ( empty( $_POST['language_source'] )
|| ! is_string( $_POST['language_source'] )
|| empty( $_POST['language_target'] )
@@ -479,8 +495,7 @@ function wplng_ajax_generate_slug() {
return;
}
- // Check and sanitize sources and target languages
-
+ // Check and sanitize source and target languages
$language_source = sanitize_key( $_POST['language_source'] );
$language_target = sanitize_key( $_POST['language_target'] );
@@ -492,19 +507,21 @@ function wplng_ajax_generate_slug() {
return;
}
- // Check and sanitize text to translate
+ /**
+ * Check and sanitize text to translate
+ */
$text = $_POST['text'];
$text = wplng_text_esc( $text );
+ // Replace certain characters for slug compatibility
$text = str_replace(
array( '/', '-', '_' ),
array( '', ' ', ' ' ),
$text
);
- // Remove img emoji
-
+ // Remove img emoji added by WordPress
$text = wp_kses(
$text,
array(
@@ -514,14 +531,14 @@ function wplng_ajax_generate_slug() {
)
);
+ // Remove image alt attributes from text
$text = preg_replace(
'/
/U',
'',
$text
);
- // Check if slug is stranlatable
-
+ // Check if text is translatable
if ( ! wplng_text_is_translatable( $text ) ) {
wp_send_json_success(
sanitize_title(
@@ -541,11 +558,13 @@ function wplng_ajax_generate_slug() {
$language_target
);
+ // Validate API response
if ( ! isset( $response[0] ) ) {
wp_send_json_error( __( 'Invalid API response', 'wplingua' ) );
return;
}
+ // Process and return translated slug
$response = $response[0];
$response = sanitize_title( $response );
$response = urldecode( $response );
diff --git a/inc/admin/translation-cpt.php b/inc/admin/translation-cpt.php
index 8bbbd84..26b1862 100644
--- a/inc/admin/translation-cpt.php
+++ b/inc/admin/translation-cpt.php
@@ -47,12 +47,16 @@ function wplng_register_post_type_translation() {
/**
* Remove quick edit on wpLingua translations list
*
- * @param array $actions
- * @param object $post
- * @return array
+ * This function is a filter that removes the Quick Edit link on the wpLingua
+ * translations list in the WordPress admin area.
+ *
+ * @param array $actions An array of row action links.
+ * @param object $post The post object.
+ * @return array The modified array of row action links.
*/
function wplng_translation_remove_quick_edit( $actions, $post ) {
+ // Check that the post type is a wpLingua translation
if ( $post->post_type != 'wplng_translation' ) {
return $actions;
}
@@ -139,15 +143,18 @@ function wplng_restrict_manage_posts_translation_status() {
/**
- * Filter translations by status: Apply custom query on CPT for translation_status
+ * Filter translations by status: Apply custom query on CPT for translation_status.
*
- * @param object $query
+ * This function modifies the query for the 'wplng_translation' post type in the admin edit screen.
+ * It applies a meta query based on the specified translation status.
+ *
+ * @param WP_Query $query The current WP_Query instance.
* @return void
*/
function wplng_posts_filter_translation_status( $query ) {
-
global $pagenow;
+ // Check if we are in the admin edit screen for 'wplng_translation' post type
if ( empty( $_GET['post_type'] )
|| 'wplng_translation' !== $_GET['post_type']
|| empty( $_GET['translation_status'] )
@@ -157,6 +164,7 @@ function wplng_posts_filter_translation_status( $query ) {
return;
}
+ // Determine the translation status and set the corresponding meta query
switch ( $_GET['translation_status'] ) {
case 'full-reviewed':
$query->set(
@@ -223,20 +231,23 @@ function wplng_posts_filter_translation_status( $query ) {
)
);
break;
-
}
-
}
/**
* Add status custom column on translations
*
- * @param array String array
+ * Adds a custom column in the admin edit screen for the 'wplng_translation' post type.
+ * The column is called 'Translation status' and is used to show the status of the
+ * translation for each post.
+ *
+ * @param array $columns String array
* @return array
*/
function wplng_translation_status_columns( $columns ) {
+ // Save the 'cb' column value if it exists
$cb = array();
if ( isset( $columns['cb'] ) ) {
@@ -246,6 +257,7 @@ function wplng_translation_status_columns( $columns ) {
unset( $columns['cb'] );
}
+ // Add the 'wplng_status' column
$columns = array_merge(
$cb,
array(
diff --git a/inc/admin/translation-edit-modal.php b/inc/admin/translation-edit-modal.php
index 9fb0125..a254559 100644
--- a/inc/admin/translation-edit-modal.php
+++ b/inc/admin/translation-edit-modal.php
@@ -134,12 +134,19 @@ function wplng_ajax_edit_modal() {
/**
* Save translation on AJAX call of modal edit
*
+ * Process the AJAX request to save a translation from modal edit,
+ * validate and sanitize the input data, and call the function to
+ * save the translation.
+ *
* @return void
*/
function wplng_ajax_save_modal() {
/**
* Check and sanitize data
+ *
+ * Check that the post ID and current user can edit the post
+ * before attempting to save the translation.
*/
if ( empty( $_POST['post_id'] )
@@ -151,12 +158,18 @@ function wplng_ajax_save_modal() {
/**
* Try to save the post
+ *
+ * Call the function to save the translation and store the result
+ * in variable $saved.
*/
$saved = wplng_translation_save_meta_boxes_data( $_POST['post_id'] );
/**
* Send AJAX success or error
+ *
+ * If the saving was successful, send a JSON success response.
+ * Otherwise, send a JSON error response with a message.
*/
if ( $saved ) {
diff --git a/inc/admin/translation-meta.php b/inc/admin/translation-meta.php
index 6c8b3d3..0e4a942 100644
--- a/inc/admin/translation-meta.php
+++ b/inc/admin/translation-meta.php
@@ -9,18 +9,22 @@
/**
* Add meta box on wpLingua translations
*
- * @param object $post
+ * This function adds a meta box to the wpLingua Translations post type in the
+ * WordPress admin interface. The meta box is used to display and edit the
+ * translation of a post.
+ *
+ * @param object $post The post object.
* @return void
*/
function wplng_translation_add_meta_box( $post ) {
add_meta_box(
- 'wplng_meta_box_translation',
- __( 'Translation', 'wplingua' ),
- 'wplng_translation_meta_box_html_output',
- 'wplng_translation',
- 'normal',
- 'low'
+ 'wplng_meta_box_translation', // Unique ID for the meta box
+ __( 'Translation', 'wplingua' ), // Title of the meta box
+ 'wplng_translation_meta_box_html_output', // Callback function to render the meta box HTML
+ 'wplng_translation', // Screen or post type where the meta box appears
+ 'normal', // Context where the meta box should appear
+ 'low' // Priority within the context
);
}
@@ -29,10 +33,13 @@ function wplng_translation_add_meta_box( $post ) {
/**
* Print HTML of translations editor meta box in back office
*
- * @param object $post
- * @return string HTML
+ * This function prints the HTML of the translations editor meta box in the
+ * WordPress admin interface. The meta box is used to display and edit the
+ * translation of a post.
+ *
+ * @param object $post The post object.
+ * @return string HTML The HTML of the meta box.
*/
-
function wplng_translation_meta_box_html_output( $post ) {
echo '
';
@@ -45,8 +52,8 @@ function wplng_translation_meta_box_html_output( $post ) {
/**
* Return HTML of translations editor in modal
*
- * @param WP_Post $post
- * @return void
+ * @param WP_Post $post The post object.
+ * @return string The HTML of the translations editor in the modal.
*/
function wplng_translation_editor_get_html( $post ) {
diff --git a/inc/dom/exclusion-replace-tags.php b/inc/dom/exclusion-replace-tags.php
index 823d868..3b30b47 100644
--- a/inc/dom/exclusion-replace-tags.php
+++ b/inc/dom/exclusion-replace-tags.php
@@ -7,27 +7,49 @@
/**
- * Replace exclution tag by HTML part
+ * Replace exclusion tag with corresponding HTML part.
*
- * @param object $dom
- * @param array $excluded_elements
- * @return object
+ * This function scans the DOM for elements with the 'wplng-tag-exclude' attribute
+ * and replaces them with HTML parts provided in the '$excluded_elements' array.
+ *
+ * @param object $dom The DOM object to process.
+ * @param array $excluded_elements An array of HTML parts to replace the exclusion tags.
+ * @return object The modified DOM object.
*/
function wplng_dom_exclusions_replace_tags( $dom, $excluded_elements ) {
- $dom = wplng_sdh_str_get_html( $dom );
+ $contain_excluded = true;
+ $counter = 0;
+
+ // Continue processing the DOM until no excluded elements are found
+ while ( $contain_excluded && $counter <= 6 ) {
+
+ $contain_excluded = false;
+ $dom = wplng_sdh_str_get_html( $dom );
- foreach ( $dom->find( '[wplng-tag-exclude]' ) as $element ) {
+ // Iterate over all elements with the 'wplng-tag-exclude' attribute
+ foreach ( $dom->find( '[wplng-tag-exclude]' ) as $element ) {
- if ( isset( $element->attr['wplng-tag-exclude'] ) ) {
+ // Check if the exclusion tag attribute is set
+ if ( ! isset( $element->attr['wplng-tag-exclude'] ) ) {
+ continue;
+ }
+ // Get the index of the excluded element
$exclude_index = (int) $element->attr['wplng-tag-exclude'];
+ // Replace the element's outer text with the corresponding HTML part
if ( isset( $excluded_elements[ $exclude_index ] ) ) {
$element->outertext = $excluded_elements[ $exclude_index ];
}
+
+ // Indicate that further processing may be needed
+ $contain_excluded = true;
}
+
+ $counter++;
}
+ // Return the processed DOM
return $dom;
}
diff --git a/inc/slug.php b/inc/slug.php
index 59dcac0..28fb510 100644
--- a/inc/slug.php
+++ b/inc/slug.php
@@ -16,7 +16,9 @@
*/
function wplng_slug_original( $slug, $language_id, $slugs_translations = false ) {
- if ( ! wplng_text_is_translatable( $slug ) ) {
+ if ( ! wplng_text_is_translatable( $slug )
+ || wplng_str_contains( $slug, '.' )
+ ) {
return $slug;
}
@@ -257,14 +259,24 @@ function wplng_slug_translate_path( $path, $language_id ) {
*/
function wplng_create_slug( $slug ) {
- if ( is_404() ) {
+ if ( is_404()
+ || ! current_user_can( 'edit_posts' )
+ || wplng_str_contains( $slug, '.' )
+ ) {
return false;
}
$slug = sanitize_title( $slug );
if ( '' === $slug
+ || ! wplng_text_is_translatable( $slug )
|| wplng_is_valid_language_id( $slug )
+ || 'go' === $slug
+ || 'refer' === $slug
+ || 'recommend' === $slug
+ || 'recommends' === $slug
+ || 'wp-includes' === $slug
+ || 'wp-json' === $slug
) {
return false;
}
@@ -391,9 +403,13 @@ function wplng_get_slugs_from_query() {
$source = sanitize_title( $meta['wplng_slug_original'][0] );
- if ( 'index-php' === $source
- || 'wp-includes' === $source
- || 'wp-json' === $source
+ if ( 'index-php' === $source
+ || 'wp-includes' === $source
+ || 'wp-json' === $source
+ || 'go' === $source
+ || 'refer' === $source
+ || 'recommend' === $source
+ || 'recommends' === $source
) {
$slug_to_delete[] = $slug_id;
continue;
diff --git a/inc/translator/js.php b/inc/translator/js.php
index b1d9e71..b124373 100644
--- a/inc/translator/js.php
+++ b/inc/translator/js.php
@@ -9,38 +9,47 @@
/**
* wpLingua translate : Get translated JS
*
- * @param string $js
- * @param array $translations
- * @return string
+ * This function translates JavaScript code containing JSON objects.
+ * It uses regex to find JavaScript variables and translates the JSON part.
+ *
+ * @param string $js The JavaScript code to translate.
+ * @param array $args Additional arguments for translation processing.
+ * @return string The translated JavaScript code.
*/
function wplng_translate_js( $js, $args = array() ) {
+ // Return early if the provided JavaScript is empty or consists only of whitespace
if ( empty( trim( $js ) ) ) {
return $js;
}
+ // Array to hold matched JSON objects
$json = array();
+ // Regex to match JavaScript variable or window object assignment containing JSON
preg_match_all(
'#(var\s|let\s|window\._)(.*)\s?=\s?(\{.*\});?#Ui',
$js,
$json
);
+ // Check if regex found a valid match
if ( ! empty( $json[2][0] ) && ! empty( $json[3][0] ) ) {
- $var_name = $json[2][0];
- $var_json = $json[3][0];
+ $var_name = $json[2][0]; // Variable name
+ $var_json = $json[3][0]; // JSON string
+ // Prepare arguments for translation
wplng_args_setup( $args );
-
$args['parents'] = array( $var_name );
+ // Translate the JSON string
$json_translated = wplng_translate_json(
$var_json,
$args
);
+ // Replace the original JSON with the translated version if different
if ( $var_json != $json_translated ) {
$js = str_replace(
$var_json,
@@ -50,5 +59,5 @@ function wplng_translate_js( $js, $args = array() ) {
}
}
- return $js;
+ return $js; // Return the translated JavaScript
}
diff --git a/inc/url.php b/inc/url.php
index 5cb4788..d8f1deb 100644
--- a/inc/url.php
+++ b/inc/url.php
@@ -134,6 +134,7 @@ function wplng_url_is_translatable( $url = '' ) {
$url = trailingslashit( $url );
$url = wp_make_link_relative( $url );
+ $url = strtolower( $url );
// Check if is an admin page
if ( wplng_str_contains( $url, wp_make_link_relative( get_admin_url() ) ) ) {
@@ -142,20 +143,28 @@ function wplng_url_is_translatable( $url = '' ) {
// Check if URL is an anchor link for the current page
if ( $is_translatable
- && '#' === substr( $url, 0, 1 )
+ && wplng_str_starts_with( $url, '#' )
) {
- return $url;
+ return false;
}
+ // Don't translate some WordPress and WooCommerce URLs
+ // admin, REST API, rss and other special URLs
if ( $is_translatable
&& (
wplng_str_contains( $url, 'wp-login.php' )
- || wplng_str_ends_with( $url, '/feed/' )
- || wplng_str_contains( $url, 'wp-comments-post.php' )
|| wplng_str_contains( $url, 'wp-register.php' )
+ || wplng_str_contains( $url, 'wp-comments-post.php' )
+ || wplng_str_ends_with( $url, '/feed/' )
|| wplng_str_contains( $url, '/wp-json/' )
|| wplng_str_contains( $url, '/wp-includes/' )
- || wplng_str_contains( $url, '?wc-ajax=' )
+ || wplng_str_contains( $url, '/oembed/' )
+ || wplng_str_contains( $url, '?wc-ajax=' )
+ || wplng_str_contains( $url, '?feed=' )
+ || wplng_str_contains( $url, '?embed=' )
+ || wplng_str_contains( $url, '&wc-ajax=' )
+ || wplng_str_contains( $url, '&feed=' )
+ || wplng_str_contains( $url, '&embed=' )
)
) {
$is_translatable = false;
@@ -180,7 +189,7 @@ function wplng_url_is_translatable( $url = '' ) {
}
// Exclude files URL
- $regex_is_file = '#\.(avi|css|doc|exe|gif|html|jfif|jpg|jpeg|mid|midi|mp3|mpg|mpeg|mov|qt|pdf|png|ram|rar|tiff|txt|wav|zip|ico)$#Uis';
+ $regex_is_file = '#\.(avi|css|doc|exe|gif|html|jfif|jpg|jpeg|webp|bmp|mid|midi|mp3|mpg|mpeg|avif|mov|qt|pdf|png|ram|rar|tiff|txt|wav|zip|ico|xml|doc|docx|xls|xlsx)$#Uis';
if ( $is_translatable
&& preg_match( $regex_is_file, $url )
) {
diff --git a/readme.txt b/readme.txt
index 46e1ab2..b769fff 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,7 +4,7 @@ Donate link: https://wplingua.com/
Tags: translate, translation, multilingual, localization, language
Requires at least: 6.0
Tested up to: 6.7
-Stable tag: 2.1.3
+Stable tag: 2.1.4
Requires PHP: 7.4
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -174,6 +174,13 @@ No, not at the moment but in the meantime, you can easily display the language s
== Changelog ==
+= 2.1.4 =
+
+* Better management of translated slugs
+* Better management of excluded elements
+* Some optimizations
+* Fix incorrectly replaced flags on flag format changing in selector options
+
= 2.1.3 =
* Better untranslatable URL detection
diff --git a/wplingua.php b/wplingua.php
index c9321df..34b3f5f 100644
--- a/wplingua.php
+++ b/wplingua.php
@@ -7,7 +7,7 @@
* Author URI: https://wplingua.com/
* Text Domain: wplingua
* Domain Path: /languages/
- * Version: 2.1.3
+ * Version: 2.1.4
* Requires PHP: 7.4
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -24,7 +24,7 @@
define( 'WPLNG_API_URL', 'https://api.wplingua.com' );
define( 'WPLNG_API_VERSION', '2.0' );
define( 'WPLNG_API_SSLVERIFY', true );
-define( 'WPLNG_PLUGIN_VERSION', '2.1.3' );
+define( 'WPLNG_PLUGIN_VERSION', '2.1.4' );
define( 'WPLNG_PLUGIN_FILE', plugin_basename( __FILE__ ) );
define( 'WPLNG_PLUGIN_PATH', dirname( __FILE__ ) );
define( 'WPLNG_MAX_TRANSLATIONS', 256 );