From e3adb724d9e05382b2454a9010784ba16ff992a0 Mon Sep 17 00:00:00 2001 From: vsolovei-smartling Date: Wed, 4 Mar 2026 18:23:02 +0100 Subject: [PATCH] add elementor nested accordion support (WP-994) --- composer.json | 2 +- .../Elementor/Elements/NestedAccordion.php | 70 ++++++++ readme.txt | 5 +- smartling-connector.php | 2 +- .../Elementor/NestedAccordionTest.php | 157 ++++++++++++++++++ 5 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 inc/Smartling/ContentTypes/Elementor/Elements/NestedAccordion.php create mode 100644 tests/Smartling/ContentTypes/Elementor/NestedAccordionTest.php diff --git a/composer.json b/composer.json index 0f19e724..0d6aa707 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "smartling/wordpress-connector", "license": "GPL-2.0-or-later", - "version": "5.3.1", + "version": "5.3.2", "description": "", "type": "wordpress-plugin", "repositories": [ diff --git a/inc/Smartling/ContentTypes/Elementor/Elements/NestedAccordion.php b/inc/Smartling/ContentTypes/Elementor/Elements/NestedAccordion.php new file mode 100644 index 00000000..0c573000 --- /dev/null +++ b/inc/Smartling/ContentTypes/Elementor/Elements/NestedAccordion.php @@ -0,0 +1,70 @@ +getIntSettingByKey($key, $this->settings); + if ($id !== null) { + $return->addContent(new Content($id, ContentTypeHelper::POST_TYPE_ATTACHMENT), $this->id, "settings/$key"); + } + } + + return $return; + } + + public function getTranslatableStrings(): array + { + $return = []; + foreach ($this->settings['items'] ?? [] as $index => $item) { + $key = 'items/' . ($item['_id'] ?? $index); + if (array_key_exists('item_title', $item)) { + $return[$key]['item_title'] = $item['item_title']; + } + } + + return [$this->getId() => $return]; + } + + public function setTargetContent( + ExternalContentElementor $externalContentElementor, + RelatedContentInfo $info, + array $strings, + SubmissionEntity $submission, + ): static { + $this->raw = parent::setTargetContent($externalContentElementor, $info, $strings, $submission)->toArray(); + $this->settings = $this->raw['settings'] ?? []; + + foreach ($strings[$this->id] ?? [] as $array) { + if (is_array($array)) { + foreach ($array as $id => $values) { + foreach ($this->settings['items'] ?? [] as $index => $item) { + if (($item['_id'] ?? '') === $id) { + foreach ($values as $property => $value) { + $this->settings['items'][$index][$property] = $value; + } + } + } + } + } + } + $this->raw['settings'] = $this->settings; + + return new static($this->raw); + } +} diff --git a/readme.txt b/readme.txt index 148422fb..c95506eb 100755 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: translation, localization, multilingual, internationalization, smartling Requires at least: 5.5 Tested up to: 6.9 Requires PHP: 8.0 -Stable tag: 5.3.1 +Stable tag: 5.3.2 License: GPLv2 or later 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 3. Track translation status within WordPress from the Submissions Board. View overall progress of submitted translation requests as well as resend updated content. == Changelog == += 5.3.2 = +* Added support for Elementor nested accordion widget + = 5.3.1 = * Fixed invalid credentials preventing settings page from loading diff --git a/smartling-connector.php b/smartling-connector.php index d789fba7..a3b304d0 100755 --- a/smartling-connector.php +++ b/smartling-connector.php @@ -11,7 +11,7 @@ * Plugin Name: Smartling Connector * Plugin URI: https://www.smartling.com/products/automate/integrations/wordpress/ * Description: Integrate your WordPress site with Smartling to upload your content and download translations. - * Version: 5.3.1 + * Version: 5.3.2 * Author: Smartling * Author URI: https://www.smartling.com * License: GPL-2.0+ diff --git a/tests/Smartling/ContentTypes/Elementor/NestedAccordionTest.php b/tests/Smartling/ContentTypes/Elementor/NestedAccordionTest.php new file mode 100644 index 00000000..8710697b --- /dev/null +++ b/tests/Smartling/ContentTypes/Elementor/NestedAccordionTest.php @@ -0,0 +1,157 @@ + 'cf8c5a0', + 'elType' => 'widget', + 'widgetType' => 'nested-accordion', + 'settings' => $settings, + 'elements' => [], + ]); + } + + public function testGetRelatedReturnsBothIconIds(): void + { + $widget = $this->makeWidget([ + 'accordion_item_title_icon' => ['value' => ['url' => 'https://example.com/plus.svg', 'id' => 329], 'library' => 'svg'], + 'accordion_item_title_icon_active' => ['value' => ['url' => 'https://example.com/minus.svg', 'id' => 330], 'library' => 'svg'], + ]); + + $related = $widget->getRelated(); + $list = $related->getRelatedContentList(); + + $this->assertArrayHasKey(ContentTypeHelper::POST_TYPE_ATTACHMENT, $list); + $this->assertContains(329, $list[ContentTypeHelper::POST_TYPE_ATTACHMENT]); + $this->assertContains(330, $list[ContentTypeHelper::POST_TYPE_ATTACHMENT]); + } + + public function testGetRelatedSkipsNonSvgIcons(): void + { + $widget = $this->makeWidget([ + 'accordion_item_title_icon' => ['value' => 'fas fa-plus', 'library' => 'fa-solid'], + ]); + + $related = $widget->getRelated(); + $list = $related->getRelatedContentList(); + + $this->assertArrayNotHasKey(ContentTypeHelper::POST_TYPE_ATTACHMENT, $list); + } + + public function testSetRelationsUpdatesIconId(): void + { + $sourceId = 329; + $targetId = 500; + + $proxy = $this->createMock(WordpressFunctionProxyHelper::class); + $externalContentElementor = $this->createMock(ExternalContentElementor::class); + $externalContentElementor->method('getTargetId')->willReturn($targetId); + $externalContentElementor->method('getWpProxy')->willReturn($proxy); + + $result = $this->makeWidget([ + 'accordion_item_title_icon' => ['value' => ['url' => 'https://example.com/plus.svg', 'id' => $sourceId], 'library' => 'svg'], + ])->setRelations( + new Content($sourceId, ContentTypeHelper::POST_TYPE_ATTACHMENT), + $externalContentElementor, + 'settings/accordion_item_title_icon/value/id', + $this->createMock(SubmissionEntity::class), + )->toArray(); + + $this->assertEquals($targetId, $result['settings']['accordion_item_title_icon']['value']['id']); + } + + public function testGetTranslatableStringsReturnsItemTitles(): void + { + $widget = $this->makeWidget([ + 'items' => [ + ['_id' => 'aaa111', 'item_title' => 'First Item'], + ['_id' => 'bbb222', 'item_title' => 'Second Item'], + ], + ]); + + $strings = $widget->getTranslatableStrings(); + + $this->assertArrayHasKey('cf8c5a0', $strings); + $this->assertEquals('First Item', $strings['cf8c5a0']['items/aaa111']['item_title']); + $this->assertEquals('Second Item', $strings['cf8c5a0']['items/bbb222']['item_title']); + } + + public function testSetTargetContentAppliesTranslatedItemTitles(): void + { + $proxy = $this->createMock(WordpressFunctionProxyHelper::class); + $externalContentElementor = $this->createMock(ExternalContentElementor::class); + $externalContentElementor->method('getWpProxy')->willReturn($proxy); + + $widget = $this->makeWidget([ + 'items' => [ + ['_id' => 'aaa111', 'item_title' => 'First Item'], + ['_id' => 'bbb222', 'item_title' => 'Second Item'], + ], + ]); + + $strings = [ + 'cf8c5a0' => [ + 'items' => [ + 'aaa111' => ['item_title' => 'Translated First'], + 'bbb222' => ['item_title' => 'Translated Second'], + ], + ], + ]; + + $result = $widget->setTargetContent( + $externalContentElementor, + new RelatedContentInfo([]), + $strings, + $this->createMock(SubmissionEntity::class), + )->toArray(); + + $this->assertEquals('Translated First', $result['settings']['items'][0]['item_title']); + $this->assertEquals('Translated Second', $result['settings']['items'][1]['item_title']); + } + + public function testSetTargetContentAppliesIconIdTranslation(): void + { + $sourceId = 329; + $targetId = 500; + + $proxy = $this->createMock(WordpressFunctionProxyHelper::class); + $externalContentElementor = $this->createMock(ExternalContentElementor::class); + $externalContentElementor->method('getTargetId') + ->with(0, $sourceId, 0, ContentTypeHelper::POST_TYPE_ATTACHMENT) + ->willReturn($targetId); + $externalContentElementor->method('getWpProxy')->willReturn($proxy); + + $submission = $this->createMock(SubmissionEntity::class); + $submission->method('getSourceBlogId')->willReturn(0); + $submission->method('getTargetBlogId')->willReturn(0); + + $widget = $this->makeWidget([ + 'accordion_item_title_icon' => ['value' => ['url' => 'https://example.com/plus.svg', 'id' => $sourceId], 'library' => 'svg'], + 'items' => [['_id' => 'aaa111', 'item_title' => 'Title']], + ]); + + $info = $widget->getRelated(); + + $result = $widget->setTargetContent( + $externalContentElementor, + $info, + [], + $submission, + )->toArray(); + + $this->assertEquals($targetId, $result['settings']['accordion_item_title_icon']['value']['id']); + } +}