PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Core/AcymPlugin.php +328 -94 11.0.3 → 11.1.0 View file →
@@ -8,8 +8,13 @@
8 8 use Joomla\CMS\HTML\HTMLHelper;
9 9
10 10 class AcymPlugin extends AcymObject
11 11 {
12 + // The row placeholders are replaced by the JS when a row is added to the form
13 + const CONDITION_FIELD_NAME = 'acym_condition[conditions][__numor__][__numand__]';
14 + const FILTER_FIELD_NAME = 'acym_action[filters][__numor__][__numand__]';
15 + const MAILBOX_ACTION_FIELD_NAME = 'acym_action[__num__]';
16 +
12 17 public string $cms = 'all';
13 18 public string $name = '';
14 19 public bool $installed = true;
15 20
@@ -57,8 +62,14 @@
57 62 private bool $active;
58 63 public array $settings = [];
59 64 private array $savedSettings = [];
60 65
66 + public array $automationTriggers = [];
67 + public array $automationActions = [];
68 + public array $automationConditions = [];
69 + public array $automationFilters = [];
70 + public array $mailboxActions = [];
71 +
61 72 public function __construct()
62 73 {
63 74 parent::__construct();
64 75
@@ -335,9 +346,13 @@
335 346 $options[] = [
336 347 'title' => 'ACYM_DOCUMENTATION',
337 348 'type' => 'custom',
338 349 'name' => 'documentation',
339 - 'output' => '<a target="_blank" href="'.ACYM_DOCUMENTATION.'main-pages/campaigns/automatic-campaigns#dont-send-twice-the-same-content"><i class="acymicon-book"></i></a>',
350 + 'output' => static function (): void {
351 + echo '<a target="_blank" href="'.esc_url(
352 + ACYM_DOCUMENTATION.'main-pages/campaigns/automatic-campaigns#dont-send-twice-the-same-content'
353 + ).'"><i class="acymicon-book"></i></a>';
354 + },
340 355 'js' => '',
341 356 'section' => 'ACYM_AUTO_CAMPAIGNS_OPTIONS',
342 357 ];
343 358
@@ -789,16 +804,231 @@
789 804 // Resize/remove pictures if needed
790 805 return $this->pluginHelper->managePicts($insertionOptions, $htmlResult);
791 806 }
792 807
808 + /**
809 + * Keep this method untyped until v12
810 + */
811 + public function onAcymDeclareTriggers(&$triggers, &$defaultValues)
812 + {
813 + if (empty($this->automationTriggers) && method_exists($this, 'initAutomationTriggers')) {
814 + $this->initAutomationTriggers();
815 + }
816 +
817 + foreach ($this->automationTriggers as $group => $groupTriggers) {
818 + foreach ($groupTriggers as $key => $name) {
819 + $triggers[$group][$key] = $this->declareTrigger($key, $name, $defaultValues, $group);
820 + }
821 + }
822 + }
823 +
824 + /**
825 + * Keep this method untyped until v12
826 + */
827 + public function onAcymDeclareTriggersScenario(&$triggers, &$defaultValues)
828 + {
829 + $this->onAcymDeclareTriggers($triggers, $defaultValues);
830 + }
831 +
832 + /**
833 + * Declares name and options callbacks for automation/scenario triggers
834 + */
835 + protected function declareTrigger(string $key, string $name, $defaultValues = [], string $group = 'user'): object
836 + {
837 + $trigger = new \stdClass();
838 + $trigger->name = $name;
839 +
840 + if (!is_array($defaultValues)) {
841 + $defaultValues = [];
842 + }
843 +
844 + $method = 'displayTriggerOptions_'.$key;
845 + if (!method_exists($this, $method)) {
846 + $method = 'displayTriggerOptions';
847 + }
848 +
849 + if (method_exists($this, $method)) {
850 + $automationFieldName = '[triggers]['.$group.']['.$key.']';
851 + $trigger->displayOptions = function (?string $fieldName = null) use ($method, $defaultValues, $key, $automationFieldName): void {
852 + $this->$method($fieldName === null ? $automationFieldName : $fieldName, $defaultValues, $key);
853 + };
854 + }
855 +
856 + return $trigger;
857 + }
858 +
859 + public function onAcymDeclareActions(array &$actions): void
860 + {
861 + if (empty($this->automationActions) && method_exists($this, 'initAutomationActions')) {
862 + $this->initAutomationActions();
863 + }
864 +
865 + foreach ($this->automationActions as $key => $name) {
866 + $actions[$key] = $this->declareAction($key, $name);
867 + }
868 + }
869 +
870 + public function onAcymDeclareActionsScenario(array &$actions): void
871 + {
872 + $this->onAcymDeclareActions($actions);
873 + }
874 +
875 + /**
876 + * Declares name and options callbacks for an automation/scenario action
877 + */
878 + protected function declareAction(string $key, string $name): object
879 + {
880 + $action = new \stdClass();
881 + $action->name = $name;
882 +
883 + $method = 'displayActionOptions_'.$key;
884 + if (!method_exists($this, $method)) {
885 + $method = 'displayActionOptions';
886 + }
887 +
888 + if (method_exists($this, $method)) {
889 + $action->displayOptions = function () use ($method, $key): void {
890 + $this->$method($key);
891 + };
892 + }
893 +
894 + return $action;
895 + }
896 +
897 + public function onAcymDeclareConditions(array &$conditions): void
898 + {
899 + if (empty($this->automationConditions) && method_exists($this, 'initAutomationConditions')) {
900 + $this->initAutomationConditions();
901 + }
902 +
903 + foreach ($this->automationConditions as $group => $groupConditions) {
904 + foreach ($groupConditions as $key => $name) {
905 + $conditions[$group][$key] = $this->declareCondition($key, $name);
906 + }
907 + }
908 + }
909 +
910 + public function onAcymDeclareConditionsScenario(array &$conditions): void
911 + {
912 + $this->onAcymDeclareConditions($conditions);
913 + }
914 +
915 + public function onAcymDeclareFilters(array &$filters): void
916 + {
917 + if (empty($this->automationFilters) && method_exists($this, 'initAutomationFilters')) {
918 + $this->initAutomationFilters();
919 + }
920 +
921 + foreach ($this->automationFilters as $key => $name) {
922 + $filters[$key] = $this->declareFilter($key, $name);
923 + }
924 + }
925 +
926 + /**
927 + * Returns a field name without its acym_condition / acym_action prefix.
928 + */
929 + protected function getFieldNameWithoutPrefix(string $fieldName): string
930 + {
931 + return str_replace(['acym_condition', 'acym_action'], '', $fieldName);
932 + }
933 +
934 + protected function declareCondition(string $key, string $name): object
935 + {
936 + $condition = new \stdClass();
937 + $condition->name = $name;
938 +
939 + $renderer = $this->getOptionsRenderer('displayConditionOptions', $key, self::CONDITION_FIELD_NAME.'['.$key.']');
940 + if ($renderer !== null) {
941 + $condition->displayOptions = $renderer;
942 + }
943 +
944 + return $condition;
945 + }
946 +
947 + public function onAcymMailboxActionDefine(&$actions)
948 + {
949 + if (empty($this->mailboxActions) && method_exists($this, 'initMailboxActions')) {
950 + $this->initMailboxActions();
951 + }
952 +
953 + foreach ($this->mailboxActions as $key => $name) {
954 + $actions[$key] = $this->declareMailboxAction($key, $name);
955 + }
956 + }
957 +
958 + /**
959 + * A follow-up condition row: a translated sentence holding the selectors the add-on built.
960 + */
961 + protected function followupConditionRow(string $translationKey, string ...$fields): callable
962 + {
963 + return static function () use ($translationKey, $fields): void {
964 + echo acym_translationSprintf($translationKey, ...$fields);
965 + };
966 + }
967 +
968 + protected function declareMailboxAction(string $key, string $name): object
969 + {
970 + $action = new \stdClass();
971 + $action->name = $name;
972 +
973 + $renderer = $this->getOptionsRenderer('displayMailboxActionOptions', $key, self::MAILBOX_ACTION_FIELD_NAME.'['.$key.']');
974 + if ($renderer !== null) {
975 + $action->displayOptions = $renderer;
976 + }
977 +
978 + return $action;
979 + }
980 +
981 + protected function declareFilter(string $key, string $name): object
982 + {
983 + $filter = new \stdClass();
984 + $filter->name = $name;
985 +
986 + $renderer = $this->getOptionsRenderer('displayFilterOptions', $key, self::FILTER_FIELD_NAME.'['.$key.']');
987 + if ($renderer !== null) {
988 + $filter->displayOptions = $renderer;
989 + }
990 +
991 + return $filter;
992 + }
993 +
994 + /**
995 + * Builds the callback that displays the option fields of a declaration.
996 + */
997 + private function getOptionsRenderer(string $methodPrefix, string $key, string $defaultFieldName): ?callable
998 + {
999 + $method = $methodPrefix.'_'.$key;
1000 + if (!method_exists($this, $method)) {
1001 + $method = $methodPrefix;
1002 + }
1003 +
1004 + if (!method_exists($this, $method)) {
1005 + return null;
1006 + }
1007 +
1008 + return function (?string $fieldName = null) use ($method, $key, $defaultFieldName): void {
1009 + $this->$method($fieldName === null ? $defaultFieldName : $fieldName, $key);
1010 + };
1011 + }
1012 +
1013 + /**
1014 + * Most add-ons offer the same choices as conditions and as filters, the only difference being the name the fields are nested under
1015 + */
793 1016 protected function filtersFromConditions(array &$filters): void
794 1017 {
795 - $newFilters = [];
1018 + $conditions = [];
1019 + $this->onAcymDeclareConditions($conditions);
796 1020
797 - $this->onAcymDeclareConditions($newFilters);
798 - foreach ($newFilters as $oneType) {
799 - foreach ($oneType as $oneFilterName => $oneFilter) {
800 - if (!empty($oneFilter->option)) $oneFilter->option = str_replace(['acym_condition', '[conditions]'], ['acym_action', '[filters]'], $oneFilter->option);
1021 + foreach ($conditions as $oneGroup) {
1022 + foreach ($oneGroup as $oneFilterName => $oneFilter) {
1023 + $renderer = $this->getOptionsRenderer('displayConditionOptions', $oneFilterName, self::FILTER_FIELD_NAME.'['.$oneFilterName.']');
1024 + if ($renderer !== null) {
1025 + $oneFilter->displayOptions = $renderer;
1026 + } elseif (!empty($oneFilter->option)) {
1027 + // TODO: remove this on version 12, only there for retro-compat of add-ons/plugins not updated along with AcyMailing
1028 + $oneFilter->option = str_replace(['acym_condition', '[conditions]'], ['acym_action', '[filters]'], $oneFilter->option);
1029 + }
1030 +
801 1031 $filters[$oneFilterName] = $oneFilter;
802 1032 }
803 1033 }
804 1034 }
@@ -1119,14 +1349,9 @@
1119 1349 }
1120 1350
1121 1351 public function displayCustomViewEditor(): void
1122 1352 {
1123 - $plugin = new \stdClass();
1124 - $plugin->folder_name = $this->name;
1125 - $plugin->settings = $this->settings;
1126 - $this->generateSettings($plugin);
1127 -
1128 - if (empty($plugin->settings['custom_view'])) {
1353 + if (empty($this->settings['custom_view']) || !acym_isAdmin()) {
1129 1354 return;
1130 1355 }
1131 1356
1132 1357 echo '<p class="acym__wysid__right__toolbar__p acym__wysid__right__toolbar__p__open acym__title">';
@@ -1132,9 +1357,9 @@
1132 1357 echo '<p class="acym__wysid__right__toolbar__p acym__wysid__right__toolbar__p__open acym__title">';
1133 1358 echo esc_html(acym_translation('ACYM_ADDON_SETTINGS'));
1134 1359 echo '<i class="acymicon-keyboard-arrow-up"></i></p>';
1135 1360 echo '<div class="acym__wysid__right__toolbar__design--show acym__wysid__right__toolbar__design acym__wysid__context__modal__container">';
1136 - echo $plugin->settings['custom_view'];
1361 + $this->displayCustomView($this->settings['custom_view']);
1137 1362 echo '</div>';
1138 1363 }
1139 1364
1140 1365 public function generateSettings(object $plugin): bool
@@ -1176,9 +1401,9 @@
1176 1401
1177 1402 if ($field['type'] === 'checkbox') {
1178 1403 $classLabel = 'shrink';
1179 1404 $text .= '<label for="'.esc_attr($id).'" class="cell '.esc_attr($classLabel).'">'.esc_html($field['label']).'</label>';
1180 - $text .= '<input id="'.esc_attr($id).'" class="cell shrink" type="checkbox" name="'.esc_attr($name).'" '.acym_checked(
1405 + $text .= '<input id="'.esc_attr($id).'" class="cell shrink" type="checkbox" name="'.esc_attr($name).'" '.checked(
1181 1406 !empty($field['value']),
1182 1407 true,
1183 1408 false
1184 1409 ).'>';
@@ -1233,83 +1458,13 @@
1233 1458 $name,
1234 1459 $field['value'],
1235 1460 'cell shrink'
1236 1461 );
1237 - } elseif ($field['type'] === 'custom_view' && acym_isAdmin()) {
1238 - $idCustomView = 'acym__plugins__installed__custom-view__'.$this->name;
1239 - $ctrl = acym_getVar('string', 'ctrl', '');
1240 - $classTooltip = $ctrl === 'dynamics' ? '' : 'wysid_tooltip';
1241 - $text .= '<label class="cell">';
1242 - $text .= acym_translation('ACYM_CUSTOM_VIEW');
1462 + } elseif ($field['type'] === 'custom_view') {
1243 1463 ob_start();
1244 - acym_info(
1245 - [
1246 - 'textShownInTooltip' => 'ACYM_CUSTOM_VIEW_DESC',
1247 - 'classText' => $classTooltip,
1248 - ]
1249 - );
1464 + $this->displayCustomView($field);
1250 1465 $text .= ob_get_clean();
1251 - $text .= '</label>';
1252 -
1253 - if (empty($field['tags'])) {
1254 - $field['tags'] = [];
1255 - }
1256 -
1257 - ob_start();
1258 - acym_info(
1259 - [
1260 - 'textShownInTooltip' => acym_translation('ACYM_DYNAMIC_CONTENT_DESC'),
1261 - ]
1262 - );
1263 - $tooltip = ob_get_clean();
1264 -
1265 - $modalContent = '<div id="'.esc_attr($idCustomView).'" class="cell grid-x acym__plugins__installed__custom-view" acym-data-tags="'.esc_attr(
1266 - json_encode($field['tags'])
1267 - ).'">
1268 - <h2 class="cell text-center acym__title__primary__color">'.acym_translationSprintf('ACYM_CUSTOM_VIEW_FOR_X', $this->pluginDescription->name).'</h2>
1269 - <div class="cell grid-x acym__plugins__installed__custom-view__edit-container">
1270 - <div class="acym__plugins__installed__custom-view__editor-loader grid-x cell align-center acym_vcenter" v-if="loading">
1271 - <div class="cell shrink acym_loader_logo">
1272 - '.acym_fileGetContent(ACYM_IMAGES.'logos/logo_grey.svg').'
1273 - </div>
1274 - </div>
1275 - <vue-prism-editor :emitEvents="true" class="cell acym__plugins__installed__custom-view__code cell auto" v-model="code" :language="language" lineNumbers="true"></vue-prism-editor>
1276 - <div class="cell grid-x medium-3 margin-left-1 acym__plugins__installed__custom-view__tags">
1277 - <h3 class="acym__title acym__title__secondary cell text-center">'.esc_html(acym_translation('ACYM_DYNAMIC_CONTENT')).$tooltip.'</h3>
1278 - <div class="cell acym__plugins__installed__custom-view__tag" v-for="(trad, tag) in tags" :key="tag" @click.prevent="insertTag(tag)">{{ trad }}</div>
1279 - </div>
1280 - </div>
1281 - <div class="cell grid-x acym__plugins__installed__custom-view__actions acym_vcenter margin-top-1 padding-bottom-1">
1282 - <div class="cell auto grid-x">
1283 - <button type="button" class="cell shrink button-secondary button" @click="resetView">'.esc_html(acym_translation('ACYM_RESET_VIEW')).'</button>
1284 - <div class="cell shrink margin-right-2 acym_vcenter margin-left-1">
1285 - <i v-if="deleting" class="acymicon-spin acymicon-circle-o-notch" style="margin-bottom: 0; line-height: 26px;"></i>
1286 - <span v-if="deleted">{{ messageDeleted }}</span>
1287 - </div>
1288 - </div>
1289 - <div class="cell auto align-right grid-x">
1290 - <div class="cell shrink margin-right-2 acym_vcenter">
1291 - <i v-if="saving" class="acymicon-spin acymicon-circle-o-notch" style="margin-bottom: 0; line-height: 26px;"></i>
1292 - <span v-if="saved">{{ messageSaved }}</span>
1293 - </div>
1294 - <button @click="save()" class="cell shrink button" type="button">'.esc_html(acym_translation('ACYM_SAVE_NEW_CUSTOM_VIEW_VERSION')).'</button>
1295 - </div>
1296 - </div>
1297 - </div>';
1298 - ob_start();
1299 - acym_modal(
1300 - acym_translation('ACYM_EDIT_CUSTOM_VIEW'),
1301 - $modalContent,
1302 - null,
1303 - [
1304 - 'acym-data-plugins-id' => $idCustomView,
1305 - 'acym-data-plugin-class' => get_class($this),
1306 - 'acym-data-plugin-folder' => $this->name,
1307 - ],
1308 - ['class' => 'cell button']
1309 - );
1310 - $text .= ob_get_clean();
1311 - } elseif ($field['type'] == 'multikeyvalue') {
1466 + } elseif ($field['type'] === 'multikeyvalue') {
1312 1467 $text .= '<label class="cell shrink">'.$field['label'].'</label>';
1313 1468
1314 1469 $text .= '<div class="multikeyvalue_container grid-x">';
1315 1470
@@ -1315,22 +1470,22 @@
1315 1470
1316 1471 if (!empty($field['value'])) {
1317 1472 $headers = json_decode($field['value'], true);
1318 1473 foreach ($headers as $headerKey => $headerValue) {
1319 - $text .= '<input type="text" class="cell" placeholder="'.acym_translation('ACYM_DKIM_KEY', true).'" value="'.esc_attr($headerKey).'"/>';
1320 - $text .= '<input type="text" class="cell" placeholder="'.acym_translation('ACYM_VALUE', true).'" value="'.esc_attr($headerValue).'" />';
1474 + $text .= '<input type="text" class="cell" placeholder="'.esc_attr(acym_translation('ACYM_DKIM_KEY')).'" value="'.esc_attr($headerKey).'"/>';
1475 + $text .= '<input type="text" class="cell" placeholder="'.esc_attr(acym_translation('ACYM_VALUE')).'" value="'.esc_attr($headerValue).'" />';
1321 1476 $text .= '<div class="multikeyvalue_container_separator cell small-6"></div>';
1322 1477 }
1323 1478 }
1324 1479
1325 - $text .= '<input type="text" class="cell" placeholder="'.acym_translation('ACYM_DKIM_KEY', true).'" value=""/>';
1326 - $text .= '<input type="text" class="cell" placeholder="'.acym_translation('ACYM_VALUE', true).'" value="" />';
1480 + $text .= '<input type="text" class="cell" placeholder="'.esc_attr(acym_translation('ACYM_DKIM_KEY')).'" value=""/>';
1481 + $text .= '<input type="text" class="cell" placeholder="'.esc_attr(acym_translation('ACYM_VALUE')).'" value="" />';
1327 1482
1328 - $text .= '<button class="button multikeyvalue_container_new">'.acym_translation('ACYM_ADD_NEW').'</button>';
1483 + $text .= '<button class="button multikeyvalue_container_new">'.esc_html(acym_translation('ACYM_ADD_NEW')).'</button>';
1329 1484
1330 - $text .= '<input type="hidden" name="'.$name.'" value="" />';
1485 + $text .= '<input type="hidden" name="'.esc_attr($name).'" value="" />';
1331 1486 $text .= '</div>';
1332 - } elseif ($field['type'] == 'custom') {
1487 + } elseif ($field['type'] === 'custom') {
1333 1488 $text .= $field['content'];
1334 1489 }
1335 1490 $plugin->settings[$key] = $text;
1336 1491 }
@@ -1335,8 +1490,87 @@
1335 1490 $plugin->settings[$key] = $text;
1336 1491 }
1337 1492
1338 1493 return true;
1494 + }
1495 +
1496 + protected function displayCustomView(array $field): void
1497 + {
1498 + if (!acym_isAdmin()) {
1499 + return;
1500 + }
1501 +
1502 + $idCustomView = 'acym__plugins__installed__custom-view__'.$this->name;
1503 + $ctrl = acym_getVar('string', 'ctrl', '');
1504 + $classTooltip = $ctrl === 'dynamics' ? '' : 'wysid_tooltip';
1505 +
1506 + echo '<label class="cell">';
1507 + echo esc_html(acym_translation('ACYM_CUSTOM_VIEW'));
1508 + acym_info(
1509 + [
1510 + 'textShownInTooltip' => 'ACYM_CUSTOM_VIEW_DESC',
1511 + 'classText' => $classTooltip,
1512 + ]
1513 + );
1514 + echo '</label>';
1515 +
1516 + if (empty($field['tags'])) {
1517 + $field['tags'] = [];
1518 + }
1519 +
1520 + ob_start();
1521 + acym_info(
1522 + [
1523 + 'textShownInTooltip' => acym_translation('ACYM_DYNAMIC_CONTENT_DESC'),
1524 + ]
1525 + );
1526 + $tooltip = ob_get_clean();
1527 +
1528 + $modalContent = '<div id="'.esc_attr($idCustomView).'" class="cell grid-x acym__plugins__installed__custom-view" acym-data-tags="'.esc_attr(
1529 + json_encode($field['tags'])
1530 + ).'">
1531 + <h2 class="cell text-center acym__title__primary__color">'.esc_html(acym_translationSprintf('ACYM_CUSTOM_VIEW_FOR_X', $this->pluginDescription->name)).'</h2>
1532 + <div class="cell grid-x acym__plugins__installed__custom-view__edit-container">
1533 + <div class="acym__plugins__installed__custom-view__editor-loader grid-x cell align-center acym_vcenter" v-if="loading">
1534 + <div class="cell shrink acym_loader_logo">
1535 + '.acym_fileGetContent(ACYM_IMAGES.'logos/logo_grey.svg').'
1536 + </div>
1537 + </div>
1538 + <vue-prism-editor :emitEvents="true" class="cell acym__plugins__installed__custom-view__code cell auto" v-model="code" :language="language" lineNumbers="true"></vue-prism-editor>
1539 + <div class="cell grid-x medium-3 margin-left-1 acym__plugins__installed__custom-view__tags">
1540 + <h3 class="acym__title acym__title__secondary cell text-center">'.esc_html(acym_translation('ACYM_DYNAMIC_CONTENT')).$tooltip.'</h3>
1541 + <div class="cell acym__plugins__installed__custom-view__tag" v-for="(trad, tag) in tags" :key="tag" @click.prevent="insertTag(tag)">{{ trad }}</div>
1542 + </div>
1543 + </div>
1544 + <div class="cell grid-x acym__plugins__installed__custom-view__actions acym_vcenter margin-top-1 padding-bottom-1">
1545 + <div class="cell auto grid-x">
1546 + <button type="button" class="cell shrink button-secondary button" @click="resetView">'.esc_html(acym_translation('ACYM_RESET_VIEW')).'</button>
1547 + <div class="cell shrink margin-right-2 acym_vcenter margin-left-1">
1548 + <i v-if="deleting" class="acymicon-spin acymicon-circle-o-notch" style="margin-bottom: 0; line-height: 26px;"></i>
1549 + <span v-if="deleted">{{ messageDeleted }}</span>
1550 + </div>
1551 + </div>
1552 + <div class="cell auto align-right grid-x">
1553 + <div class="cell shrink margin-right-2 acym_vcenter">
1554 + <i v-if="saving" class="acymicon-spin acymicon-circle-o-notch" style="margin-bottom: 0; line-height: 26px;"></i>
1555 + <span v-if="saved">{{ messageSaved }}</span>
1556 + </div>
1557 + <button @click="save()" class="cell shrink button" type="button">'.esc_html(acym_translation('ACYM_SAVE_NEW_CUSTOM_VIEW_VERSION')).'</button>
1558 + </div>
1559 + </div>
1560 + </div>';
1561 +
1562 + acym_modal(
1563 + acym_translation('ACYM_EDIT_CUSTOM_VIEW'),
1564 + $modalContent,
1565 + null,
1566 + [
1567 + 'acym-data-plugins-id' => $idCustomView,
1568 + 'acym-data-plugin-class' => get_class($this),
1569 + 'acym-data-plugin-folder' => $this->name,
1570 + ],
1571 + ['class' => 'cell button']
1572 + );
1339 1573 }
1340 1574
1341 1575 /**
1342 1576 * Called using ajax