diff --git a/packages/wp-plugin/essentials/inc/dashboard/index.php b/packages/wp-plugin/essentials/inc/dashboard/index.php index 05e4bac..84a57c2 100644 --- a/packages/wp-plugin/essentials/inc/dashboard/index.php +++ b/packages/wp-plugin/essentials/inc/dashboard/index.php @@ -2,6 +2,9 @@ namespace ionos_wordpress\essentials\dashboard; +use function ionos_wordpress\essentials\dashboard\blocks\next_best_actions\getNBAData; +use function ionos_wordpress\essentials\dashboard\blocks\next_best_actions\model\getNBAElements; + use const ionos_wordpress\essentials\PLUGIN_DIR; /* @@ -41,6 +44,8 @@ \register_block_type(PLUGIN_DIR . '/build/dashboard/blocks/deep-links'); \register_block_type(PLUGIN_DIR . '/build/dashboard/blocks/quick-links'); \register_block_type(PLUGIN_DIR . '/build/dashboard/blocks/vulnerability'); + \register_block_type(PLUGIN_DIR . '/build/dashboard/blocks/next-best-actions'); + }); // remove our blocks from all other post types @@ -165,3 +170,44 @@ EOF ); }); + +\add_action('load-' . ADMIN_PAGE_HOOK, function () { + +}); +add_action('wp_ajax_execute-nba-callback', function() { + $process = isset($_GET['process']) ? sanitize_text_field($_GET['process']) : ''; + $id = isset($_GET['id']) ? sanitize_text_field($_GET['id']) : ''; + + if (empty($process) || empty($id)) { + \wp_send_json_error(new \WP_Error('missing_parameters', 'Missing parameters')); + } + + require_once PLUGIN_DIR . '/build/dashboard/blocks/next-best-actions/data.php'; + $elements = getNBAData(); + if (! is_array($elements)) { + \wp_send_json_error(new \WP_Error('no_actions', 'No actions found')); + } + + foreach ($elements as $element) { + if ($element->__get('id') === $id ) { + + switch ($process) { + case 'click-nba-dismiss': + $element->__set('dismissed', true); + \wp_send_json_success(['addClass' => 'dismissed']); + break; + case 'click-nba-action': + $callback = $element->__get('completeOnClickCallback'); + $result = \call_user_func($callback) === true; + if ($result === true) { + $element->__set('completed', true); + } + \wp_send_json_success( [ 'redirect' => $element->__get('link') ] ); + break; + } + } + } + + \wp_send_json_error(new \WP_Error('action_not_found', 'Action not found')); +}); + diff --git a/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/block.json b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/block.json new file mode 100644 index 0000000..549ebcf --- /dev/null +++ b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/block.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "ionos-dashboard-page/next-best-actions", + "version": "0.1.0", + "title": "NBA", + "category": "widgets", + "icon": "index-card", + "description": "Next Best Actions", + "example": {}, + "supports": { + "html": false + }, + "textdomain": "ionos-essentials", + "editorScript": "file:./index.js", + "viewScript": [ + "file:./view.js", + "wp-util" + ], + "render": "file:./render.php" +} diff --git a/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/data.php b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/data.php new file mode 100644 index 0000000..2798d5b --- /dev/null +++ b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/data.php @@ -0,0 +1,62 @@ + false, + callback: fn() => false, + ), + new Model( + id: 'checkThemesPage', + title: 'Check Themes Page', + description: 'Check the themes page for updates and security issues.', + link: admin_url('themes.php'), + image: 'https://raw.githubusercontent.com/codeformm/mitaka-kichijoji-wapuu/main/mitaka-kichijoji-wapuu.png', + completeOnClickCallback: fn() => false, + callback: fn() => true, + ), + new Model( + id: 'checkUpdatesPage', + title: 'Check Updates Page', + description: 'Check the updates page for updates and security issues.', + link: admin_url('update-core.php'), + image: 'https://raw.githubusercontent.com/codeformm/mitaka-kichijoji-wapuu/main/mitaka-kichijoji-wapuu.png', + completeOnClickCallback: fn() => true, + callback: fn() => true, + ), + new Model( + id: 'checkSettingsPage', + title: 'Check Settings Page', + description: 'Check the settings page for updates and security issues.', + link: admin_url('options-general.php'), + image: 'https://raw.githubusercontent.com/codeformm/mitaka-kichijoji-wapuu/main/mitaka-kichijoji-wapuu.png', + completeOnClickCallback: fn() => true, + callback: fn() => true, + ), + new Model( + id: 'checkUsersPage', + title: 'Check Users Page', + description: 'Check the users page for updates and security issues.', + link: admin_url('users.php'), + image: 'https://raw.githubusercontent.com/codeformm/mitaka-kichijoji-wapuu/main/mitaka-kichijoji-wapuu.png', + completeOnClickCallback: fn() => true, + callback: fn() => true, + ) + ); +} + diff --git a/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/index.js b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/index.js new file mode 100644 index 0000000..0f8df3c --- /dev/null +++ b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={n:t=>{var o=t&&t.__esModule?()=>t.default:()=>t;return e.d(o,{a:o}),o},d:(t,o)=>{for(var r in o)e.o(o,r)&&!e.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:o[r]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.blocks,o=(window.wp.i18n,window.wp.blockEditor),r=window.wp.serverSideRender;var n=e.n(r);const i=window.ReactJSXRuntime,s=JSON.parse('{"UU":"ionos-dashboard-page/next-best-actions"}');(0,t.registerBlockType)(s.UU,{edit:function(e){return(0,i.jsx)("div",{...(0,o.useBlockProps)(),children:(0,i.jsx)(n(),{block:e.name,attributes:e.attributes})})},save:()=>null})})(); \ No newline at end of file diff --git a/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/model.php b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/model.php new file mode 100644 index 0000000..adba215 --- /dev/null +++ b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/model.php @@ -0,0 +1,73 @@ + static::_setOption($this->id, 'completed', $value), + 'dismissed' => static::_setOption($this->id, 'dismissed', $value), + default => throw new \InvalidArgumentException("Invalid property: $optionName"), + }; + } + + function __get(string $optionName): mixed { + return match ($optionName) { + 'id' => $this->id, + 'title' => $this->title, + 'description' => $this->description, + 'link' => $this->link, + 'completeOnClickCallback' => $this->completeOnClickCallback, + 'image' => $this->image, + 'callback' => $this->callback, + 'completed' => static::_getOption($this->id, 'completed'), + 'dismissed' => static::_getOption($this->id, 'dismissed'), + default => throw new \InvalidArgumentException("Invalid property: $optionName"), + }; + } + + protected static function _getWPOption() { + if(!isset(static::$_wp_option)) { + $option = \get_option(static::WP_OPTION_NAME); + static::$_wp_option = is_array( $option ) ? $option : []; + } + return static::$_wp_option; + } + + + protected static function _setOption(string $id, string $optionName, string $value) { + $wp_option = static::_getWPOption(); + $wp_option[$id][$optionName] = $value; + \update_option(static::WP_OPTION_NAME, $wp_option); + } + + protected static function _getOption(string $id, string $optionName): mixed { + $wp_option = static::_getWPOption(); + return $wp_option[$id][$optionName] ?? false; + } +} + diff --git a/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/render.php b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/render.php new file mode 100644 index 0000000..cbd1319 --- /dev/null +++ b/packages/wp-plugin/essentials/src/dashboard/blocks/next-best-actions/render.php @@ -0,0 +1,46 @@ +%s', \esc_html__('Next best actions ⚡', 'ionos-essentials')); +echo '