=== $table_name; // phpcs:enable WordPress.DB.PreparedSQL if (!$exists) { $this->dbDeltaCountCache(); } $joins[] = "LEFT JOIN {$table_name} AS rmlicl ON tn.id = rmlicl.fid"; return $joins; } /** * Load the cnt from the WPML count cache table. * * @param string[] $fields * @return string[] */ public function sqlstatement_select_fields($fields) { global $sitepress; $currentLanguage = $sitepress->get_current_language(); $escaped = Util::getInstance()->esc_sql_name($currentLanguage); $fields[1] = "rmlicl.`cnt_{$escaped}` AS cnt, IFNULL(rmlicl.`cnt_{$escaped}`, (\n " . $this->getSingleCountSql($currentLanguage, 'tn.id') . ' )) AS cnt_result'; return $fields; } /** * Get the single SQL for the subquery of count getter. * * @param string $code * @param string $fieldId * @return string */ public function getSingleCountSql($code, $fieldId = 'tn.fid') { global $wpdb; $table_name_posts = $this->getTableName('posts'); $where = empty($fieldId) ? '' : "WHERE rmlpostscnt.fid = {$fieldId}"; return "SELECT COUNT(*) FROM {$table_name_posts} AS rmlpostscnt\n \tINNER JOIN " . $wpdb->prefix . "icl_translations AS wpmlt\n \tON wpmlt.element_id = rmlpostscnt.attachment\n \tAND wpmlt.element_type = 'post_attachment'\n \tAND wpmlt.language_code = '{$code}'\n \t{$where}"; } /** * Update the count cache for WPML regarding the active languages. * * @param int[] $folders * @param int[] $attachments * @param string $where */ public function updateCountCache($folders, $attachments, $where) { global $wpdb, $sitepress; $table_name = $this->getTableName(); $table_name_icl = $this->getTableName('icl_count'); $table_name_posts = $this->getTableName('posts'); $langs = $this->getActiveLanguages(); $where = $where !== 'tn.cnt IS NULL' ? \str_replace('tn.id', 'tn.fid', $where) : '1=1'; // Keep both tables synced (performance should be good because both queries use the best available index) // phpcs:disable WordPress.DB.PreparedSQL $wpdb->query("INSERT IGNORE INTO {$table_name_icl} (`fid`) SELECT id FROM {$table_name}"); $wpdb->query("DELETE rmlicl FROM {$table_name_icl} AS rmlicl WHERE NOT EXISTS(SELECT * FROM {$table_name} AS rml WHERE rml.id = rmlicl.fid)"); // phpcs:enable WordPress.DB.PreparedSQL // Sync available languages counts $setters = []; $readers = []; foreach ($langs as $code) { $escaped = Util::getInstance()->esc_sql_name($code); $setters[] = "tn.`cnt_{$escaped}` = curr.`cnt_{$escaped}`"; // phpcs:disable WordPress.DB.PreparedSQL $readers[] = $wpdb->prepare("SUM(IF(wpmlt.language_code = %s, 1, 0)) AS `cnt_{$escaped}`", $code); // phpcs:enable WordPress.DB.PreparedSQL } // Create UPDATE query // phpcs:disable WordPress.DB.PreparedSQL $sqlStatement = "UPDATE {$table_name_icl} AS tn\n INNER JOIN (\n SELECT rmlic.fid, " . \join(',', $readers) . "\n FROM {$table_name_icl} rmlic\n LEFT JOIN {$table_name_posts} rmlpostscnt\n ON rmlpostscnt.fid = rmlic.fid\n LEFT JOIN " . $wpdb->prefix . "icl_translations wpmlt\n ON wpmlt.element_id = rmlpostscnt.attachment\n AND wpmlt.element_type = 'post_attachment'\n GROUP BY rmlic.fid\n ) curr\n ON curr.fid = tn.fid\n SET " . \join(',', $setters) . "\n WHERE {$where}"; $wpdb->query($sqlStatement); // phpcs:enable WordPress.DB.PreparedSQL $this->debug('WPML: Update count cache table', __METHOD__); } /** * Reset the count cache for WPML regarding the active languages. * * @param int $folderId */ public function resetCountCache($folderId) { global $wpdb; $table_name = $this->getTableName('icl_count'); // phpcs:disable WordPress.DB.PreparedSQL if (\is_array($folderId)) { $wpdb->query("DELETE FROM {$table_name} WHERE fid IN (" . \implode(',', $folderId) . ')'); } else { $wpdb->query("DELETE FROM {$table_name}"); } // phpcs:enable WordPress.DB.PreparedSQL } /** * Fired when wpml language gets activated. */ public function wpml_update_active_languages() { $this->debug('WPML: Update active languages in count cache table', __METHOD__); $this->dbDeltaCountCache(); } /** * Create a count cache table with dbDelta functionality. */ public function dbDeltaCountCache() { if (!$this->isActive()) { return \false; } $this->getCore()->getActivator()->install(\false, [$this, '_dbDeltaCountCache']); return \true; } /** * Create the icl_count table. */ public function _dbDeltaCountCache() { $charset_collate = $this->getCore()->getActivator()->getCharsetCollate(); $table_name = $this->getTableName('icl_count'); $langs = $this->getActiveLanguages(); if (\count($langs) > 0) { $keys = ''; foreach ($langs as $code) { $escaped = Util::getInstance()->esc_sql_name($code); $keys .= "`cnt_{$escaped}` mediumint(10) DEFAULT NULL,\n \t\t "; } $sql = "CREATE TABLE {$table_name} (\n \t\t fid mediumint(9) NOT NULL,\n \t\t " . \trim($keys) . "\n \t\t PRIMARY KEY (fid)\n \t\t) {$charset_collate};"; \dbDelta($sql); // CountCache::getInstance()->updateCountCache(); } } /** * Register option for PolyLang. */ public function options_register() { \register_setting('media', 'rml_wpml_move', 'esc_attr'); \add_settings_field('rml_wpml_move', '', [$this, 'html_options_move'], 'media', 'rml_options_general'); } /** * Option to move files also when a translation gets moved. */ public function html_options_move() { $value = \get_option('rml_wpml_move', '1'); echo ' '; } /** * A file is moved (not copied) and then move also all the translations. * * @param int $folderId * @param int[] $ids * @param IFolder $folder * @param boolean $isShortcut */ public function item_move_finished($folderId, $ids, $folder, $isShortcut) { if (\get_option('rml_wpml_move', '1') === '1' && \json_encode($ids) !== \json_encode($this->previousIds) && $folderId !== $this->previousFolderId) { global $sitepress; $moveToFolder = []; $this->previousFolderId = $folderId; $this->previousIds = $ids; // Iterate all moved ids foreach ($ids as $post_id) { $trid = $sitepress->get_element_trid($post_id); $translations = $sitepress->get_element_translations($trid, 'post_attachment'); // Iterate all translation ids foreach ($translations as $tr) { $tr_id = \intval($tr->element_id); if (!\in_array($tr_id, $ids, \true)) { $moveToFolder[] = $tr_id; } } } if (\count($moveToFolder) > 0) { $this->debug("WPML: While moving to folder {$folderId} there are some translations which also must be moved: " . \json_encode($moveToFolder), __METHOD__); \wp_rml_move($folderId, $moveToFolder); } } } /** * New translation created => synchronize with original post. * Then reset the count cache for the unorganized folder. * * @param int $post_id * @param int $tr_id */ public function wpml_media_create_duplicate_attachment($post_id, $tr_id) { $folderId = \wp_attachment_folder($post_id); \_wp_rml_synchronize_attachment($tr_id, $folderId); $this->debug('WPML: Move translation id ' . $tr_id . ' to the original file (' . $post_id . ') folder id ' . $folderId, __METHOD__); CountCache::getInstance()->addNewAttachment($tr_id)->resetCountCacheOnWpDie(\_wp_rml_root()); } /** * Count attachments through WPML tables. * * @param int $count * @return int * @see https://wpml.org/forums/topic/wp_count_posts/ */ public function wpml_count_attachments($count) { global $wpdb, $sitepress; $lang = $sitepress->get_current_language(); $table_name = $wpdb->prefix . 'icl_translations'; // phpcs:disable WordPress.DB.PreparedSQL return (int) $wpdb->get_var("SELECT COUNT(*)\n FROM {$table_name} AS wpmlt\n INNER JOIN {$wpdb->posts} AS p ON p.id = wpmlt.element_id\n WHERE wpmlt.element_type = 'post_attachment'\n AND wpmlt.language_code = '{$lang}'"); // phpcs:enable WordPress.DB.PreparedSQL } /** * Check if current active language is default. * * @return boolean */ public function isDefaultLanguage() { global $sitepress; return $sitepress->get_current_language() === $sitepress->get_default_language(); } /** * Get the default id for an attachment. * * @param int $attachment * @return int */ public function getDefaultId($attachment) { global $sitepress; return \apply_filters('wpml_object_id', $attachment, 'post', \true, $sitepress->get_default_language()); } /** * Get active WPML language codes. * * @return string[] */ public function getActiveLanguages() { return \array_keys(\apply_filters('wpml_active_languages', [])); } /** * Check if WPML plugin is active. */ public function isActive() { return \is_plugin_active('sitepress-multilingual-cms/sitepress.php') && \apply_filters('wpml_is_translated_post_type', \false, 'attachment'); } /** * Get instance. * * @return WPML */ public static function getInstance() { return self::$me === null ? self::$me = new \MatthiasWeb\RealMediaLibrary\comp\WPML() : self::$me; } }