Skip to content

Commit 5085d25

Browse files
add support for elementor internal links (WP-962)
1 parent 6822870 commit 5085d25

14 files changed

Lines changed: 248 additions & 39 deletions

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "smartling/wordpress-connector",
33
"license": "GPL-2.0-or-later",
4-
"version": "4.3.6",
4+
"version": "4.3.7",
55
"description": "",
66
"type": "wordpress-plugin",
77
"repositories": [
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Smartling\ContentTypes\Elementor;
4+
5+
interface DynamicTagManager
6+
{
7+
public function tag_text_to_tag_data(string $tagText): ?array;
8+
9+
public function tag_data_to_tag_text(string $tagId, string $tagName, array $settings): string;
10+
}

inc/Smartling/ContentTypes/Elementor/ElementAbstract.php

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Smartling\ContentTypes\Elementor;
44

55
use Elementor\Core\DynamicTags\Manager;
6+
use Smartling\ContentTypes\ContentTypeHelper;
67
use Smartling\ContentTypes\ExternalContentElementor;
78
use Smartling\Helpers\ArrayHelper;
89
use Smartling\Helpers\LoggerSafeTrait;
@@ -13,7 +14,8 @@
1314
abstract class ElementAbstract implements Element {
1415
use LoggerSafeTrait;
1516
protected const SETTING_KEY_DYNAMIC = '__dynamic__';
16-
protected const SETTING_KEY_POPUP = 'popup';
17+
protected const DYNAMIC_INTERNAL_URL = 'internal-url';
18+
protected const DYNAMIC_POPUP = 'popup';
1719

1820
protected array $elements;
1921
protected string $id;
@@ -98,11 +100,18 @@ public function setRelations(
98100
): static {
99101
$arrayHelper = new ArrayHelper();
100102
$result = clone $this;
103+
$contentType = $content->getType() === ContentTypeHelper::CONTENT_TYPE_POST ?
104+
$externalContentElementor->getWpProxy()->get_post_type($content->getId()) :
105+
$content->getType();
106+
if ($contentType === false) {
107+
$this->getLogger()->debug("Unable to get post type for contentId={$content->getId()}, proceeding with unknown type");
108+
$contentType = ContentTypeHelper::CONTENT_TYPE_UNKNOWN;
109+
}
101110
$targetId = $externalContentElementor->getTargetId(
102111
$submission->getSourceBlogId(),
103112
$content->getId(),
104113
$submission->getTargetBlogId(),
105-
$content->getType(),
114+
$contentType,
106115
);
107116
if ($targetId !== null) {
108117
$result->raw = array_replace_recursive(
@@ -166,7 +175,7 @@ public function isDynamicProperty(string $path): bool
166175
return str_contains($path, self::SETTING_KEY_DYNAMIC);
167176
}
168177

169-
public function getDynamicTagsManager(): ?Manager
178+
public function getDynamicTagsManager(): DynamicTagManager|Manager|null
170179
{
171180
if (class_exists(Manager::class)) {
172181
return new Manager();
@@ -187,24 +196,32 @@ public function getDynamicTagsManager(): ?Manager
187196
return null;
188197
}
189198

199+
// $value must be string to be converted back to tag
190200
public function replaceDynamicTagSetting(string $tag, string $value): string
191201
{
192202
$dynamicTagsManager = $this->getDynamicTagsManager();
193203
if ($dynamicTagsManager === null) {
194204
$this->getLogger()->info("Elementor dynamic tags manager not available, skip replacing tag=\"$tag\", value=\"$value\"");
205+
return $tag;
195206
}
196207
try {
197208
$tagData = $dynamicTagsManager->tag_text_to_tag_data($tag);
198209
} catch (\Throwable $e) {
199210
$this->getLogger()->warning("Unable to convert Elementor tagText=\"$tag\" to array, value=\"$value\": {$e->getMessage()}");
200211
return $tag;
201212
}
202-
if (($tagData['name'] ?? '') !== self::SETTING_KEY_POPUP) {
203-
$this->getLogger()->warning("Unknown Elementor tag encountered, skipping replacement, tagText=\"$tag\"");
204-
return $tag;
213+
switch ($tagData['name'] ?? '') {
214+
case self::DYNAMIC_INTERNAL_URL:
215+
$tagData['settings']['post_id'] = $value;
216+
break;
217+
case self::DYNAMIC_POPUP:
218+
$tagData['settings'][self::DYNAMIC_POPUP] = $value;
219+
break;
220+
default:
221+
$this->getLogger()->warning("Unknown Elementor tag encountered, skipping replacement, tagText=\"$tag\"");
222+
return $tag;
205223
}
206224
try {
207-
$tagData['settings'][self::SETTING_KEY_POPUP] = $value; // $value must be string in order to be converted back to tag
208225
$tagText = $dynamicTagsManager->tag_data_to_tag_text(...array_values($tagData));
209226
if ($tagText === '') {
210227
$this->getLogger()->debug('No tag text returned by manager, fallback tag text creation');
@@ -215,6 +232,7 @@ public function replaceDynamicTagSetting(string $tag, string $value): string
215232
} catch (\Throwable $e) {
216233
$this->getLogger()->warning("Unable to convert Elementor tag data to text: {$e->getMessage()}");
217234
}
235+
218236
return $tag;
219237
}
220238
}

inc/Smartling/ContentTypes/Elementor/Elements/GlobalWidget.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
namespace Smartling\ContentTypes\Elementor\Elements;
44

5+
use Smartling\ContentTypes\ContentTypeHelper;
56
use Smartling\Models\Content;
67
use Smartling\Models\RelatedContentInfo;
7-
use Smartling\Services\ContentRelationsDiscoveryService;
88

99
class GlobalWidget extends Unknown {
1010
public function getType(): string
@@ -17,7 +17,7 @@ public function getRelated(): RelatedContentInfo
1717
$result = parent::getRelated();
1818
$id = $this->getIntSettingByKey('templateID', $this->raw);
1919
if ($id !== null) {
20-
$result->addContent(new Content($id, ContentRelationsDiscoveryService::POST_BASED_PROCESSOR), $this->id, 'templateID');
20+
$result->addContent(new Content($id, ContentTypeHelper::CONTENT_TYPE_POST), $this->id, 'templateID');
2121
}
2222

2323
return $result;

inc/Smartling/ContentTypes/Elementor/Elements/IconList.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ public function getRelated(): RelatedContentInfo
2323
if ($id !== null) {
2424
$return->addContent(new Content($id, ContentTypeHelper::POST_TYPE_ATTACHMENT), $this->id, "settings/$key");
2525
}
26+
if (array_key_exists(self::SETTING_KEY_DYNAMIC, $listItem)) {
27+
foreach ($this->getRelatedFromDynamic(
28+
$listItem[self::SETTING_KEY_DYNAMIC],
29+
"settings/icon_list/$index/" . self::SETTING_KEY_DYNAMIC,
30+
) as $item) {
31+
$return->addContent($item->getContent(), $item->getContainerId(), $item->getPath());
32+
}
33+
}
2634
}
2735

2836
return $return;
@@ -47,6 +55,7 @@ public function setTargetContent(
4755
array $strings,
4856
SubmissionEntity $submission,
4957
): static {
58+
$this->raw = parent::setTargetContent($externalContentElementor, $info, $strings, $submission)->toArray();
5059
foreach ($strings[$this->id]['icon_list'] ?? [] as $id => $setting) {
5160
if (is_array($setting) && array_key_exists('text', $setting)) {
5261
foreach ($this->raw['settings']['icon_list'] ?? [] as $key => $icon) {
@@ -58,6 +67,11 @@ public function setTargetContent(
5867
}
5968
}
6069

70+
foreach ($info->getOwnRelatedContent($this->id) as $path => $content) {
71+
assert($content instanceof Content);
72+
$this->raw = $this->setRelations($content, $externalContentElementor, $path, $submission)->toArray();
73+
}
74+
6175
return new self($this->raw);
6276
}
6377
}

inc/Smartling/ContentTypes/Elementor/Elements/Unknown.php

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Smartling\Helpers\LoggerSafeTrait;
1111
use Smartling\Models\Content;
1212
use Smartling\Models\RelatedContentInfo;
13+
use Smartling\Models\RelatedContentItem;
1314

1415
class Unknown extends ElementAbstract {
1516
use LoggerSafeTrait;
@@ -34,35 +35,18 @@ public function getRelated(): RelatedContentInfo
3435
if (array_key_exists(ElementAbstract::SETTING_KEY_DYNAMIC, $this->settings)
3536
&& is_array($this->settings[ElementAbstract::SETTING_KEY_DYNAMIC])
3637
) {
37-
$dynamicTagsManager = $this->getDynamicTagsManager();
38-
if ($dynamicTagsManager !== null) {
39-
foreach ($this->settings[ElementAbstract::SETTING_KEY_DYNAMIC] as $property => $value) {
40-
try {
41-
$relatedId = $dynamicTagsManager->parse_tag_text($value, [], function ($id, $name, $settings) {
42-
if (is_array($settings) && array_key_exists(ElementAbstract::SETTING_KEY_POPUP, $settings)) {
43-
return (int)$settings[ElementAbstract::SETTING_KEY_POPUP];
44-
}
45-
46-
return null;
47-
});
48-
if ($relatedId !== null) {
49-
$return->addContent(
50-
new Content($relatedId, ContentTypeHelper::CONTENT_TYPE_UNKNOWN),
51-
$this->id,
52-
implode('/', ['settings', ElementAbstract::SETTING_KEY_DYNAMIC, $property]),
53-
);
54-
}
55-
} catch (\Throwable $e) {
56-
$this->getLogger()->notice("Failed to get related id for property=$property, tag=$value: {$e->getMessage()}");
57-
continue;
58-
}
59-
}
60-
}
38+
foreach ($this->getRelatedFromDynamic(
39+
$this->settings[ElementAbstract::SETTING_KEY_DYNAMIC],
40+
"settings/" . ElementAbstract::SETTING_KEY_DYNAMIC,
41+
) as $item) {
42+
$return->addContent($item->getContent(), $item->getContainerId(), $item->getPath());
43+
}
6144
}
6245

6346
return $return;
6447
}
6548

49+
6650
public function getTranslatableStrings(): array
6751
{
6852
$return = [];
@@ -87,4 +71,46 @@ public function getType(): string
8771
{
8872
return ElementFactory::UNKNOWN_ELEMENT;
8973
}
74+
75+
/**
76+
* @return RelatedContentItem[]
77+
*/
78+
public function getRelatedFromDynamic(array $dynamic, string $path): array
79+
{
80+
$return = [];
81+
$dynamicTagsManager = $this->getDynamicTagsManager();
82+
if ($dynamicTagsManager !== null) {
83+
foreach ($dynamic as $property => $value) {
84+
try {
85+
$related = $dynamicTagsManager->parse_tag_text($value, [], function ($id, $name, $settings): ?Content {
86+
if (is_array($settings)) {
87+
return $this->getKnownDynamicContent($name, $settings);
88+
}
89+
90+
return null;
91+
});
92+
if ($related !== null) {
93+
$return[] = new RelatedContentItem($related, $this->id, "$path/$property");
94+
}
95+
} catch (\Throwable $e) {
96+
$this->getLogger()->notice("Failed to get related id for property=$property, tag=$value: {$e->getMessage()}");
97+
continue;
98+
}
99+
}
100+
}
101+
102+
return $return;
103+
}
104+
105+
private function getKnownDynamicContent(string $name, array $settings): ?Content
106+
{
107+
if ($name === self::DYNAMIC_POPUP && array_key_exists(self::DYNAMIC_POPUP, $settings)) {
108+
return new Content((int)$settings[self::DYNAMIC_POPUP], ContentTypeHelper::CONTENT_TYPE_UNKNOWN);
109+
}
110+
if ($name === self::DYNAMIC_INTERNAL_URL && ($settings['type'] ?? '') === 'post' && array_key_exists('post_id', $settings)) {
111+
return new Content((int)$settings['post_id'], ContentTypeHelper::CONTENT_TYPE_POST);
112+
}
113+
114+
return null;
115+
}
90116
}

inc/Smartling/ContentTypes/ExternalContentElementor.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ public function __construct(
6565
parent::__construct($pluginHelper, $submissionManager, $wpProxy);
6666
}
6767

68+
public function getWpProxy(): WordpressFunctionProxyHelper
69+
{
70+
return $this->wpProxy;
71+
}
72+
6873
public function afterMetaWritten(SubmissionEntity $submission): void
6974
{
7075
if ($submission->getTargetId() === 0) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Smartling\Models;
4+
5+
class RelatedContentItem
6+
{
7+
function __construct(private Content $content, private string $containerId, private string $path)
8+
{
9+
}
10+
11+
public function getContainerId(): string
12+
{
13+
return $this->containerId;
14+
}
15+
16+
public function getContent(): Content
17+
{
18+
return $this->content;
19+
}
20+
21+
public function getPath(): string
22+
{
23+
return $this->path;
24+
}
25+
}

inc/Smartling/Services/ContentRelationsDiscoveryService.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,10 @@ public function normalizeReferences(array $references): array
596596
if (isset($references[ContentTypeHelper::POST_TYPE_ATTACHMENT])) {
597597
$result[ContentTypeHelper::POST_TYPE_ATTACHMENT] = $references[ContentTypeHelper::POST_TYPE_ATTACHMENT];
598598
}
599-
if (isset($references[ContentTypeHelper::CONTENT_TYPE_UNKNOWN])) {
600-
$references[self::POST_BASED_PROCESSOR] = array_merge($references[self::POST_BASED_PROCESSOR] ?? [], $references[ContentTypeHelper::CONTENT_TYPE_UNKNOWN]);
599+
foreach ([ContentTypeHelper::CONTENT_TYPE_POST, ContentTypeHelper::CONTENT_TYPE_UNKNOWN] as $contentType) {
600+
if (isset($references[$contentType])) {
601+
$references[self::POST_BASED_PROCESSOR] = array_merge($references[self::POST_BASED_PROCESSOR] ?? [], $references[$contentType]);
602+
}
601603
}
602604

603605
if (isset($references['MediaBasedProcessor'])) {

readme.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Tags: translation, localization, localisation, translate, multilingual, smartlin
44
Requires at least: 5.5
55
Tested up to: 6.6.2
66
Requires PHP: 8.0
7-
Stable tag: 4.3.6
7+
Stable tag: 4.3.7
88
License: GPLv2 or later
99

1010
Translate content in WordPress quickly and seamlessly with Smartling, the industry-leading Translation Management System.
@@ -62,6 +62,9 @@ Additional information on the Smartling Connector for WordPress can be found [he
6262
3. Track translation status within WordPress from the Submissions Board. View overall progress of submitted translation requests as well as resend updated content.
6363

6464
== Changelog ==
65+
= 4.3.7 =
66+
* Added support for Elementor internal url links
67+
6568
= 4.3.6 =
6669
* Improved replacement of attachment URLs in translated content by using WordPress built-in attachment_url_to_postid() function
6770
* Exclude and Copy fields by field name will now change to a stricter regex when changing the "Treat Exclude fields by field name and Copy fields by field name as regex" setting

0 commit comments

Comments
 (0)