Changeset 2774075
- Timestamp:
- 08/23/2022 12:20:07 PM (4 years ago)
- Location:
- memsource-connector/trunk
- Files:
-
- 12 edited
-
memsource.php (modified) (3 diffs)
-
readme.txt (modified) (1 diff)
-
src/Controller/ContentController.php (modified) (4 diffs)
-
src/Parser/ShortcodeParser.php (modified) (2 diffs)
-
src/Service/Content/AbstractPostService.php (modified) (5 diffs)
-
src/Service/CustomFieldService.php (modified) (11 diffs)
-
src/Service/ExternalPlugin/ElementorPlugin.php (modified) (1 diff)
-
src/Service/OptionsService.php (modified) (3 diffs)
-
src/Service/TranslationPlugin/ITranslationPlugin.php (modified) (1 diff)
-
src/Service/TranslationPlugin/MultilingualpressPlugin.php (modified) (2 diffs)
-
src/Service/TranslationPlugin/NonExistingPlugin.php (modified) (1 diff)
-
src/Service/TranslationPlugin/WPMLPlugin.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
memsource-connector/trunk/memsource.php
r2746961 r2774075 5 5 Plugin URI: https://help.memsource.com/hc/en-us/articles/360012208319-WordPress-Connector 6 6 Description: Localize WordPress websites with the help of professional translation tools: translation memories, terminology bases and quality checkers. 7 Version: 3. 4.37 Version: 3.5.0 8 8 Text Domain: memsource 9 9 Domain Path: /locale … … 19 19 20 20 define('MEMSOURCE_PLUGIN_PATH', dirname(__FILE__)); 21 define('MEMSOURCE_PLUGIN_VERSION', '3. 4.3');21 define('MEMSOURCE_PLUGIN_VERSION', '3.5.0'); 22 22 define('MEMSOURCE_PLUGIN_DIR_URL', plugin_dir_url(__FILE__)); 23 23 … … 181 181 function memsource_check_php_version() { 182 182 $php_version = phpversion(); 183 if (!version_compare($php_version, '7. 0', '>=')) {184 wp_die(__(sprintf('Plugin requires PHP 7. 0or higher. Your version is %s. Please, update the version.', $php_version), 'memsource-connector'));183 if (!version_compare($php_version, '7.3', '>=')) { 184 wp_die(__(sprintf('Plugin requires PHP 7.3 or higher. Your version is %s. Please, update the version.', $php_version), 'memsource-connector')); 185 185 } 186 186 } -
memsource-connector/trunk/readme.txt
r2746961 r2774075 29 29 == Changelog == 30 30 31 = 3.5.0 = 32 *Release Date - 23 Aug 2022* 33 34 * Added SEOPress support 35 * All taxonomies are now transferred to the translation 36 * The lowest supported PHP version is now 7.3 37 * Various bug fixes 38 31 39 = 3.4.3 = 32 40 *Release Date - 23 Jun 2022* -
memsource-connector/trunk/src/Controller/ContentController.php
r2722771 r2774075 17 17 final class ContentController extends \WP_REST_Controller 18 18 { 19 private const IGNORED_CONTENT_TYPES = [ 20 'acf-field', 21 ]; 22 19 23 /** @var \wpdb */ 20 24 private $wpdb; … … 99 103 * Add a content service for endpoints. 100 104 * @param $content IContentService 101 * @return IContentService105 * @return void 102 106 * @throws \Exception 103 107 */ 104 108 public function addContentService(IContentService $content) 105 109 { 110 if (in_array($content->getType(), self::IGNORED_CONTENT_TYPES)) { 111 return; 112 } 113 106 114 if (!isset($this->contentServices[$content->getType()])) { 107 115 $this->contentServices[$content->getType()] = $content; 108 return $content; 109 } 116 return; 117 } 118 110 119 throw new \Exception(sprintf('Content type \'%s\' is registered already.', $content->getType())); 111 120 } … … 284 293 285 294 /** 295 * @deprecated This endpoint will be present for a while due to backward compatibility. 286 296 * @param $request \WP_REST_Request 287 297 * @param $response \WP_REST_Response … … 290 300 private function storeLastProcessedId(\WP_REST_Request $request, \WP_REST_Response $response) 291 301 { 292 $contentType = $request->get_param('type') ?: PostService::TYPE; 293 if ($contentType === PostService::TYPE) { 294 /** @var $contentService \Memsource\Service\Content\PostService */ 295 $contentService = $this->getContentService(PostService::TYPE); 296 $id = $contentService->storeLastProcessedId(); 297 $response->set_data($id); 298 return; 299 } 300 301 $response->set_status(400); 302 $response->set_data(['error' => 'Invalid type of content.', 'contentType' => $contentType]); 302 $response->set_data(['status' => 'OK']); 303 303 } 304 304 -
memsource-connector/trunk/src/Parser/ShortcodeParser.php
r2746961 r2774075 231 231 $translatedText = html_entity_decode($extractedText); 232 232 } 233 $translatedText = str_replace('$', '\$', $translatedText); 233 234 $shortcodeWithId = $shortcode . ":" . $uniqueId; 234 235 $storedContent = preg_replace( … … 258 259 } 259 260 $translatedText = html_entity_decode($match[3]); 261 $translatedText = str_replace('$', '\$', $translatedText); 260 262 $attributeWithId = $attribute . ":" . $uniqueId; 261 263 $storedContent = preg_replace( 262 "| ${attributeWithId}=[\"'].*?[\"']|sm", " ${attribute}=${delimiter}${translatedText}${delimiter}", 264 "| ${attributeWithId}=[\"'].*?[\"']|sm", 265 " ${attribute}=${delimiter}${translatedText}${delimiter}", 263 266 $storedContent 264 267 ); -
memsource-connector/trunk/src/Service/Content/AbstractPostService.php
r2722771 r2774075 60 60 // turn off paging to return all posts 61 61 $queryArgs = ['post_type' => $this->getType(), 'nopaging' => true, 'post_status' => $this->optionsService->getListStatuses()]; 62 $lastId = 0;63 64 if (isset($_GET['newPosts'])) {65 $lastId = $this->optionsService->getLastProcessedId();66 }67 68 62 $postsQuery = new \WP_Query(); 69 63 $this->filterService->addQueryFilters($postsQuery, true); … … 76 70 $post = $this->getLastRevision($post); 77 71 if ( 78 $post->ID > $lastId79 &&80 72 ( 81 73 $post->post_content != '' … … 161 153 } 162 154 163 public function storeLastProcessedId()164 {165 // compare with stored ID and save only a higher one166 $stored_last_id = $this->optionsService->getLastProcessedId();167 $new_last_id = $_POST['lastId'];168 // find the last revision ID169 $last_revision = $this->getLastRevision(get_post($new_last_id));170 if ($last_revision) {171 $new_last_id = $last_revision->ID;172 }173 $overwrite = isset($_POST['overwrite']);174 if ($overwrite || $new_last_id > $stored_last_id) {175 $this->optionsService->updateLastProcessedId($new_last_id);176 return ['id' => $new_last_id];177 }178 return ['id' => $stored_last_id];179 }180 181 155 public function getPost($original_post_id) 182 156 { … … 249 223 update_post_meta($sourcePostId, '_wpml_post_translation_editor_native', 'yes'); 250 224 251 // transfer categories from source to target 252 $sourceCategories = wp_get_post_categories($sourcePostId); 253 if (is_array($sourceCategories)) { 254 $this->translationPlugin->updatePostCategories($sourceCategories, $targetPostId, $language); 255 } 225 // transfer all terms from source to target 226 $this->transferTermsFromSourceToTarget($sourcePostId, $targetPostId, $language); 256 227 257 228 // copy featured image to target … … 367 338 return $json; 368 339 } 340 341 /** 342 * Go through all taxonomies and add already translated terms to the translated post. 343 * 344 * @param int $sourcePostId Source post ID 345 * @param int $targetPostId Target post ID 346 * @param string $language Translation language 347 * 348 * @return void 349 */ 350 private function transferTermsFromSourceToTarget(int $sourcePostId, int $targetPostId, string $language) { 351 foreach (get_taxonomies() as $taxonomy) { 352 $sourceTerms = wp_get_post_terms($sourcePostId, $taxonomy, ['fields' => 'ids']); 353 if (is_array($sourceTerms)) { 354 $this->translationPlugin->transferPostTerms($taxonomy, $sourceTerms, $targetPostId, $language); 355 } 356 } 357 } 369 358 } -
memsource-connector/trunk/src/Service/CustomFieldService.php
r2722771 r2774075 14 14 const CUSTOMFIELD_META_CONTENT_TYPE = 'customfield_meta'; 15 15 16 const YOAST_SEO_TAG_START = '< !--yoast_wpseo_tag';17 const YOAST_SEO_TAG_END = ' _yoast_wpseo_tag-->';16 const YOAST_SEO_TAG_START = '<yoast_seo_tag_'; 17 const YOAST_SEO_TAG_END = '/>'; 18 18 const YOAST_SEO_CUSTOM_FIELD_PREFIX = '_yoast_wpseo_'; 19 const YOAST_SEO_CUSTOM_REPLACEMENT_PREFIX = 'yoast_seo_tag_'; 20 21 const SEOPRESS_TAG_START = '<seo_press_tag_'; 22 const SEOPRESS_TAG_END = '/>'; 23 const SEOPRESS_CUSTOM_FIELD_PREFIX = '_seopress_'; 24 const SEOPRESS_CUSTOM_REPLACEMENT_PREFIX = 'seo_press_tag_'; 19 25 20 26 const RESULT_CUSTOM_FIELDS = 'customFields'; 21 27 const RESULT_PLACEHOLDERS = 'placeholders'; 22 28 23 private $ translatableSystemCustomFields= [29 private $customFieldsWhiteList = [ 24 30 '_yoast_wpseo_focuskw', 25 31 '_yoast_wpseo_title', … … 30 36 '_yoast_wpseo_twitter-title', 31 37 '_yoast_wpseo_twitter-description', 38 '_seopress_titles_title', 39 '_seopress_titles_desc', 40 '_seopress_social_fb_title', 41 '_seopress_social_fb_desc', 42 '_seopress_social_twitter_title', 43 '_seopress_social_twitter_desc', 44 '_seopress_robots_canonical', 45 '_seopress_analysis_target_kw', 32 46 ]; 33 47 … … 45 59 46 60 public function __construct( 47 ElementorPlugin $elementorPlugin,61 ElementorPlugin $elementorPlugin, 48 62 TranslationWorkflowService $translationWorkflowService, 49 AuthUtils $authUtils, 50 PlaceholderService $placeholderService 51 ) { 63 AuthUtils $authUtils, 64 PlaceholderService $placeholderService 65 ) 66 { 52 67 $this->elementorPlugin = $elementorPlugin; 53 68 $this->translationWorkflowService = $translationWorkflowService; … … 68 83 $customFields[$key]['meta_value'] = (string)$row['meta_value']; 69 84 70 if ($this->elementorPlugin->isElementorDataField($row['meta_key'])) { 85 if ($this->elementorPlugin->isElementorDataField($row['meta_key']) && 86 $this->elementorPlugin->isPostCreatedByElementorPlugin($postId)) { 71 87 $token = $this->authUtils->generateRandomToken(); 72 88 $placeholders[$token] = sprintf('<!--_elementor_data_%s-->', $row['meta_value']); … … 202 218 203 219 return 204 ($firstChar === '_' && !in_array($customFieldName, $this-> translatableSystemCustomFields))220 ($firstChar === '_' && !in_array($customFieldName, $this->customFieldsWhiteList)) 205 221 || in_array($customFieldName, $translationWorkflowFields, true); 206 222 } … … 305 321 306 322 $value = $this->encodeFieldIfSerialized($value); 307 $value = $this->encodeYoast SeoVariables($key, $value);323 $value = $this->encodeYoastAndSeopressVariables($key, $value); 308 324 309 325 return sprintf('<div data-type="custom_field_v2" data-source-id="%d" data-key="%s"><div id="value">%s</div></div>', $sourceId, $key, $value); … … 311 327 312 328 /** 313 * Convert Yoast SEOvariables to HTML comments (and tags in Memsource).329 * Convert Yoast and SEOPRESS variables to HTML comments (and tags in Memsource). 314 330 * 315 331 * @param string $customFieldName … … 318 334 * @return string 319 335 */ 320 public function encodeYoastSeoVariables(string $customFieldName, string $customFieldValue): string 321 { 322 if (substr($customFieldName, 0, strlen(self::YOAST_SEO_CUSTOM_FIELD_PREFIX)) !== self::YOAST_SEO_CUSTOM_FIELD_PREFIX) { 323 return $customFieldValue; 324 } 325 326 return preg_replace( 327 "|(%%[a-z_]*%%)|sm", 328 self::YOAST_SEO_TAG_START . '${1}' . self::YOAST_SEO_TAG_END, 329 $customFieldValue 330 ); 336 public function encodeYoastAndSeopressVariables(string $customFieldName, string $customFieldValue): string 337 { 338 if ((strpos($customFieldName, self::YOAST_SEO_CUSTOM_FIELD_PREFIX) === 0) && $customFieldValue) { 339 $pattern = '|(%%[a-z_]*%%)|sm'; 340 preg_match_all($pattern, $customFieldValue, $matches); 341 342 foreach ($matches[0] ?? [] as $match) { 343 $replacement = self::YOAST_SEO_TAG_START . str_replace('%%', '', $match) . self::YOAST_SEO_TAG_END; 344 $customFieldValue = str_replace($match, $replacement, $customFieldValue); 345 346 } 347 } 348 349 if ((strpos($customFieldName, self::SEOPRESS_CUSTOM_FIELD_PREFIX) === 0) && $customFieldValue) { 350 $pattern = '|(%%[a-z_]*%%)|sm'; 351 preg_match_all($pattern, $customFieldValue, $matches); 352 353 foreach ($matches[0] ?? [] as $match) { 354 $replacement = self::SEOPRESS_TAG_START . str_replace('%%', '', $match) . self::SEOPRESS_TAG_END; 355 $customFieldValue = str_replace($match, $replacement, $customFieldValue); 356 } 357 } 358 359 return $customFieldValue; 331 360 } 332 361 … … 379 408 foreach ($matches ?: [] as $match) { 380 409 $value = $match[3]; 381 $value = $this->removeYoast SeoTags($value);410 $value = $this->removeYoastAndSeoPluginTags($value); 382 411 383 412 if ($this->elementorPlugin->isElementorDataField($match[2])) { … … 397 426 398 427 /** 399 * Remove HTML comments around Yoast SEOvariables.428 * Remove HTML comments around Yoast and SEOPRESS variables. 400 429 * 401 430 * @param string $customFieldValue 402 431 * @return string 403 432 */ 404 public function removeYoastSeoTags(string $customFieldValue): string 405 { 406 $customFieldValue = str_replace(self::YOAST_SEO_TAG_START, '', $customFieldValue); 407 $customFieldValue = str_replace(self::YOAST_SEO_TAG_END, '', $customFieldValue); 433 public function removeYoastAndSeoPluginTags(string $customFieldValue): string 434 { 435 if (strpos($customFieldValue, self::YOAST_SEO_CUSTOM_REPLACEMENT_PREFIX) !== false || strpos($customFieldValue, self::SEOPRESS_CUSTOM_REPLACEMENT_PREFIX) !== false) { 436 437 $pattern = '|<[^>]*>|sm'; 438 preg_match_all($pattern, $customFieldValue, $matches); 439 440 foreach ($matches[0] ?? [] as $match) { 441 $replacement = ''; 442 443 if (strpos($match, self::YOAST_SEO_CUSTOM_REPLACEMENT_PREFIX) !== false) { 444 $replacement = str_replace(self::YOAST_SEO_CUSTOM_REPLACEMENT_PREFIX, '', $match); 445 } 446 if (strpos($match, self::SEOPRESS_CUSTOM_REPLACEMENT_PREFIX) !== false) { 447 $replacement = str_replace(self::SEOPRESS_CUSTOM_REPLACEMENT_PREFIX, '', $match); 448 } 449 450 $replacement = '%%' . substr($replacement, 1, -2) . '%%'; 451 452 $customFieldValue = str_replace($match, $replacement, $customFieldValue); 453 454 } 455 } 408 456 409 457 return $customFieldValue; … … 499 547 global $wpdb; 500 548 501 $query = "SELECT post_excerpt as 'field' FROM $wpdb->posts where post_type = 'acf-field'";549 $query = "SELECT post_excerpt as 'field' FROM $wpdb->posts where post_type = 'acf-field'"; 502 550 $results = $wpdb->get_results($query, ARRAY_A); 503 551 -
memsource-connector/trunk/src/Service/ExternalPlugin/ElementorPlugin.php
r2730911 r2774075 256 256 public function isPostCreatedByElementorPlugin($postId): bool 257 257 { 258 global $wpdb; 259 260 $table = $wpdb->postmeta; 261 $query = $wpdb->prepare('SELECT * FROM ' . $table . ' WHERE post_id = %d', $postId); 262 $result = $wpdb->get_results($query, ARRAY_A) ?: []; 263 264 foreach ($result as $row) { 265 if ($this->isElementorDataField($row['meta_key'])) { 266 return true; 267 } 268 } 269 270 return false; 258 $document = Plugin::$instance->documents->get($postId); 259 260 return $document && $document->is_built_with_elementor(); 271 261 } 272 262 -
memsource-connector/trunk/src/Service/OptionsService.php
r2643752 r2774075 20 20 private $OPTION_TOKEN = 'memsource_token'; 21 21 private $OPTION_ADMIN_USER = 'memsource_admin_user'; 22 private $OPTION_LAST_PROCESSED_ID = 'memsource_last_processed_id';23 22 private $OPTION_LIST_STATUS = 'memsource_list_status'; 24 23 private $OPTION_INSERT_STATUS = 'memsource_insert_status'; … … 39 38 add_option($this->OPTION_TOKEN, AuthUtils::createNewToken()); 40 39 add_option($this->OPTION_ADMIN_USER, get_current_user_id()); 41 add_option($this->OPTION_LAST_PROCESSED_ID, 0);42 40 add_option($this->OPTION_LIST_STATUS, 'publish'); 43 41 add_option($this->OPTION_INSERT_STATUS, 'publish'); … … 113 111 } 114 112 115 public function updateLastProcessedId($id) {116 return update_option($this->OPTION_LAST_PROCESSED_ID, $id);117 }118 119 public function getLastProcessedId() {120 return get_option($this->OPTION_LAST_PROCESSED_ID);121 }122 123 113 public function getAdminUser() { 124 114 return get_option($this->OPTION_ADMIN_USER); -
memsource-connector/trunk/src/Service/TranslationPlugin/ITranslationPlugin.php
r2611482 r2774075 79 79 * If possible, assign proper categories to the translation. 80 80 * 81 * @param int[] $sourceCategories categories of a source post 81 * @param string $taxonomy Taxonomy name, for example 'category' or 'post_tag' 82 * @param int[] $sourceTermsIds Categories of a source post 82 83 * @param int $targetPostId Translated post ID 84 * @param string $targetLanguage Target language 83 85 * 84 86 * @return mixed 85 87 */ 86 public function updatePostCategories(array $sourceCategories, int $targetPostId, string $targetLanguage);88 public function transferPostTerms(string $taxonomy, array $sourceTermsIds, int $targetPostId, string $targetLanguage); 87 89 88 90 /** -
memsource-connector/trunk/src/Service/TranslationPlugin/MultilingualpressPlugin.php
r2611482 r2774075 123 123 } 124 124 125 public function updatePostCategories(array $sourceCategories, int $targetPostId, string $targetLanguage)125 public function transferPostTerms(string $taxonomy, array $sourceTermsIds, int $targetPostId, string $targetLanguage) 126 126 { 127 127 $api = $this->api(); … … 129 129 $targetSiteId = $this->getSiteIdByLang($targetLanguage); 130 130 131 $target Categories = [];132 133 foreach ($source Categories as $sourceCategoryId) {134 $translationId = $api->contentIdForSite(get_current_blog_id(), $source CategoryId, ContentRelations::CONTENT_TYPE_TERM, $targetSiteId);131 $targetTerms = []; 132 133 foreach ($sourceTermsIds as $sourceTermId) { 134 $translationId = $api->contentIdForSite(get_current_blog_id(), $sourceTermId, ContentRelations::CONTENT_TYPE_TERM, $targetSiteId); 135 135 136 136 if ($translationId !== null) { 137 $target Categories[] = $translationId;138 } 139 } 140 141 if (!empty($target Categories)) {142 $mainBlogId = $this->switchToSite($targetSiteId); 143 wp_set_post_ categories($targetPostId, $targetCategories);137 $targetTerms[] = $translationId; 138 } 139 } 140 141 if (!empty($targetTerms)) { 142 $mainBlogId = $this->switchToSite($targetSiteId); 143 wp_set_post_terms($targetPostId, $targetTerms, $taxonomy); 144 144 $this->switchToSite($mainBlogId); 145 145 } -
memsource-connector/trunk/src/Service/TranslationPlugin/NonExistingPlugin.php
r2611482 r2774075 70 70 } 71 71 72 public function updatePostCategories(array $sourceCategories, int $targetPostId, string $targetLanguage)72 public function transferPostTerms(string $taxonomy, array $sourceTermsIds, int $targetPostId, string $targetLanguage) 73 73 { 74 74 } -
memsource-connector/trunk/src/Service/TranslationPlugin/WPMLPlugin.php
r2643752 r2774075 102 102 } 103 103 104 public function updatePostCategories(array $sourceCategories, int $targetPostId, string $targetLanguage) 105 { 106 $pluginContentType = $this->convertTermTypeToWpmlType('category'); 107 $defaultSourceCategory = get_option('default_category'); 108 $targetCategories = []; 109 110 foreach ($sourceCategories as $sourceCategoryId) { 111 $translationId = $this->getTranslationId($pluginContentType, $sourceCategoryId, $targetLanguage); 104 public function transferPostTerms(string $taxonomy, array $sourceTermsIds, int $targetPostId, string $targetLanguage) 105 { 106 $defaultSourceCategory = null; 107 if ($taxonomy === 'category') { 108 $defaultSourceCategory = get_option('default_category'); 109 } 110 $pluginContentType = $this->convertTermTypeToWpmlType($taxonomy); 111 $targetTerms = []; 112 113 foreach ($sourceTermsIds as $sourceTermId) { 114 $translationId = $this->getTranslationId($pluginContentType, $sourceTermId, $targetLanguage); 112 115 113 116 if ($translationId !== null) { 114 $target Categories[] = $translationId;115 } 116 } 117 118 if (!empty($target Categories)) {119 wp_set_post_ categories($targetPostId, $targetCategories);117 $targetTerms[] = $translationId; 118 } 119 } 120 121 if (!empty($targetTerms)) { 122 wp_set_post_terms($targetPostId, $targetTerms, $taxonomy); 120 123 } elseif (is_numeric($defaultSourceCategory)) { 121 124 $translationId = $this->getTranslationId($pluginContentType, $defaultSourceCategory, $targetLanguage); … … 257 260 } 258 261 259 return $translation[$targetLanguage] ?? null; 262 if (!isset($translation[$targetLanguage])) { 263 return null; 264 } 265 266 return (int) $translation[$targetLanguage]; 260 267 } 261 268
Note: See TracChangeset
for help on using the changeset viewer.