first commit

This commit is contained in:
2023-09-12 21:41:04 +02:00
commit 3361a7f053
13284 changed files with 2116755 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
<?php
class WPML_File_Name_Converter {
/**
* @var string
*/
private $home_path;
/**
* @param string $file
*
* @return string
*/
public function transform_realpath_to_reference( $file ) {
$home_path = $this->get_home_path();
return str_replace( $home_path, '', $file );
}
/**
* @param string $file
*
* @return string
*/
public function transform_reference_to_realpath( $file ) {
$home_path = $this->get_home_path();
return trailingslashit( $home_path ) . ltrim( $file, '/\\' );
}
/**
* @return string
*/
private function get_home_path() {
if ( null === $this->home_path ) {
if ( ! function_exists( 'get_home_path' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
$this->home_path = get_home_path();
}
return $this->home_path;
}
}

View File

@@ -0,0 +1,58 @@
<?php
class WPML_ST_File_Hashing {
const OPTION_NAME = 'wpml-scanning-files-hashing';
/** @var array */
private $hashes;
public function __construct() {
$this->hashes = $this->get_hashes();
}
/**
* @param string $file
*/
private function set_hash( $file ) {
$this->hashes[ $file ] = md5_file( $file );
}
/**
* @param string $file
*
* @return bool
*/
public function hash_changed( $file ) {
return ! array_key_exists( $file, $this->hashes ) || md5_file( $file ) !== $this->hashes[ $file ];
}
public function save_hash() {
$needs_to_save = false;
if ( array_key_exists( 'files', $_POST ) ) {
foreach ( $_POST['files'] as $file_path ) {
if ( realpath( $file_path ) ) {
$this->set_hash( $file_path );
$needs_to_save = true;
}
}
}
if ( $needs_to_save ) {
update_option( self::OPTION_NAME, $this->hashes );
}
wp_send_json_success();
}
/**
* @return array
*/
private function get_hashes() {
return get_option( self::OPTION_NAME ) ? get_option( self::OPTION_NAME ) : array();
}
public function clean_hashes() {
delete_option( self::OPTION_NAME );
}
}

View File

@@ -0,0 +1,55 @@
<?php
class WPML_ST_Strings_Stats {
/**
* @var SitePress
*/
private $sitepress;
/**
* @var wpdb
*/
private $wpdb;
/**
* @var array
*/
private $stats;
public function __construct( wpdb $wpdb, SitePress $sitepress ) {
$this->wpdb = $wpdb;
$this->sitepress = $sitepress;
}
/**
* @param string $component_name
* @param string $type
* @param string $domain
*/
public function update( $component_name, $type, $domain ) {
$count = $this->get_count( $domain );
$string_settings = $this->sitepress->get_setting( 'st' );
$string_settings[ $type . '_localization_domains' ][ $component_name ][ $domain ] = $count;
$this->sitepress->set_setting( 'st', $string_settings, true );
$this->sitepress->save_settings();
}
/**
* @param string $domain
*
* @return int
*/
private function get_count( $domain ) {
if ( ! $this->stats ) {
$this->set_stats();
}
return isset( $this->stats[ $domain ] ) ? (int) $this->stats[ $domain ]->count : 0;
}
private function set_stats() {
$count_query = 'SELECT context, COUNT(id) count FROM ' . $this->wpdb->prefix . 'icl_strings GROUP BY context';
$this->stats = $this->wpdb->get_results( $count_query, OBJECT_K );
}
}

View File

@@ -0,0 +1,17 @@
<?php
class WPML_ST_Theme_Plugin_Hooks {
/**
* @var WPML_ST_File_Hashing
*/
private $file_hashing;
public function __construct( WPML_ST_File_Hashing $file_hashing ) {
$this->file_hashing = $file_hashing;
}
public function add_hooks() {
add_action( 'icl_st_unregister_string_multi', array( $this->file_hashing, 'clean_hashes' ) );
}
}

View File

@@ -0,0 +1,39 @@
<?php
class WPML_ST_Theme_Plugin_Scan_Files_Ajax implements IWPML_Action {
/** @var IWPML_ST_String_Scanner */
private $string_scanner;
/**
* WPML_ST_Theme_Scan_Files_Ajax constructor.
*
* @param IWPML_ST_String_Scanner $string_scanner
*/
public function __construct( IWPML_ST_String_Scanner $string_scanner ) {
$this->string_scanner = $string_scanner;
}
public function add_hooks() {
add_action( 'wp_ajax_wpml_st_scan_chunk', array( $this, 'scan' ) );
}
public function scan() {
wpml_get_admin_notices()->remove_notice(
WPML_ST_Themes_And_Plugins_Settings::NOTICES_GROUP,
WPML_ST_Themes_And_Plugins_Updates::WPML_ST_SCAN_NOTICE_ID
);
wpml_get_admin_notices()->remove_notice(
WPML_ST_Themes_And_Plugins_Settings::NOTICES_GROUP,
WPML_ST_Themes_And_Plugins_Updates::WPML_ST_SCAN_ACTIVE_ITEMS_NOTICE_ID
);
$this->clear_items_needs_scan_buffer();
$this->string_scanner->scan();
}
public function clear_items_needs_scan_buffer() {
delete_option( WPML_ST_Themes_And_Plugins_Updates::WPML_ST_ITEMS_TO_SCAN );
}
}

View File

@@ -0,0 +1,20 @@
<?php
class WPML_ST_Update_File_Hash_Ajax implements IWPML_Action {
/** @var WPML_ST_File_Hashing */
private $file_hashing;
/**
* WPML_ST_Update_File_Hash_Ajax constructor.
*
* @param WPML_ST_File_Hashing $file_hashing
*/
public function __construct( WPML_ST_File_Hashing $file_hashing ) {
$this->file_hashing = $file_hashing;
}
public function add_hooks() {
add_action( 'wp_ajax_update_file_hash', array( $this->file_hashing, 'save_hash' ) );
}
}

View File

@@ -0,0 +1,49 @@
<?php
class WPML_ST_Themes_And_Plugins_Settings {
const OPTION_NAME = 'wpml_st_display_strings_scan_notices';
const NOTICES_GROUP = 'wpml-st-string-scan';
public function init_hooks() {
if ( $this->must_display_notices() ) {
add_action( 'wp_ajax_hide_strings_scan_notices', array( $this, 'hide_strings_scan_notices' ) );
add_action( 'wpml-notices-scripts-enqueued', array( $this, 'enqueue_scripts' ) );
}
}
public function get_notices_group() {
return self::NOTICES_GROUP;
}
public function must_display_notices() {
return (bool) get_option( self::OPTION_NAME );
}
public function set_strings_scan_notices( $value ) {
update_option( self::OPTION_NAME, $value );
}
public function hide_strings_scan_notices() {
update_option( self::OPTION_NAME, false );
}
public function display_notices_setting_is_missing() {
return null === get_option( self::OPTION_NAME, null );
}
public function create_display_notices_setting() {
add_option( self::OPTION_NAME, true );
}
public function enqueue_scripts() {
$strings = array(
'title' => __( 'Dismiss all notices', 'wpml-string-translation' ),
'message' => __( 'Also prevent similar messages in the future?', 'wpml-string-translation' ),
'no' => __( 'No - keep showing these message', 'wpml-string-translation' ),
'yes' => __( 'Yes - disable these notifications completely', 'wpml-string-translation' ),
);
wp_register_script( 'wpml-st-disable-notices', WPML_ST_URL . '/res/js/disable-string-scan-notices.js', array( 'jquery', 'jquery-ui-dialog' ) );
wp_localize_script( 'wpml-st-disable-notices', 'wpml_st_disable_notices_strings', $strings );
wp_enqueue_script( 'wpml-st-disable-notices' );
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* @author OnTheGo Systems
*/
class WPML_ST_Themes_And_Plugins_Updates {
const WPML_WP_UPDATED_MO_FILES = 'wpml_wp_updated_mo_files';
const WPML_ST_ITEMS_TO_SCAN = 'wpml_items_to_scan';
const WPML_ST_SCAN_NOTICE_ID = 'wpml_st_scan_items';
const WPML_ST_FASTER_SETTINGS_NOTICE_ID = 'wpml_st_faster_settings';
const WPML_ST_SCAN_ACTIVE_ITEMS_NOTICE_ID = 'wpml_st_scan_active_items';
/** @var WPML_Notices */
private $admin_notices;
/** @var WPML_ST_Themes_And_Plugins_Settings */
private $settings;
/**
* WPML_ST_Admin_Notices constructor.
*
* @param WPML_Notices $admin_notices
* @param WPML_ST_Themes_And_Plugins_Settings $settings
*/
public function __construct( WPML_Notices $admin_notices, WPML_ST_Themes_And_Plugins_Settings $settings ) {
$this->admin_notices = $admin_notices;
$this->settings = $settings;
}
public function init_hooks() {
add_action( 'upgrader_process_complete', array( $this, 'store_mo_file_update' ), 10, 2 );
}
public function data_is_valid( $thing ) {
return $thing && ! is_wp_error( $thing );
}
public function notices_count() {
return $this->admin_notices->count();
}
public function remove_notice( $id ) {
$this->admin_notices->remove_notice( $this->settings->get_notices_group(), $id );
}
/**
* @param \WP_Upgrader $upgrader
* @param array<string,string|array<string,string>> $language_translations
*/
public function store_mo_file_update( WP_Upgrader $upgrader, $language_translations ) {
if ( is_wp_error( $upgrader->result ) ) {
return;
}
$action = $language_translations['action'];
if ( in_array( $action, array( 'update', 'install' ), true ) ) {
if ( 'translation' === $language_translations['type'] ) {
$last_update = get_option( self::WPML_WP_UPDATED_MO_FILES, array() );
$translations = $language_translations['translations'];
foreach ( $translations as $translation ) {
$last_update[ $translation['type'] ][ $translation['slug'] ] = time();
}
update_option( self::WPML_WP_UPDATED_MO_FILES, $last_update, false );
}
}
}
}

View File

@@ -0,0 +1,11 @@
<?php
class WPML_ST_Theme_Plugin_Hooks_Factory implements IWPML_Backend_Action_Loader {
/**
* @return WPML_ST_Theme_Plugin_Hooks
*/
public function create() {
return new WPML_ST_Theme_Plugin_Hooks( new WPML_ST_File_Hashing() );
}
}

View File

@@ -0,0 +1,17 @@
<?php
class WPML_ST_Update_File_Hash_Ajax_Factory extends WPML_AJAX_Base_Factory implements IWPML_Backend_Action_Loader {
const AJAX_ACTION = 'update_file_hash';
const NONCE = 'wpml-update-file-hash-nonce';
/** @return null|WPML_ST_Update_File_Hash_Ajax */
public function create() {
$hooks = null;
if ( $this->is_valid_action( self::AJAX_ACTION ) ) {
$hooks = new WPML_ST_Update_File_Hash_Ajax( new WPML_ST_File_Hashing() );
}
return $hooks;
}
}

View File

@@ -0,0 +1,10 @@
<?php
class WPML_ST_Plugin_String_Scanner_Factory {
/** @return WPML_Plugin_String_Scanner */
public function create() {
$file_hashing = new WPML_ST_File_Hashing();
return new WPML_Plugin_String_Scanner( wpml_get_filesystem_direct(), $file_hashing );
}
}

View File

@@ -0,0 +1,20 @@
<?php
class WPML_ST_Theme_Plugin_Scan_Dir_Ajax_Factory extends WPML_AJAX_Base_Factory implements IWPML_Backend_Action_Loader {
const AJAX_ACTION = 'wpml_get_files_to_scan';
const NONCE = 'wpml-get-files-to-scan-nonce';
/** @return null|WPML_ST_Theme_Plugin_Scan_Dir_Ajax */
public function create() {
$hooks = null;
if ( $this->is_valid_action( self::AJAX_ACTION ) ) {
$scan_dir = new WPML_ST_Scan_Dir();
$file_hashing = new WPML_ST_File_Hashing();
$hooks = new WPML_ST_Theme_Plugin_Scan_Dir_Ajax( $scan_dir, $file_hashing );
}
return $hooks;
}
}

View File

@@ -0,0 +1,28 @@
<?php
class WPML_ST_Theme_Plugin_Scan_Files_Ajax_Factory extends WPML_AJAX_Base_Factory implements IWPML_Backend_Action_Loader {
const AJAX_ACTION = 'wpml_st_scan_chunk';
const NONCE = 'wpml-scan-files-nonce';
/** @return null|WPML_ST_Theme_Plugin_Scan_Files_Ajax */
public function create() {
$hooks = null;
$scan_factory = '';
if ( $this->is_valid_action( self::AJAX_ACTION ) ) {
if ( array_key_exists( 'theme', $_POST ) ) {
$scan_factory = new WPML_ST_Theme_String_Scanner_Factory();
} elseif ( array_key_exists( 'plugin', $_POST ) ) {
$scan_factory = new WPML_ST_Plugin_String_Scanner_Factory();
}
if ( $scan_factory ) {
$scan = $scan_factory->create();
$hooks = new WPML_ST_Theme_Plugin_Scan_Files_Ajax( $scan );
}
}
return $hooks;
}
}

View File

@@ -0,0 +1,10 @@
<?php
class WPML_ST_Theme_String_Scanner_Factory {
/** @return WPML_Theme_String_Scanner */
public function create() {
$file_hashing = new WPML_ST_File_Hashing();
return new WPML_Theme_String_Scanner( wpml_get_filesystem_direct(), $file_hashing );
}
}

View File

@@ -0,0 +1,6 @@
<?php
interface IWPML_ST_String_Scanner {
public function scan();
}

View File

@@ -0,0 +1,124 @@
<?php
class WPML_ST_Theme_Plugin_Scan_Dir_Ajax {
/** @var WPML_ST_Scan_Dir */
private $scan_dir;
/** @var WPML_ST_File_Hashing */
private $file_hashing;
/**
* WPML_ST_Theme_Plugin_Scan_Dir_Ajax constructor.
*
* @param WPML_ST_Scan_Dir $scan_dir
* @param WPML_ST_File_Hashing $file_hashing
*/
public function __construct( WPML_ST_Scan_Dir $scan_dir, WPML_ST_File_Hashing $file_hashing ) {
$this->scan_dir = $scan_dir;
$this->file_hashing = $file_hashing;
}
public function add_hooks() {
add_action( 'wp_ajax_wpml_get_files_to_scan', array( $this, 'get_files' ) );
}
public function get_files() {
$folders = $this->get_folder();
$result = array();
if ( $folders ) {
$file_type = array( 'php', 'inc' );
$files_found_chunks = array();
foreach ( $folders as $folder ) {
$files_found_chunks[] = $this->scan_dir->scan(
$folder,
$file_type,
$this->is_one_file_plugin(),
$this->get_folders_to_ignore()
);
}
$files = call_user_func_array( 'array_merge', $files_found_chunks );
$files = $this->filter_modified_files( $files );
if ( ! $files ) {
$this->clear_items_to_scan_buffer();
}
$result = array(
'files' => $files,
'no_files_message' => __( 'Files already scanned.', 'wpml-string-translation' ),
);
}
wp_send_json_success( $result );
}
private function clear_items_to_scan_buffer() {
wpml_get_admin_notices()->remove_notice(
WPML_ST_Themes_And_Plugins_Settings::NOTICES_GROUP,
WPML_ST_Themes_And_Plugins_Updates::WPML_ST_SCAN_NOTICE_ID
);
delete_option( WPML_ST_Themes_And_Plugins_Updates::WPML_ST_ITEMS_TO_SCAN );
}
/**
* @param array $files
*
* @return array
*/
private function filter_modified_files( $files ) {
$modified_files = array();
foreach ( $files as $file ) {
if ( $this->file_hashing->hash_changed( $file ) ) {
$modified_files[] = $file;
}
}
return $modified_files;
}
/** @return array */
private function get_folder() {
$folder = array();
if ( array_key_exists( 'theme', $_POST ) ) {
$folder[] = get_theme_root() . '/' . sanitize_text_field( $_POST['theme'] );
} elseif ( array_key_exists( 'plugin', $_POST ) ) {
$plugin_folder = explode( '/', $_POST['plugin'] );
$folder[] = WPML_PLUGINS_DIR . '/' . sanitize_text_field( $plugin_folder[0] );
} elseif ( array_key_exists( 'mu-plugin', $_POST ) ) {
$folder[] = WPMU_PLUGIN_DIR . '/' . sanitize_text_field( $_POST['mu-plugin'] );
}
return $folder;
}
private function is_one_file_plugin() {
$is_one_file_plugin = false;
if ( array_key_exists( 'plugin', $_POST ) ) {
$is_one_file_plugin = false === strpos( $_POST['plugin'], 'plugins/' );
}
if ( array_key_exists( 'mu-plugin', $_POST ) ) {
$is_one_file_plugin = false === strpos( $_POST['mu-plugin'], 'mu-plugins/' );
}
return $is_one_file_plugin;
}
/**
* @return array
*/
private function get_folders_to_ignore() {
$folders = [
WPML_ST_Scan_Dir::PLACEHOLDERS_ROOT . '/node_modules',
WPML_ST_Scan_Dir::PLACEHOLDERS_ROOT . '/tests',
];
return $folders;
}
}