diff --git a/.eslintrc.js b/.eslintrc.js index 0e995642..0d431a08 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,13 +3,21 @@ module.exports = { 'plugin:react/recommended', 'plugin:no-jquery/deprecated', 'plugin:@wordpress/eslint-plugin/recommended-with-formatting', + 'plugin:import/recommended', + 'plugin:jsx-a11y/strict', ], plugins: [ 'babel', 'react', 'no-jquery', - ], - parser: '@babel/eslint-parser', + '@typescript-eslint', + '@elementor', + 'import', + 'react-hooks', + 'prettier', + ], + ignorePatterns: [ '!**/*' ], + parser: '@babel/eslint-parser', globals: { wp: true, window: true, @@ -142,5 +150,7 @@ module.exports = { // 'react/jsx-tag-spacing': 'error', // 'react/no-children-prop': 'off', // 'react/prop-types': 'off', + '@elementor/eui-default-imports-only': 'error', + 'react/no-unescaped-entities': 'warn', }, }; diff --git a/.github/checkstyle-problem-matcher.json b/.github/checkstyle-problem-matcher.json new file mode 100644 index 00000000..5c6ce669 --- /dev/null +++ b/.github/checkstyle-problem-matcher.json @@ -0,0 +1,23 @@ +{ + "problemMatcher": [ + { + "owner": "phpcs", + "severity": "error", + "pattern": [ + { + "regexp": "^$", + "file": 1 + }, + { + "regexp": "+)$", + "line": 1, + "column": 2, + "severity": 3, + "message": 4, + "code": 5, + "loop": true + } + ] + } + ] +} diff --git a/.github/workflows/js-ci.yml b/.github/workflows/js-ci.yml new file mode 100644 index 00000000..2826c6a1 --- /dev/null +++ b/.github/workflows/js-ci.yml @@ -0,0 +1,53 @@ +name: NPM CI + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + +env: + token: ${{ secrets.CLOUD_DEVOPS_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.CLOUD_DEVOPS_TOKEN }} + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v2 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + cache-dependency-path: package-lock.json + + - uses: actions/setup-node@v4 + with: + registry-url: 'https://npm.pkg.github.com' + scope: '@elementor' + + - name: Install Dependencies + run: npm ci + env: + NODE_AUTH_TOKEN: ${{ secrets.CLOUD_DEVOPS_TOKEN }} + + - name: Build + run: npm run build + + - name: Lint + run: npm run lint:js + +# - name: Test +# run: npm run test diff --git a/.github/workflows/php-coding-standards.yml b/.github/workflows/php-coding-standards.yml new file mode 100644 index 00000000..863702ec --- /dev/null +++ b/.github/workflows/php-coding-standards.yml @@ -0,0 +1,54 @@ +name: PHP Lint + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: read + +jobs: + PHP-Code-Standards: + name: Lint PHP files + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, '[skip PHPCS]') || !contains(github.event.head_commit.message, '[skip CI]')" + steps: + - name: Check out source code + uses: actions/checkout@v4 + + - name: Set up PHP + uses: shivammathur/setup-php@a36e1e52ff4a1c9e9c9be31551ee4712a6cb6bd0 # 2.27.1 + with: + php-version: '7.4' + coverage: none + tools: composer, cs2pr, phpcs + env: + fail-fast: 'true' + + - name: Log debug information + run: | + export PATH=$HOME/.composer/vendor/bin:$PATH + php --version + phpcs -i + composer --version + + - name: Oauth Composer authentication + run: composer config -g github-oauth.github.com ${{ secrets.DEVOPS_TOKEN }} + + - name: Install dependencies + uses: ramsey/composer-install@83af392bf5f031813d25e6fe4cd626cdba9a2df6 # 2.2.0 + + - name: Add error matcher + run: echo "::add-matcher::$(pwd)/.github/checkstyle-problem-matcher.json" + + - name: Run style check + run: | + export PATH=$HOME/.composer/vendor/bin:$PATH + composer run lint -- --report=checkstyle diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..b467ce5c --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +//npm.pkg.github.com/:_authToken=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 +@elementor:registry=https://npm.pkg.github.com/elementor diff --git a/assets/dev/js/editor/hooks/ui/controls-hook.js b/assets/dev/js/editor/hooks/ui/controls-hook.js index 67d2e43b..75d916b3 100644 --- a/assets/dev/js/editor/hooks/ui/controls-hook.js +++ b/assets/dev/js/editor/hooks/ui/controls-hook.js @@ -186,7 +186,6 @@ export default class ControlsHook extends $e.modules.hookUI.After { * @param {string} classPrefix * @param {Object} inputOptions * @param {string} inputValue - * */ toggleLayoutClass( element, classPrefix, inputOptions, inputValue ) { // Loop through the possible classes and remove the one that's not in use diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..442b4dd1 --- /dev/null +++ b/composer.json @@ -0,0 +1,17 @@ +{ + "name": "elementor/hello-plus", + "require": { + "squizlabs/php_codesniffer": "^3.10.2", + "dealerdirect/phpcodesniffer-composer-installer": "^v1.0.0", + "wp-coding-standards/wpcs": "^3.1.0" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, + "scripts": { + "lint": "vendor/bin/phpcs --standard=./phpcs.xml --ignore=node_modules,vendor,build .", + "lint:fix": "vendor/bin/phpcbf --ignore=node_modules,vendor,build ." + } +} diff --git a/includes/module-base.php b/includes/module-base.php index 162c276f..3649a349 100644 --- a/includes/module-base.php +++ b/includes/module-base.php @@ -46,7 +46,7 @@ abstract class Module_Base { * * @var Module_Base[] */ - protected static array $_instances = []; + protected static array $instances = []; /** * Get module name. @@ -79,11 +79,11 @@ abstract protected function get_component_ids(): array; public static function instance(): Module_Base { $class_name = static::class_name(); - if ( empty( static::$_instances[ $class_name ] ) ) { - static::$_instances[ $class_name ] = new static(); // @codeCoverageIgnore + if ( empty( static::$instances[ $class_name ] ) ) { + static::$instances[ $class_name ] = new static(); // @codeCoverageIgnore } - return static::$_instances[ $class_name ]; + return static::$instances[ $class_name ]; } /** @@ -125,7 +125,7 @@ public function get_reflection(): \ReflectionClass { $this->reflection = new \ReflectionClass( $this ); } catch ( \ReflectionException $e ) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { - error_log( $e->getMessage() ); + error_log( $e->getMessage() ); //phpcs:ignore } } } @@ -196,7 +196,7 @@ public static function namespace_name(): string { * @param ?array $components_ids => component's class name. * @return void */ - protected function register_components( array $components_ids = null ):void { + protected function register_components( array $components_ids = null ): void { if ( empty( $components_ids ) ) { $components_ids = $this->get_component_ids(); } @@ -216,7 +216,7 @@ protected function register_components( array $components_ids = null ):void { * @param \Elementor\Widgets_Manager $widgets_manager * @return void */ - public function register_widgets( \Elementor\Widgets_Manager $widgets_manager ):void { + public function register_widgets( \Elementor\Widgets_Manager $widgets_manager ): void { $widget_ids = $this->get_widget_ids(); $namespace = static::namespace_name(); diff --git a/index.php b/index.php index 5e467a39..f677905c 100644 --- a/index.php +++ b/index.php @@ -28,10 +28,8 @@ if ( ! $is_elementor_theme_exist || ! elementor_theme_do_location( 'archive' ) ) { get_template_part( 'template-parts/search' ); } -} else { - if ( ! $is_elementor_theme_exist || ! elementor_theme_do_location( 'single' ) ) { - get_template_part( 'template-parts/404' ); - } +} elseif ( ! $is_elementor_theme_exist || ! elementor_theme_do_location( 'single' ) ) { + get_template_part( 'template-parts/404' ); } get_footer(); diff --git a/modules/admin/assets/js/components/link/admin-link.js b/modules/admin/assets/js/components/link/admin-link.js deleted file mode 100644 index bff5c40e..00000000 --- a/modules/admin/assets/js/components/link/admin-link.js +++ /dev/null @@ -1,7 +0,0 @@ -import { Link } from '@elementor/ui/Link'; - -export const AdminLink = ( { href, children } ) => { - return ( - { children } - ); -}; diff --git a/modules/admin/assets/js/components/link/promotion-link.js b/modules/admin/assets/js/components/link/promotion-link.js index ce84e73e..ce7b3e14 100644 --- a/modules/admin/assets/js/components/link/promotion-link.js +++ b/modules/admin/assets/js/components/link/promotion-link.js @@ -1,6 +1,6 @@ -import { Stack } from '@elementor/ui/Stack'; -import { Typography } from '@elementor/ui/Typography'; -import { Button } from '@elementor/ui/Button'; +import Stack from '@elementor/ui/Stack'; +import Typography from '@elementor/ui/Typography'; +import Button from '@elementor/ui/Button'; export const PromotionLink = ( { image, alt, title, message, button, link } ) => { return ( diff --git a/modules/admin/assets/js/components/link/top-bar-link.js b/modules/admin/assets/js/components/link/top-bar-link.js new file mode 100644 index 00000000..7d3206d8 --- /dev/null +++ b/modules/admin/assets/js/components/link/top-bar-link.js @@ -0,0 +1,23 @@ +import Typography from '@elementor/ui/Typography'; +import IconButton from '@elementor/ui/IconButton'; + +export const TopBarLink = ( { linkData } ) => { + const { label, hrefStr, children, color, aria } = linkData; + return ( + + { children } + + { label } + + + ); +}; diff --git a/modules/admin/assets/js/components/panels/dashboard/home/components/home-hero.js b/modules/admin/assets/js/components/panels/dashboard/home/components/home-hero.js deleted file mode 100644 index 612e1f01..00000000 --- a/modules/admin/assets/js/components/panels/dashboard/home/components/home-hero.js +++ /dev/null @@ -1,21 +0,0 @@ -import { __ } from '@wordpress/i18n'; -import { Box } from '@elementor/ui/Box'; -import { Stack } from '@elementor/ui/Stack'; -import { Typography } from '@elementor/ui/Typography'; - -const HomeHero = () => { - return ( - - - { __( 'Welcome to Hello+', 'hello-plus' ) } - - - - { __( 'Here you’ll find links to some site settings that will help you setup and get running as soon as possible.', 'hello-plus' ) } - - - - ); -}; - -export default HomeHero; diff --git a/modules/admin/assets/js/components/panels/dashboard/home/components/home-links-grid.js b/modules/admin/assets/js/components/panels/dashboard/home/components/home-links-grid.js deleted file mode 100644 index 216f1bc8..00000000 --- a/modules/admin/assets/js/components/panels/dashboard/home/components/home-links-grid.js +++ /dev/null @@ -1,10 +0,0 @@ -import { Grid } from '@elementor/ui/Grid'; -import { LinksColumn } from './links-column'; - -export const HomeLinksGrid = ( { linksColumns } ) => { - return ( - - { linksColumns.map( ( column, index ) => ) } - - ); -}; diff --git a/modules/admin/assets/js/components/panels/dashboard/home/components/links-column.js b/modules/admin/assets/js/components/panels/dashboard/home/components/links-column.js deleted file mode 100644 index 0637887f..00000000 --- a/modules/admin/assets/js/components/panels/dashboard/home/components/links-column.js +++ /dev/null @@ -1,19 +0,0 @@ -import { Grid } from '@elementor/ui/Grid'; -import { Stack } from '@elementor/ui/Stack'; -import { Typography } from '@elementor/ui/Typography'; -import { AdminLink } from '../../../../link/admin-link'; - -export const LinksColumn = ( { linksColumn } ) => { - const { title, links } = linksColumn; - - return ( - - - { title } - { links.map( ( link, i ) => { - return { link.title }; - } ) } - - - ); -}; diff --git a/modules/admin/assets/js/components/panels/dashboard/home/dashboard-home-panel.js b/modules/admin/assets/js/components/panels/dashboard/home/dashboard-home-panel.js deleted file mode 100644 index 0055d79d..00000000 --- a/modules/admin/assets/js/components/panels/dashboard/home/dashboard-home-panel.js +++ /dev/null @@ -1,82 +0,0 @@ -import { Stack } from '@elementor/ui/Stack'; -import HomeHero from './components/home-hero'; -import { HomeLinksGrid } from './components/home-links-grid'; -import { __ } from '@wordpress/i18n'; -import { GridWithActionLinks } from '../../../../layouts/grids/grid-with-action-links'; - -const linksColumns = [ - { - title: __( 'My Website Parts', 'hello-plus' ), - links: [ - { - title: __( 'Edit Header', 'hello-plus' ), - url: '#', - }, - { - title: __( 'Edit Footer', 'hello-plus' ), - url: '#', - }, - ], - }, - { - title: __( 'My Website Pages', 'hello-plus' ), - links: [ - { - title: __( 'Home Page', 'hello-plus' ), - url: '#', - }, - { - title: __( 'About', 'hello-plus' ), - url: '#', - }, - { - title: __( 'Services', 'hello-plus' ), - url: '#', - }, - { - title: __( 'Work', 'hello-plus' ), - url: '#', - }, - { - title: __( 'Contact', 'hello-plus' ), - url: '#', - }, - ], - }, - { - title: __( 'Quick Links', 'hello-plus' ), - links: [ - { - title: __( 'Site Nme', 'hello-plus' ), - url: '#', - }, - { - title: __( 'Site Logo', 'hello-plus' ), - url: '#', - }, - { - title: __( 'Edit menu', 'hello-plus' ), - url: '#', - }, - { - title: __( 'Website Colors', 'hello-plus' ), - url: '#', - }, - { - title: __( 'Website fonts', 'hello-plus' ), - url: '#', - }, - ], - }, -]; - -export const DashboardHomePanel = () => { - return ( - - - - - - - ); -}; diff --git a/modules/admin/assets/js/components/panels/dashboard/settings/components/setting-card.js b/modules/admin/assets/js/components/panels/dashboard/settings/components/setting-card.js deleted file mode 100644 index 4460723c..00000000 --- a/modules/admin/assets/js/components/panels/dashboard/settings/components/setting-card.js +++ /dev/null @@ -1,33 +0,0 @@ -import { Box } from '@elementor/ui/Box'; -import { Card } from '@elementor/ui/Card'; -import { CardContent } from '@elementor/ui/CardContent'; -import { FormControlLabel } from '@elementor/ui/FormControlLabel'; -import { Stack } from '@elementor/ui/Stack'; - -export const SettingCard = ( { label, description, control, code } ) => { - return ( - - - - - - - - - - { description } - - { code } - - - - - - ); -}; diff --git a/modules/admin/assets/js/components/panels/dashboard/settings/components/settings-body.js b/modules/admin/assets/js/components/panels/dashboard/settings/components/settings-body.js deleted file mode 100644 index 401c8f90..00000000 --- a/modules/admin/assets/js/components/panels/dashboard/settings/components/settings-body.js +++ /dev/null @@ -1,99 +0,0 @@ -import { Alert } from '@elementor/ui/Alert'; -import { Switch } from '@elementor/ui/Switch'; -import { Typography } from '@elementor/ui/Typography'; -import { Stack } from '@elementor/ui/Stack'; -import { Paper } from '@elementor/ui/Paper'; -import { __ } from '@wordpress/i18n'; -import { SettingCard } from './setting-card'; - -export const SettingsBody = ( { settings, settingsData, updateSettings } ) => { - const protocol = window.location.protocol || 'https:'; - const hostname = window.location.hostname || 'example.com'; - const prefix = protocol + '//' + hostname; - - return ( - - - - { __( 'Be cautious, disabling some of the following options may break your website.', 'hello-plus' ) } - - - <meta name="description" content="..." /> - } - label={ __( 'Disable description meta tag', 'hello-plus' ) } - control={ { - updateSettings( settings.DESCRIPTION_META_TAG, event.target.checked ); - } } - /> } - - /> - - <a class="skip-link screen-reader-text" href="#content"> Skip to - content </a> - } - label={ __( 'Disable skip link', 'hello-plus' ) } - control={ updateSettings( settings.SKIP_LINK, event.target.checked ) } - /> } - /> - - <header id="site-header" class="site-header"> ... </header> - - - <footer id="site-footer" class="site-footer"> ... </footer> - } - control={ updateSettings( settings.HEADER_FOOTER, event.target.checked ) } - /> } - /> - - <div class="page-header"> <h1 class="entry-title"> Post - title </h1> </div> - } - control={ updateSettings( settings.PAGE_TITLE, event.target.checked ) } - /> } - /> - - <link - rel="stylesheet" href="{ prefix }/wp-content/themes/hello-plus/style.min.css" /> - } - control={ updateSettings( settings.HELLO_PLUS_STYLE, event.target.checked ) } - /> } - /> - - <link - rel="stylesheet" href="{ prefix }/wp-content/themes/hello-plus/theme.min.css" /> - } - control={ updateSettings( settings.HELLO_PLUS_THEME, event.target.checked ) } - /> } - /> - - - ); -}; diff --git a/modules/admin/assets/js/components/panels/dashboard/settings/dashboard-settings-panel.js b/modules/admin/assets/js/components/panels/dashboard/settings/dashboard-settings-panel.js deleted file mode 100644 index 91bca4ce..00000000 --- a/modules/admin/assets/js/components/panels/dashboard/settings/dashboard-settings-panel.js +++ /dev/null @@ -1,111 +0,0 @@ -import { useEffect, useState } from 'react'; -import { __ } from '@wordpress/i18n'; -import api from '@wordpress/api'; -import { SettingsBody } from './components/settings-body'; -import { Alert } from '@elementor/ui/Alert'; -import { Box } from '@elementor/ui/Box'; -import { Button } from '@elementor/ui/Button'; -import { CircularProgress } from '@elementor/ui/CircularProgress'; -import { Stack } from '@elementor/ui/Stack'; -import { GridWithActionLinks } from '../../../../layouts/grids/grid-with-action-links'; - -export const DashboardSettingsPanel = () => { - const [ settingsData, setSettingsData ] = useState( {} ); - const [ message, setMessage ] = useState( '' ); - const [ severity, setSeverity ] = useState( 'success' ); - - const settingsPrefix = 'hello_plus_settings'; - - const SETTINGS = { - DESCRIPTION_META_TAG: '_description_meta_tag', - SKIP_LINK: '_skip_link', - HEADER_FOOTER: '_header_footer', - PAGE_TITLE: '_page_title', - HELLO_PLUS_STYLE: '_hello_plus_style', - HELLO_PLUS_THEME: '_hello_plus_theme', - }; - - /** - * Update settings data. - * - * @param {string} settingsName - * @param {string} settingsValue - */ - const updateSettings = ( settingsName, settingsValue ) => { - setSettingsData( { - ...settingsData, - [ settingsName ]: settingsValue, - } ); - }; - - /** - * Save settings to server. - */ - const saveSettings = async () => { - const data = {}; - - Object.values( SETTINGS ).forEach( ( value ) => data[ `${ settingsPrefix }${ value }` ] = settingsData[ value ] ? 'true' : '' ); - - try { - const settings = new api.models.Settings( data ); - - await settings.save(); - setMessage( __( 'Settings Saved', 'hello-plus' ) ); - setSeverity( 'success' ); - } catch ( e ) { - setMessage( __( 'Failed to save settings', 'hello-plus' ) ); - setSeverity( 'error' ); - } - }; - - useEffect( () => { - const fetchSettings = async () => { - try { - await api.loadPromise; - const settings = new api.models.Settings(); - const response = await settings.fetch(); - - const data = {}; - Object.values( SETTINGS ).forEach( ( value ) => data[ value ] = response[ `${ settingsPrefix }${ value }` ] ); - - setSettingsData( data ); - setHasLoaded( true ); - } catch ( error ) { - // eslint-disable-next-line no-console - console.error( error ); - } - }; - - if ( hasLoaded ) { - return; - } - - fetchSettings(); - }, [ settingsData ] ); - - const [ hasLoaded, setHasLoaded ] = useState( false ); - - if ( ! hasLoaded ) { - return ( - - - - ); - } - - return ( - - - { message && setMessage( '' ) }>{ message } } - - - - - ); -}; diff --git a/modules/admin/assets/js/components/papers/quick-links.js b/modules/admin/assets/js/components/papers/quick-links.js new file mode 100644 index 00000000..e012df24 --- /dev/null +++ b/modules/admin/assets/js/components/papers/quick-links.js @@ -0,0 +1,9 @@ +import Paper from '@elementor/ui/Paper'; + +export const QuickLinks = () => { + return ( + + Quick Links + + ); +}; diff --git a/modules/admin/assets/js/components/papers/site-parts.js b/modules/admin/assets/js/components/papers/site-parts.js new file mode 100644 index 00000000..841affea --- /dev/null +++ b/modules/admin/assets/js/components/papers/site-parts.js @@ -0,0 +1,9 @@ +import Paper from '@elementor/ui/Paper'; + +export const SiteParts = () => { + return ( + + Site Parts + + ); +}; diff --git a/modules/admin/assets/js/components/papers/welcome.js b/modules/admin/assets/js/components/papers/welcome.js new file mode 100644 index 00000000..13bdf87a --- /dev/null +++ b/modules/admin/assets/js/components/papers/welcome.js @@ -0,0 +1,9 @@ +import Paper from '@elementor/ui/Paper'; + +export const Welcome = () => { + return ( + +

Welcome to Hello Plus

+
+ ); +}; diff --git a/modules/admin/assets/js/components/panels/promotions-links-panel.js b/modules/admin/assets/js/components/promotions/list.js similarity index 74% rename from modules/admin/assets/js/components/panels/promotions-links-panel.js rename to modules/admin/assets/js/components/promotions/list.js index 5e5fe2cd..dd3c5e80 100644 --- a/modules/admin/assets/js/components/panels/promotions-links-panel.js +++ b/modules/admin/assets/js/components/promotions/list.js @@ -1,13 +1,13 @@ import { PromotionLink } from '../link/promotion-link'; import { useDashboardContext } from '../../hooks/use-dashboard-context'; -export const PromotionsLinksPanel = () => { +export const PromotionsList = () => { const { promotionsLinks } = useDashboardContext(); return (
{ promotionsLinks.map( ( link, i ) => { - return ; - } ) } + return ; + } ) }
); }; diff --git a/modules/admin/assets/js/components/top-bar/top-bar-links.js b/modules/admin/assets/js/components/top-bar/top-bar-links.js new file mode 100644 index 00000000..63143783 --- /dev/null +++ b/modules/admin/assets/js/components/top-bar/top-bar-links.js @@ -0,0 +1,13 @@ +import Stack from '@elementor/ui/Stack'; +import { TopBarLink } from '../link/top-bar-link'; + +export const TopBarLinks = ( { linksData } ) => { + linksData.forEach( ( link ) => link.color = 'secondary' ); + return ( + + { + linksData.map( ( linkData, index ) => ) + } + + ); +}; diff --git a/modules/admin/assets/js/components/top-bar/top-bar.js b/modules/admin/assets/js/components/top-bar/top-bar.js new file mode 100644 index 00000000..01e5346b --- /dev/null +++ b/modules/admin/assets/js/components/top-bar/top-bar.js @@ -0,0 +1,41 @@ +import AppBar from '@elementor/ui/AppBar'; +import Toolbar from '@elementor/ui/Toolbar'; +import { __ } from '@wordpress/i18n'; +import HomeIcon from '@elementor/icons/HomeIcon'; +import HelpIcon from '@elementor/icons/HelpIcon'; +import { TopBarLinks } from './top-bar-links'; +import { TopBarLink } from '../link/top-bar-link'; + +const home = { + label: __( 'Hello+', 'hello-plus' ), + hrefStr: '#', + children: , + color: 'primary', + aria: 'menu', +}; + +const adminTopBarLinks = [ + { + label: 'Todo1', + hrefStr: '#', + children: , + aria: 'todo-1', + }, + { + label: 'Todo2', + hrefStr: '#', + children: , + aria: 'todo-2', + }, +]; + +export const TopBar = () => { + return ( + + + + + + + ); +}; diff --git a/modules/admin/assets/js/hello-plus-admin.js b/modules/admin/assets/js/hello-plus-admin.js index 6914ba38..2eb6393f 100644 --- a/modules/admin/assets/js/hello-plus-admin.js +++ b/modules/admin/assets/js/hello-plus-admin.js @@ -1,17 +1,18 @@ import { createRoot } from 'react-dom/client'; -import { DashboardPage } from './pages/dashboard-page.js'; +import { AdminPage } from './pages/admin-page.js'; import { DashboardProvider } from './providers/dashboard-provider'; const App = () => { return ( - + ); }; document.addEventListener( 'DOMContentLoaded', () => { - const container = document.getElementById( 'hello-plus-dashboard' ); + const container = document.getElementById( 'ehp-admin-home' ); + if ( container ) { const root = createRoot( container ); root.render( ); diff --git a/modules/admin/assets/js/layouts/grids/grid-with-action-links.js b/modules/admin/assets/js/layouts/grids/grid-with-action-links.js index e8c7fde8..5f52e9ae 100644 --- a/modules/admin/assets/js/layouts/grids/grid-with-action-links.js +++ b/modules/admin/assets/js/layouts/grids/grid-with-action-links.js @@ -1,14 +1,14 @@ -import { Grid } from '@elementor/ui/Grid'; -import { PromotionsLinksPanel } from '../../components/panels/promotions-links-panel'; +import Grid from '@elementor/ui/Grid'; +import { PromotionsList } from '../../components/promotions/list'; export const GridWithActionLinks = ( { children } ) => { return ( - + { children } - - + + diff --git a/modules/admin/assets/js/pages/admin-page.js b/modules/admin/assets/js/pages/admin-page.js new file mode 100644 index 00000000..46e1c3f5 --- /dev/null +++ b/modules/admin/assets/js/pages/admin-page.js @@ -0,0 +1,29 @@ +import Box from '@elementor/ui/Box'; + +import { ThemeProvider } from '@elementor/ui/styles'; + +import { TopBar } from '../components/top-bar/top-bar'; +import { GridWithActionLinks } from '../layouts/grids/grid-with-action-links'; +import Stack from '@elementor/ui/Stack'; +import { QuickLinks } from '../components/papers/quick-links'; +import { Welcome } from '../components/papers/welcome'; +import { SiteParts } from '../components/papers/site-parts'; + +export const AdminPage = () => { + return ( + + + + + + + + + + + + + + + ); +}; diff --git a/modules/admin/assets/js/pages/dashboard-page.js b/modules/admin/assets/js/pages/dashboard-page.js deleted file mode 100644 index fea04f34..00000000 --- a/modules/admin/assets/js/pages/dashboard-page.js +++ /dev/null @@ -1,61 +0,0 @@ -import { __ } from '@wordpress/i18n'; -// TODO: minimize to only necessary imports -import { Tabs } from '@elementor/ui/Tabs'; -import { useTabs } from '@elementor/ui/useTabs'; -import { TabPanel } from '@elementor/ui/TabPanel'; -import { Tab } from '@elementor/ui/Tab'; -import { Box } from '@elementor/ui/Box'; -import { Container } from '@elementor/ui/Container'; -import { ThemeProvider } from '@elementor/ui/styles'; - -import { DashboardSettingsPanel } from '../components/panels/dashboard/settings/dashboard-settings-panel'; -import { DashboardHomePanel } from '../components/panels/dashboard/home/dashboard-home-panel'; - -export const DashboardPage = ( props ) => { - const tabs = [ - { - name: 'HOME', - component: , - title: __( 'Home', 'hello-plus' ), - }, - { - name: 'SETTINGS', - component: , - title: __( 'Settings', 'hello-plus' ), - }, - ]; - - const params = { - tab: tabs[ 0 ].name, - }; - - const { getTabsProps, getTabProps, getTabPanelProps } = useTabs( params.tab ); - - return ( - - - - -

{ __( 'Hello+ Dashboard', 'hello-plus' ) }

-
-
-
- - - - - { - tabs.map( ( tab ) => ) - } - - - { - tabs.map( ( tab ) => { tab.component } ) - } - - - - -
- ); -}; diff --git a/modules/admin/classes/menu/pages/kits-library.php b/modules/admin/classes/menu/pages/kits-library.php new file mode 100644 index 00000000..637c8a2d --- /dev/null +++ b/modules/admin/classes/menu/pages/kits-library.php @@ -0,0 +1,27 @@ +Kits Library Page Content'; + } +} diff --git a/modules/admin/classes/menu/pages/settings.php b/modules/admin/classes/menu/pages/settings.php new file mode 100644 index 00000000..8fd22bac --- /dev/null +++ b/modules/admin/classes/menu/pages/settings.php @@ -0,0 +1,27 @@ +Settings Page Content'; + } +} diff --git a/modules/admin/classes/menu/pages/setup-wizard.php b/modules/admin/classes/menu/pages/setup-wizard.php new file mode 100644 index 00000000..24a40f46 --- /dev/null +++ b/modules/admin/classes/menu/pages/setup-wizard.php @@ -0,0 +1,27 @@ +Setup Wizard Page Content'; + } +} diff --git a/modules/admin/components/rest-get-promotions.php b/modules/admin/classes/rest/get-promotions.php similarity index 95% rename from modules/admin/components/rest-get-promotions.php rename to modules/admin/classes/rest/get-promotions.php index 4d950e6f..17d89e22 100644 --- a/modules/admin/components/rest-get-promotions.php +++ b/modules/admin/classes/rest/get-promotions.php @@ -1,10 +1,14 @@ $action_links_data ] ); } - } diff --git a/modules/admin/components/admin-menu-controller.php b/modules/admin/components/admin-menu-controller.php new file mode 100644 index 00000000..f9b55b06 --- /dev/null +++ b/modules/admin/components/admin-menu-controller.php @@ -0,0 +1,92 @@ +register_settings_page(); + + $setup_wizard = new Setup_Wizard(); + $setup_wizard->register_setup_wizard_page(); + + $kits_library = new Kits_Library(); + $kits_library->register_kits_library_page(); + } + + public function enqueue_scripts() { + $screen = get_current_screen(); + + if ( 'toplevel_page_' . self::MENU_PAGE_SLUG !== $screen->id ) { + return; + } + + $handle = 'hello-plus-admin'; + $asset_path = HELLO_PLUS_SCRIPTS_PATH . 'hello-plus-admin.asset.php'; + $asset_url = HELLO_PLUS_SCRIPTS_URL; + + if ( ! file_exists( $asset_path ) ) { + throw new \Error( 'You need to run `npm run build` for the "hello-plus" first.' ); + } + + $script_asset = require $asset_path; + + wp_enqueue_script( + $handle, + HELLO_PLUS_SCRIPTS_URL . "$handle.js", + $script_asset['dependencies'], + $script_asset['version'], + true + ); + + wp_set_script_translations( $handle, 'hello-plus' ); + + wp_enqueue_style( + $handle, + HELLO_PLUS_STYLE_URL . "$handle.css", + [ 'wp-components' ], + $script_asset['version'] + ); + } + + public function render(): void { + echo '
'; + } + + public function __construct() { + add_action( 'admin_menu', array( $this, 'admin_menu' ) ); + add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); + } +} diff --git a/modules/admin/components/plugin-notice.php b/modules/admin/components/plugin-notice.php index 4515d245..1d1c2496 100644 --- a/modules/admin/components/plugin-notice.php +++ b/modules/admin/components/plugin-notice.php @@ -98,16 +98,17 @@ public function ajax_set_admin_notice_viewed() { public function enqueue() { wp_enqueue_style( 'hello-plus-notice-style', - HELLO_PLUS_STYLE_URL . 'hello-plus-notice' . Theme::get_min_suffix() . '.css', + HELLO_PLUS_STYLE_URL . 'hello-plus-notice.css', [], HELLO_PLUS_ELEMENTOR_VERSION ); wp_enqueue_script( 'hello-plus-notice', - HELLO_PLUS_SCRIPTS_URL . 'hello-plus-notice' . Theme::get_min_suffix() . '.js', + HELLO_PLUS_SCRIPTS_URL . 'hello-plus-notice.js', [], - HELLO_PLUS_ELEMENTOR_VERSION + HELLO_PLUS_ELEMENTOR_VERSION, + true ); wp_localize_script( diff --git a/modules/admin/components/rest-controller.php b/modules/admin/components/rest-controller.php new file mode 100644 index 00000000..27f99fff --- /dev/null +++ b/modules/admin/components/rest-controller.php @@ -0,0 +1,14 @@ +endpoints['promotions'] = new Get_Promotions(); + } +} diff --git a/modules/admin/module.php b/modules/admin/module.php index 5affdfa0..8e7714ab 100644 --- a/modules/admin/module.php +++ b/modules/admin/module.php @@ -28,7 +28,8 @@ public static function get_name(): string { protected function get_component_ids(): array { return [ 'Plugin_Notice', - 'Rest_Get_Promotions', + 'Rest_Controller', + 'Admin_Menu_Controller', ]; } } diff --git a/modules/content/assets/js/hello-plus-content.js b/modules/content/assets/js/hello-plus-content.js index a801395d..65a340ab 100644 --- a/modules/content/assets/js/hello-plus-content.js +++ b/modules/content/assets/js/hello-plus-content.js @@ -1,4 +1,4 @@ -window.addEventListener( 'elementor/frontend/init', ( e ) => { +window.addEventListener( 'elementor/frontend/init', () => { elementorFrontend.hooks.addAction( 'frontend/element_ready/zigzag.default', ( $scope ) => { const scope0 = $scope[ 0 ]; const motionEffectElements = scope0.querySelectorAll( '.motion-effect-fade-in' ); diff --git a/modules/content/assets/scss/hello-plus-content.scss b/modules/content/assets/scss/hello-plus-content.scss index aec2347a..13603445 100644 --- a/modules/content/assets/scss/hello-plus-content.scss +++ b/modules/content/assets/scss/hello-plus-content.scss @@ -1,136 +1,237 @@ -/* CSS for the ZigZag widget */ +.e-zigzag { + $transition: all .3s; + $corners-shape-default: 8px; + $corners-shape-sharp: 0; + $corners-shape-rounded: 12px; + $corners-shape-round: 32px; + + $breakpoint-tablet-max: 767px; + $breakpoint-tablet-min: 768px; + $breakpoint-desktop-min: 1024px; + + --zigzag-button-icon-size: 16px; + --zigzag-button-icon-spacing: 10px; + --zigzag-button-text-color: #555963; + --zigzag-button-text-color-hover: #555963; + --zigzag-button-border-width: 1px; + --zigzag-button-border-color: #000000; + --zigzag-button-border-radius: 0; + --zigzag-button-background-color: #0052FF; + --zigzag-title-color: #000000; + --zigzag-description-color: #000000; + --zigzag-rows-spacing: 60px; + --zigzag-wrapper-border-width: 2px; + --zigzag-wrapper-border-color: #000000; + --zigzag-wrapper-border-radius: 0; + --zigzag-text-alignment: center; + --zigzag-image-width: 50%; + --zigzag-icon-width: 50%; + --zigzag-image-position: center center; + --zigzag-button-padding-block-end: 8px; + --zigzag-button-padding-block-start: 8px; + --zigzag-button-padding-inline-end: 16px; + --zigzag-button-padding-inline-start: 16px; + --zigzag-elements-gap: 32px; + --zigzag-content-width: 1304px; + --zigzag-icon-size: 256px; + --zigzag-icon-color: #555963; -.zigzag-inner-container { - border-style: solid; - border-width: 0; -} + align-items: center; + background-color: transparent; + display: flex; + flex-direction: column; -.zigzag-widget-container { - display: flex; - flex-direction: column; - background-color: transparent; - align-items: center; - &.full-width { - width: 100%; + @media screen and (min-width: $breakpoint-tablet-min) { + --zigzag-elements-gap: 40px; + --zigzag-rows-spacing: 100px; } -} - -.elementor-widget-container { - display: flex; - flex-direction: column; - align-items: center; -} - -.zigzag-block-item-container { - display: flex; - &.row-odd { - flex-direction: row !important; + @media screen and (min-width: $breakpoint-desktop-min) { + --zigzag-elements-gap: 120px; } - &.row-even { - flex-direction: row-reverse !important; + &.has-border { + border-color: var(--zigzag-wrapper-border-color); + border-style: solid; + border-width: var(--zigzag-wrapper-border-width); + border-radius: var(--zigzag-wrapper-border-radius); } - &.row-reverse-odd { - flex-direction: row-reverse !important; + &__button-icon { + fill: currentColor; + height: var(--zigzag-button-icon-size); + width: var(--zigzag-button-icon-size); } - .row-reverse-even { - flex-direction: row !important; + &__button, + &__button:not([href]):not([tabindex]) { + align-items: center; + color: var(--zigzag-button-text-color); + display: flex; + font-weight: 500; + font-size: 16px; + gap: var(--zigzag-button-icon-spacing); + text-decoration: none; + transition: $transition; + + &:hover, + &:focus { + color: var(--zigzag-button-text-color-hover); + transition: $transition; + } + + &.has-border { + border-color: var(--zigzag-button-border-color); + border-style: solid; + border-width: var(--zigzag-button-border-width); + border-radius: var(--zigzag-button-border-radius); + } + + &.is-type { + + &-button { + background-color: var(--zigzag-button-background-color); + padding-block-end: var(--zigzag-button-padding-block-end); + padding-block-start: var(--zigzag-button-padding-block-start); + padding-inline-end: var(--zigzag-button-padding-inline-end); + padding-inline-start: var(--zigzag-button-padding-inline-start); + text-decoration: none; + } + + &-link, + &-link:not([href]):not([tabindex]) { + text-decoration: underline; + } + } + + &.has-shape { + + &-sharp { + border-radius: $corners-shape-sharp; + } + + &-rounded { + border-radius: $corners-shape-rounded; + } + + &-round { + border-radius: $corners-shape-round; + } + + &-default { + border-radius: $corners-shape-default; + } + } } - &:nth-child(even) .zigzag-text-container { + &__button-container { display: flex; - flex-direction: column; - justify-content: center; - align-items: start; - width: 50%; - padding: 20px } - &:nth-child(odd) .zigzag-text-container { - display: flex; - flex-direction: column; - justify-content: center; - align-items: start; - width: 50%; - padding: 20px - } -} - -.zigzag-text-container { - display: flex; - flex-direction: column; - justify-content: center; - width: 50%; - padding: 20px; -} - -.zigzag-graphic-element-container { - width: 50%; - padding: 20px; -} -.elementor-button-link { - border-style: solid; -} - -/* Mobile */ -@media screen and (max-width: 767px) { - .zigzag-block-item-container:first-child { + &__text-container { display: flex; flex-direction: column; - } + justify-content: var(--zigzag-text-alignment); + + &.is-graphic-image { + width: calc(100% - var(--zigzag-image-width)); + } - .zigzag-widget-container, - .zigzag-text-container, - .zigzag-graphic-element-container, - .zigzag-block-item-container:nth-child(even) .zigzag-text-container, - .zigzag-block-item-container:nth-child(odd) .zigzag-text-container { - width: 100%; - } + &.is-graphic-icon { + width: calc(100% - var(--zigzag-icon-width)); + } - .zigzag-block-item-container, - .zigzag-block-item-container:nth-child(even), - .zigzag-block-item-container:nth-child(odd){ - display: flex; - flex-direction: column; - } -} + .row-even & { + @media screen and (min-width: $breakpoint-tablet-min) { + padding-inline-end: var(--zigzag-elements-gap); + } + } -.elementor-button-content-wrapper { - display: flex; - align-items: center; -} + .row-odd & { + @media screen and (min-width: $breakpoint-tablet-min) { + padding-inline-start: var(--zigzag-elements-gap); + } + } + } -.elementor-button-content-wrapper.icon-before { - flex-direction: row !important; -} + &__title { + color: var(--zigzag-title-color); + } -.elementor-button-content-wrapper.icon-after { - flex-direction: row-reverse !important; -} + &__description { + color: var(--zigzag-description-color); + font-size: 18px; + } + &__graphic-element-container { + align-items: center; + display: flex; + &.has-image { + width: var(--zigzag-image-width); + + img { + aspect-ratio: 16 / 9; + object-fit: cover; + object-position: var(--zigzag-image-position); + width: 100%; + } + } + + &.has-icon { + align-items: center; + color: var(--zigzag-icon-color); + display: flex; + justify-content: center; + width: var(--zigzag-icon-width); + + & svg { + fill: currentColor; + height: var(--zigzag-icon-size); + width: var(--zigzag-icon-size); + } + + & i { + font-size: var(--zigzag-icon-size); + } + } + } -.zigzag-button { - flex: 0 0 auto; - margin-top: 0; - text-align: start; - padding-top: 15px; + &__item-wrapper { + display: flex; + justify-content: center; + width: 100%; + } - a { - border-style: solid; - border-width: 0px; - padding: 12px 24px; + &__item-container { + display: flex; + padding-block: calc(var(--zigzag-rows-spacing) / 2); + max-width: var(--zigzag-content-width); + width: 100%; + + &.row-odd { + flex-direction: row; + } + + &.row-even { + flex-direction: row-reverse; + } + + @media screen and (max-width: $breakpoint-tablet-max) { + gap: var(--zigzag-elements-gap); + } } -} -.hello-plus-zigzag-icon { -display: flex; -align-items: center; -height: 60%; -} + @media screen and (max-width: $breakpoint-tablet-max) { + .e-zigzag__item-container { + flex-direction: column; + } + .e-zigzag__graphic-element-container, + .e-zigzag__text-container { + width: 100%; + } + } +} diff --git a/modules/content/classes/render/widget-zig-zag-render.php b/modules/content/classes/render/widget-zig-zag-render.php new file mode 100644 index 00000000..2a6ab9e3 --- /dev/null +++ b/modules/content/classes/render/widget-zig-zag-render.php @@ -0,0 +1,184 @@ +widget = $widget; + $this->settings = $widget->get_settings_for_display(); + } + + public function render(): void { + $layout_classnames = 'e-zigzag'; + + $this->widget->add_render_attribute( 'layout', [ + 'class' => $layout_classnames, + ] ); + ?> +
widget->get_render_attribute_string( 'layout' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>> + settings['first_zigzag_direction'] ? 0 : 1; + + $graphic_element = $this->settings['graphic_element']; + $repeater = 'image' === $graphic_element ? $this->settings['image_zigzag_items'] : $this->settings['icon_zigzag_items']; + + foreach ( $repeater as $key => $item ) { + $is_odd = $remainder !== $key % 2; + + $item_class = 'e-zigzag__item-container '; + + $item_class .= 'row' . ( $is_odd ? '-odd' : '-even' ); + + $this->widget->add_render_attribute( 'zigzag-item-' . $key, [ + 'class' => $item_class, + ] ); + ?> +
+
widget->get_render_attribute_string( 'zigzag-item-' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>> + render_graphic_element_container( $item, $key ); + $this->render_text_element_container( $item, $key ); + ?> +
+
+ +
+ settings['graphic_element']; + + $graphic_element_classnames = 'e-zigzag__graphic-element-container'; + + $is_icon = 'icon' === $graphic_element && ! empty( $item['icon_graphic_icon'] ); + $is_image = 'image' === $graphic_element && ! empty( $item['image_graphic_image']['url'] ); + + if ( $is_icon ) { + $graphic_element_classnames .= ' has-icon'; + } elseif ( $is_image ) { + $graphic_element_classnames .= ' has-image'; + } + + $this->widget->add_render_attribute( 'graphic-element-container-' . $key, [ + 'class' => $graphic_element_classnames, + ] ); + ?> +
widget->get_render_attribute_string( 'graphic-element-container-' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>> + + + + 'true' ] ); ?> + +
+ settings['graphic_element']; + + $button_text = $item[ $graphic_element . '_button_text' ] ?? ''; + $button_link = $item[ $graphic_element . '_button_link' ] ?? ''; + $button_icon = $item[ $graphic_element . '_button_icon' ] ?? ''; + $has_button = ! empty( $button_text ); + + $title_tag = $item[ $graphic_element . '_title_tag' ] ?? 'h2'; + $title_text = $item[ $graphic_element . '_title' ] ?? ''; + $has_title = ! empty( $title_text ); + + $description_text = $item[ $graphic_element . '_description' ] ?? ''; + $has_description = ! empty( $description_text ); + + $button_classnames = 'e-zigzag__button'; + $button_hover_animation = $this->settings['button_hover_animation'] ?? ''; + $button_has_border = $this->settings['show_button_border']; + $button_corner_shape = $this->settings['button_shape'] ?? ''; + $button_type = $this->settings['button_type'] ?? ''; + + $is_graphic_image = 'image' === $graphic_element; + $is_graphic_icon = 'icon' === $graphic_element; + $text_container_classnames = 'e-zigzag__text-container'; + + $this->widget->add_render_attribute( 'description-' . $key, [ + 'class' => 'e-zigzag__description', + ] ); + + if ( ! empty( $button_type ) ) { + $button_classnames .= ' is-type-' . $button_type; + } + + if ( $button_hover_animation ) { + $button_classnames .= ' elementor-animation-' . $button_hover_animation; + } + + if ( 'yes' === $button_has_border ) { + $button_classnames .= ' has-border'; + } + + if ( ! empty( $button_corner_shape ) ) { + $button_classnames .= ' has-shape-' . $button_corner_shape; + } + + $this->widget->add_render_attribute( 'button-link-' . $key, [ + 'class' => $button_classnames, + ] ); + + if ( ! empty( $button_link ) ) { + $this->widget->add_link_attributes( 'button-link-' . $key, $button_link ); + } + + if ( $is_graphic_icon ) { + $text_container_classnames .= ' is-graphic-icon'; + } elseif ( $is_graphic_image ) { + $text_container_classnames .= ' is-graphic-image'; + } + + $this->widget->add_render_attribute( 'text-container-' . $key, [ + 'class' => $text_container_classnames, + ] ); + ?> +
widget->get_render_attribute_string( 'text-container-' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>> + %4$s', Utils::validate_html_tag( $title_tag ), $this->widget->get_render_attribute_string( 'heading' ), 'class="e-zigzag__title"', esc_html( $title_text ) ); + // Escaped above + Utils::print_unescaped_internal_string( $title_output ); + } ?> + +

widget->get_render_attribute_string( 'description-' . $key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>

+ + + + +
+ render(); + } + protected function register_controls() { - $this->add_layout_section(); - $this->add_blocks_section(); + $this->add_content_section(); $this->add_style_section(); - $this->add_background_style_section(); - $this->add_border_style_section(); - $this->add_advanced_section(); - $this->add_motion_effects_section(); - $this->add_advanced_responsive_section(); - $this->add_custom_section(); } - private function add_layout_section() { - $this->start_controls_section( - 'layout_section', - [ - 'label' => esc_html__( 'Layout', 'hello-plus' ), - 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, - ] - ); - - $this->add_responsive_control( - 'image_width', - [ - 'label' => esc_html__( 'Image Width', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SELECT, - 'options' => [ - '100' => '50%', - '50' => '30%', - ], - 'devices' => [ 'desktop', 'tablet', 'mobile' ], - 'desktop_default' => '100', - 'tablet_default' => '100', - 'mobile_default' => '100', - 'selectors' => [ - '{{WRAPPER}} .zigzag-widget-image-container img' => 'width: {{VALUE}}%;', - ], - ] - ); + protected function add_content_section() { + $this->add_zigzags_content_section(); + } + protected function add_style_section() { + $this->add_style_zigzags_section(); + $this->add_box_style_section(); + } - $this->add_responsive_control( - 'content_alignment', + private function add_zigzags_content_section() { + $this->start_controls_section( + 'zigzags_content_section', [ - 'label' => esc_html__( 'Align Content', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::CHOOSE, - 'options' => [ - 'flex-start' => [ - 'title' => esc_html__( 'Left', 'hello-plus' ), - 'icon' => 'eicon-align-start-v', - ], - 'center' => [ - 'title' => esc_html__( 'Center', 'hello-plus' ), - 'icon' => 'eicon-align-center-v', - ], - 'flex-end' => [ - 'title' => esc_html__( 'Right', 'hello-plus' ), - 'icon' => 'eicon-align-end-v', - ], - ], - 'devices' => [ 'desktop', 'tablet', 'mobile' ], - 'desktop_default' => 'center', - 'tablet_default' => 'center', - 'mobile_default' => 'center', - 'selectors' => [ - '{{WRAPPER}} .zigzag-text-container' => 'justify-content: {{VALUE}};', - ], + 'label' => esc_html__( 'Zigzags', 'hello-plus' ), + 'tab' => Controls_Manager::TAB_CONTENT, ] ); $this->add_control( - 'first_block_direction', + 'first_zigzag_direction', [ - 'label' => esc_html__( 'First Image Position', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::CHOOSE, + 'label' => esc_html__( 'Align First Graphic', 'hello-plus' ), + 'type' => Controls_Manager::CHOOSE, 'options' => [ 'row' => [ - 'title' => esc_html__( 'Row', 'hello-plus' ), + 'title' => esc_html__( 'Left', 'hello-plus' ), 'icon' => 'eicon-order-start', ], 'row-reverse' => [ - 'title' => esc_html__( 'Row Reverse', 'hello-plus' ), + 'title' => esc_html__( 'Right', 'hello-plus' ), 'icon' => 'eicon-order-end', ], ], @@ -181,33 +96,16 @@ private function add_layout_section() { $this->add_control( 'important_note', [ - 'label' => '' . esc_html__( 'Note: Image position applies only on desktop.', 'hello-plus' ) . '', - 'type' => \Elementor\Controls_Manager::HEADING, - 'separator' => 'default', - ] - ); - - $this->end_controls_section(); - } - - private function add_blocks_section( ) { - $this->start_controls_section( - 'Blocks_section', - [ - 'label' => esc_html__( 'Blocks', 'hello-plus' ), - 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, + 'label' => esc_html__( 'Note: Graphic alignment does not apply to Mobile', 'hello-plus' ), + 'type' => Controls_Manager::HEADING, ] ); - /* Start repeater */ - - $repeater = new \Elementor\Repeater(); - - $repeater->add_control( + $this->add_control( 'graphic_element', [ 'label' => esc_html__( 'Graphic Element', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::CHOOSE, + 'type' => Controls_Manager::CHOOSE, 'options' => [ 'image' => [ 'title' => esc_html__( 'Image', 'hello-plus' ), @@ -219,45 +117,52 @@ private function add_blocks_section( ) { ], ], 'default' => 'image', - 'toggle' => true, + 'toggle' => false, ] ); - $repeater->add_control( - 'graphic_image', - [ - 'label' => esc_html__( 'Image', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::MEDIA, - 'default' => [ - 'url' => \Elementor\Utils::get_placeholder_image_src(), - ], - 'condition' => [ - 'graphic_element' => 'image', - ], - ] - ); + $this->add_graphic_element_repeater( 'image' ); - $repeater->add_control( - 'graphic_icon', - [ - 'label' => esc_html__( 'Icon', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::ICONS, - 'default' => [ - 'value' => 'fas fa-circle', - 'library' => 'fa-solid', - ], - 'condition' => [ - 'graphic_element' => 'icon', - ], - ] - ); + $this->add_graphic_element_repeater( 'icon' ); + + $this->end_controls_section(); + } + + private function add_graphic_element_repeater( $type ) { + $repeater = new Repeater(); + + if ( 'icon' === $type ) { + $repeater->add_control( + $type . '_graphic_icon', + [ + 'label' => esc_html__( 'Icon', 'hello-plus' ), + 'type' => Controls_Manager::ICONS, + 'default' => [ + 'value' => 'fas fa-circle', + 'library' => 'fa-solid', + ], + ] + ); + } + if ( 'image' === $type ) { + $repeater->add_control( + $type . '_graphic_image', + [ + 'label' => esc_html__( 'Image', 'hello-plus' ), + 'type' => Controls_Manager::MEDIA, + 'default' => [ + 'url' => Utils::get_placeholder_image_src(), + ], + ] + ); + } $repeater->add_control( - 'title', + $type . '_title', [ 'label' => esc_html__( 'Title', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::TEXT, + 'type' => Controls_Manager::TEXT, 'default' => esc_html__( 'Default title', 'hello-plus' ), 'label_block' => true, 'placeholder' => esc_html__( 'Type your title here', 'hello-plus' ), @@ -268,10 +173,30 @@ private function add_blocks_section( ) { ); $repeater->add_control( - 'description', + $type . '_title_tag', + [ + 'label' => esc_html__( 'HTML Tag', 'hello-plus' ), + 'type' => Controls_Manager::SELECT, + 'options' => [ + 'h1' => 'H1', + 'h2' => 'H2', + 'h3' => 'H3', + 'h4' => 'H4', + 'h5' => 'H5', + 'h6' => 'H6', + 'div' => 'div', + 'span' => 'span', + 'p' => 'p', + ], + 'default' => 'h2', + ] + ); + + $repeater->add_control( + $type . '_description', [ 'label' => esc_html__( 'Description', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::TEXTAREA, + 'type' => Controls_Manager::TEXTAREA, 'rows' => 6, 'default' => esc_html__( 'Default description', 'hello-plus' ), 'placeholder' => esc_html__( 'Type your description here', 'hello-plus' ), @@ -281,120 +206,245 @@ private function add_blocks_section( ) { ] ); - // Add a control for the button text $repeater->add_control( - 'button_text', + $type . '_button_label', + [ + 'label' => esc_html__( 'Button', 'hello-plus' ), + 'type' => Controls_Manager::HEADING, + ] + ); + + $repeater->add_control( + $type . '_button_text', [ - 'label' => esc_html__( 'Button Text', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::TEXT, + 'label' => esc_html__( 'Text', 'hello-plus' ), + 'type' => Controls_Manager::TEXT, 'default' => esc_html__( 'Learn More', 'hello-plus' ), 'dynamic' => [ 'active' => true, - ] + ], ] ); $repeater->add_control( - 'button_link', + $type . '_button_link', [ 'label' => esc_html__( 'Link', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::URL, + 'type' => Controls_Manager::URL, 'dynamic' => [ 'active' => true, ], 'default' => [ - 'url' => '#', + 'url' => '', + 'is_external' => true, ], ] ); $repeater->add_control( - 'button_icon', + $type . '_button_icon', [ 'label' => esc_html__( 'Icon', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::ICONS, + 'type' => Controls_Manager::ICONS, 'label_block' => false, 'skin' => 'inline', ] ); - - - /* End repeater */ - $this->add_control( - 'block_items', + $type . '_zigzag_items', [ - 'label' => esc_html__( 'Block Items', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::REPEATER, - 'fields' => $repeater->get_controls(), /* Use our repeater */ + 'type' => Controls_Manager::REPEATER, + 'fields' => $repeater->get_controls(), 'default' => [ [ - 'title' => esc_html__( 'Social media done right', 'hello-plus' ), - 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet', + $type . '_title' => esc_html__( 'Social media done right', 'hello-plus' ), + $type . '_description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet', ], [ - 'title' => esc_html__( 'Award-winning studio', 'hello-plus' ), - 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet', + $type . '_title' => esc_html__( 'Award-winning studio', 'hello-plus' ), + $type . '_description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet', ], [ - 'title' => esc_html__( 'Join Our Community', 'hello-plus' ), - 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet', + $type . '_title' => esc_html__( 'Join Our Community', 'hello-plus' ), + $type . '_description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet', ], [ - 'title' => esc_html__( 'Your Perfect Match', 'hello-plus' ), - 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet', + $type . '_title' => esc_html__( 'Your Perfect Match', 'hello-plus' ), + $type . '_description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet', ], ], - 'title_field' => '{{{ title }}}', + 'title_field' => '{{{ ' . $type . '_title }}}', + 'condition' => [ + 'graphic_element' => $type, + ], ] ); - - $this->end_controls_section(); } - private function add_style_section() { + private function add_style_zigzags_section() { $this->start_controls_section( - 'style_section', + 'style_zigzags_section', [ - 'label' => esc_html__( 'Blocks', 'hello-plus' ), - 'tab' => \Elementor\Controls_Manager::TAB_STYLE, + 'label' => esc_html__( 'Zigzag', 'hello-plus' ), + 'tab' => Controls_Manager::TAB_STYLE, ] ); $this->add_control( - 'style_spacing', + 'image_label', [ - 'label' => esc_html__( 'Spacing', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::HEADING, + 'label' => esc_html__( 'Image', 'hello-plus' ), + 'type' => Controls_Manager::HEADING, 'separator' => 'before', + 'condition' => [ + 'graphic_element' => 'image', + ], ] ); $this->add_responsive_control( - 'space_rows', + 'image_width', [ - 'label' => esc_html__( 'Space Between Rows', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, - 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ], + 'label' => esc_html__( 'Image Width', 'hello-plus' ), + 'type' => Controls_Manager::SELECT, + 'options' => [ + '50%' => '50%', + '30%' => '30%', + ], + 'default' => '50%', + 'devices' => [ 'desktop', 'tablet', 'mobile' ], + 'selectors' => [ + '{{WRAPPER}} .e-zigzag' => '--zigzag-image-width: {{VALUE}};', + ], + 'condition' => [ + 'graphic_element' => 'image', + ], + ] + ); + + $this->add_responsive_control( + 'image_position', + [ + 'label' => esc_html__( 'Position', 'hello-plus' ), + 'type' => Controls_Manager::SELECT, + 'desktop_default' => 'center center', + 'tablet_default' => 'center center', + 'mobile_default' => 'center center', + 'options' => [ + '' => esc_html__( 'Default', 'hello-plus' ), + 'center center' => esc_html__( 'Center Center', 'hello-plus' ), + 'center left' => esc_html__( 'Center Left', 'hello-plus' ), + 'center right' => esc_html__( 'Center Right', 'hello-plus' ), + 'top center' => esc_html__( 'Top Center', 'hello-plus' ), + 'top left' => esc_html__( 'Top Left', 'hello-plus' ), + 'top right' => esc_html__( 'Top Right', 'hello-plus' ), + 'bottom center' => esc_html__( 'Bottom Center', 'hello-plus' ), + 'bottom left' => esc_html__( 'Bottom Left', 'hello-plus' ), + 'bottom right' => esc_html__( 'Bottom Right', 'hello-plus' ), + ], + 'selectors' => [ + '{{WRAPPER}} .e-zigzag' => '--zigzag-image-position: {{VALUE}}', + ], + 'condition' => [ + 'graphic_element' => 'image', + ], + ] + ); + + $this->add_control( + 'icon_label', + [ + 'label' => esc_html__( 'Icon', 'hello-plus' ), + 'type' => Controls_Manager::HEADING, + 'separator' => 'before', + 'condition' => [ + 'graphic_element' => 'icon', + ], + ] + ); + + $this->add_responsive_control( + 'icon_width', + [ + 'label' => esc_html__( 'Box Width', 'hello-plus' ), + 'type' => Controls_Manager::SELECT, + 'options' => [ + '50%' => '50%', + '30%' => '30%', + ], + 'default' => '50%', + 'devices' => [ 'desktop', 'tablet', 'mobile' ], + 'selectors' => [ + '{{WRAPPER}} .e-zigzag' => '--zigzag-icon-width: {{VALUE}};', + ], + 'condition' => [ + 'graphic_element' => 'icon', + ], + ] + ); + + $this->add_control( + 'icon_zigzag_color', + [ + 'label' => esc_html__( 'Color', 'hello-plus' ), + 'type' => Controls_Manager::COLOR, + 'selectors' => [ + '{{WRAPPER}} .e-zigzag' => '--zigzag-icon-color: {{VALUE}}', + ], + 'condition' => [ + 'graphic_element' => 'icon', + ], + ] + ); + + $this->add_responsive_control( + 'icon_zigzag_size', + [ + 'label' => esc_html__( 'Icon Size', 'hello-plus' ), + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em', 'rem', 'custom' ], 'range' => [ 'px' => [ - 'min' => 0, - 'max' => 1000, - 'step' => 5, + 'max' => 300, ], '%' => [ - 'min' => 0, 'max' => 100, ], ], - 'default' => [ - 'unit' => 'px', - 'size' => 40, + 'selectors' => [ + '{{WRAPPER}} .e-zigzag' => '--zigzag-icon-size: {{SIZE}}{{UNIT}};', + ], + 'condition' => [ + 'graphic_element' => 'icon', + ], + ] + ); + + $this->add_responsive_control( + 'content_alignment', + [ + 'label' => esc_html__( 'Content Position', 'hello-plus' ), + 'type' => Controls_Manager::CHOOSE, + 'options' => [ + 'flex-start' => [ + 'title' => esc_html__( 'Start', 'hello-plus' ), + 'icon' => 'eicon-align-start-v', + ], + 'center' => [ + 'title' => esc_html__( 'Center', 'hello-plus' ), + 'icon' => 'eicon-align-center-v', + ], + 'flex-end' => [ + 'title' => esc_html__( 'End', 'hello-plus' ), + 'icon' => 'eicon-align-end-v', + ], ], + 'default' => 'center', 'selectors' => [ - '{{WRAPPER}} .zigzag-block-item-container' => 'margin-bottom: {{SIZE}}{{UNIT}};', + '{{WRAPPER}} .e-zigzag' => '--zigzag-text-alignment: {{VALUE}};', ], + 'separator' => 'before', ] ); @@ -402,8 +452,7 @@ private function add_style_section() { 'style_heading', [ 'label' => esc_html__( 'Heading', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::HEADING, - 'separator' => 'before', + 'type' => Controls_Manager::HEADING, ] ); @@ -411,52 +460,18 @@ private function add_style_section() { 'title_color', [ 'label' => esc_html__( 'Text Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, + 'type' => Controls_Manager::COLOR, 'selectors' => [ - '{{WRAPPER}} .zigzag-block-item-container h2' => 'color: {{VALUE}}', + '{{WRAPPER}} .e-zigzag' => '--zigzag-title-color: {{VALUE}}', ], ] ); $this->add_group_control( - \Elementor\Group_Control_Typography::get_type(), + Group_Control_Typography::get_type(), [ 'name' => 'title_typography', - 'selector' => '{{WRAPPER}} .zigzag-block-item-container h2', - 'fields_options' => [ - 'typography' => ['default' => 'yes'], - 'font_family' => [ - 'default' => 'Poppins', - ], - 'font_size' => [ - 'default' => [ - 'unit' => 'px', - 'size' => 40, - ], - 'tablet_default' => [ - 'unit' => 'px', - 'size' => 36, - ], - 'mobile_default' => [ - 'unit' => 'px', - 'size' => 32, - ], - ], - 'line_height' => [ - 'default' => [ - 'unit' => 'px', - 'size' => 58, - ], - 'tablet_default' => [ - 'unit' => 'px', - 'size' => 52, - ], - 'mobile_default' => [ - 'unit' => 'px', - 'size' => 46, - ], - ], - ] + 'selector' => '{{WRAPPER}} .e-zigzag__title', ] ); @@ -464,7 +479,7 @@ private function add_style_section() { 'style_description', [ 'label' => esc_html__( 'Paragraph', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::HEADING, + 'type' => Controls_Manager::HEADING, 'separator' => 'default', ] ); @@ -473,52 +488,39 @@ private function add_style_section() { 'description_color', [ 'label' => esc_html__( 'Text Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, + 'type' => Controls_Manager::COLOR, 'selectors' => [ - '{{WRAPPER}} .zigzag-block-item-container p' => 'color: {{VALUE}}', + '{{WRAPPER}} .e-zigzag' => '--zigzag-description-color: {{VALUE}}', ], ] ); $this->add_group_control( - \Elementor\Group_Control_Typography::get_type(), + Group_Control_Typography::get_type(), [ 'name' => 'description_typography', - 'selector' => '{{WRAPPER}} .zigzag-block-item-container p', - 'fields_options' => [ - 'typography' => ['default' => 'yes'], - 'font_family' => [ - 'default' => 'Poppins', - ], - 'font_size' => [ - 'default' => [ - 'unit' => 'px', - 'size' => 18, - ], - 'tablet_default' => [ - 'unit' => 'px', - 'size' => 16, - ], - 'mobile_default' => [ - 'unit' => 'px', - 'size' => 14, - ], + 'selector' => '{{WRAPPER}} .e-zigzag__description', + ] + ); + + $this->add_responsive_control( + 'elements_gap', + [ + 'label' => esc_html__( 'Gap', 'hello-plus' ), + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em', 'rem', 'custom' ], + 'range' => [ + 'px' => [ + 'max' => 200, ], - 'line_height' => [ - 'default' => [ - 'unit' => 'px', - 'size' => 32, - ], - 'tablet_default' => [ - 'unit' => 'px', - 'size' => 28, - ], - 'mobile_default' => [ - 'unit' => 'px', - 'size' => 24, - ], + '%' => [ + 'max' => 100, ], - ] + ], + 'selectors' => [ + '{{WRAPPER}} .e-zigzag' => '--zigzag-elements-gap: {{SIZE}}{{UNIT}};', + ], + 'separator' => 'before', ] ); @@ -526,76 +528,59 @@ private function add_style_section() { 'style_button', [ 'label' => esc_html__( 'Button', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::HEADING, - 'separator' => 'default', + 'type' => Controls_Manager::HEADING, + 'separator' => 'before', + ] + ); + + $this->add_control( + 'button_type', + [ + 'label' => esc_html__( 'Type', 'hello-plus' ), + 'type' => Controls_Manager::SELECT, + 'default' => 'link', + 'options' => [ + 'button' => esc_html__( 'Button', 'hello-plus' ), + 'link' => esc_html__( 'Link', 'hello-plus' ), + ], ] ); $this->add_group_control( - \Elementor\Group_Control_Typography::get_type(), + Group_Control_Typography::get_type(), [ 'name' => 'button_typography', - 'selector' => '{{WRAPPER}} .zigzag-button a', + 'selector' => '{{WRAPPER}} .e-zigzag__button', 'fields_options' => [ - 'typography' => ['default' => 'yes'], - 'font_family' => [ - 'default' => 'Poppins', - ], - 'font_weight' => [ - 'default' => '500', - ], - 'font_size' => [ - 'default' => [ - 'unit' => 'px', - 'size' => 16, - ], - 'tablet_default' => [ - 'unit' => 'px', - 'size' => 14, - ], - 'mobile_default' => [ - 'unit' => 'px', - 'size' => 12, - ], - ], - 'line_height' => [ - 'default' => [ - 'unit' => 'px', - 'size' => 24, - ], - 'tablet_default' => [ - 'unit' => 'px', - 'size' => 22, - ], - 'mobile_default' => [ - 'unit' => 'px', - 'size' => 20, - ], - ], - 'text_decoration' => [ - 'default' => 'underline', - ], - ] + 'typography' => [ 'default' => 'yes' ], + ], ] ); - $this->add_control( + $this->add_responsive_control( 'button_icon_position', [ 'label' => esc_html__( 'Icon Position', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::CHOOSE, + 'type' => Controls_Manager::CHOOSE, + 'default' => is_rtl() ? 'row' : 'row-reverse', + 'toggle' => false, 'options' => [ - 'left' => [ - 'title' => esc_html__( 'Left', 'hello-plus' ), + 'row' => [ + 'title' => esc_html__( 'Start', 'hello-plus' ), 'icon' => 'eicon-h-align-left', ], - 'right' => [ - 'title' => esc_html__( 'Right', 'hello-plus' ), + 'row-reverse' => [ + 'title' => esc_html__( 'End', 'hello-plus' ), 'icon' => 'eicon-h-align-right', ], ], - 'default' => 'right', - 'toggle' => true, + 'selectors_dictionary' => [ + 'left' => is_rtl() ? 'row-reverse' : 'row', + 'right' => is_rtl() ? 'row' : 'row-reverse', + ], + 'selectors' => [ + '{{WRAPPER}} .e-zigzag__button' => 'flex-direction: {{VALUE}};', + ], ] ); @@ -603,26 +588,24 @@ private function add_style_section() { 'button_icon_spacing', [ 'label' => esc_html__( 'Icon Spacing', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, - 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ], + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em', 'rem', 'custom' ], 'range' => [ 'px' => [ - 'min' => 0, 'max' => 100, - 'step' => 2, + ], + 'em' => [ + 'max' => 5, + ], + 'rem' => [ + 'max' => 5, ], '%' => [ - 'min' => 0, 'max' => 100, ], ], - 'default' => [ - 'unit' => 'px', - 'size' => 10, - ], 'selectors' => [ - '{{WRAPPER}} .zigzag-button a .icon-left' => 'margin-right: {{SIZE}}{{UNIT}};', - '{{WRAPPER}} .zigzag-button a .icon-right' => 'margin-left: {{SIZE}}{{UNIT}};', + '{{WRAPPER}} .e-zigzag' => '--zigzag-button-icon-spacing: {{SIZE}}{{UNIT}};', ], ] ); @@ -642,34 +625,27 @@ private function add_style_section() { 'button_text_color', [ 'label' => esc_html__( 'Text Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, - 'default' => '#000000', + 'type' => Controls_Manager::COLOR, 'selectors' => [ - '{{WRAPPER}} .zigzag-button a' => 'color: {{VALUE}}', + '{{WRAPPER}} .e-zigzag' => '--zigzag-button-text-color: {{VALUE}}', ], ] ); - $this->add_control( - 'button_icon_color', + $this->add_group_control( + Group_Control_Background::get_type(), [ - 'label' => esc_html__( 'Icon Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, - 'default' => '#000000', // Default to black if no color is selected - 'selectors' => [ - '{{WRAPPER}} .icon-left, {{WRAPPER}} .icon-right' => 'color: {{VALUE}};', + 'name' => 'button_background', + 'types' => [ 'classic', 'gradient' ], + 'exclude' => [ 'image' ], + 'selector' => '{{WRAPPER}} .e-zigzag__button', + 'fields_options' => [ + 'background' => [ + 'default' => 'classic', + ], ], - ] - ); - - $this->add_control( - 'button_background_color', - [ - 'label' => esc_html__( 'Background Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, - 'default' => '#00000000', - 'selectors' => [ - '{{WRAPPER}} .zigzag-button a' => 'background-color: {{VALUE}}', // Replace .your-class with .elementor-button-link + 'condition' => [ + 'button_type' => 'button', ], ] ); @@ -687,33 +663,27 @@ private function add_style_section() { 'hover_button_text_color', [ 'label' => esc_html__( 'Text Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, + 'type' => Controls_Manager::COLOR, 'selectors' => [ - '{{WRAPPER}} .zigzag-button a:hover' => 'color: {{VALUE}}', + '{{WRAPPER}} .e-zigzag' => '--zigzag-button-text-color-hover: {{VALUE}}', ], ] ); - // Button Icon Color on Hover - $this->add_control( - 'hover_button_icon_color', + $this->add_group_control( + Group_Control_Background::get_type(), [ - 'label' => esc_html__( 'Icon Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, - 'selectors' => [ - '{{WRAPPER}} .icon-left:hover, {{WRAPPER}} .icon-right:hover' => 'color: {{VALUE}}', + 'name' => 'button_background_hover', + 'types' => [ 'classic', 'gradient' ], + 'exclude' => [ 'image' ], + 'selector' => '{{WRAPPER}} .e-zigzag__button:hover, {{WRAPPER}} .e-zigzag__button:focus', + 'fields_options' => [ + 'background' => [ + 'default' => 'classic', + ], ], - ] - ); - - // Button Background Color on Hover - $this->add_control( - 'hover_button_background_color', - [ - 'label' => esc_html__( 'Background Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, - 'selectors' => [ - '{{WRAPPER}} .zigzag-button a:hover' => 'background-color: {{VALUE}}', + 'condition' => [ + 'button_type' => 'button', ], ] ); @@ -722,7 +692,7 @@ private function add_style_section() { 'button_hover_animation', [ 'label' => esc_html__( 'Hover Animation', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::HOVER_ANIMATION, + 'type' => Controls_Manager::HOVER_ANIMATION, ] ); @@ -732,21 +702,18 @@ private function add_style_section() { $this->end_controls_tabs(); $this->add_control( - 'button_style_divider', - [ - 'type' => \Elementor\Controls_Manager::DIVIDER, - ] - ); - - $this->add_control( - 'show_border', + 'show_button_border', [ 'label' => esc_html__( 'Border', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SWITCHER, + 'type' => Controls_Manager::SWITCHER, 'label_on' => esc_html__( 'Yes', 'hello-plus' ), 'label_off' => esc_html__( 'No', 'hello-plus' ), 'return_value' => 'yes', 'default' => 'no', + 'separator' => 'before', + 'condition' => [ + 'button_type' => 'button', + ], ] ); @@ -754,7 +721,7 @@ private function add_style_section() { 'button_border_width', [ 'label' => __( 'Border Width', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, + 'type' => Controls_Manager::SLIDER, 'size_units' => [ 'px', '%', 'em', 'rem' ], 'range' => [ 'px' => [ @@ -767,15 +734,11 @@ private function add_style_section() { 'max' => 100, ], ], - 'default' => [ - 'unit' => 'px', - 'size' => 2, + 'selectors' => [ + '{{WRAPPER}} .e-zigzag' => '--zigzag-button-border-width: {{SIZE}}{{UNIT}};', ], 'condition' => [ - 'show_border' => 'yes', - ], - 'selectors' => [ - '{{WRAPPER}} .zigzag-button a' => 'border-width: {{SIZE}}{{UNIT}}; border-style: solid;', + 'show_button_border' => 'yes', ], ] ); @@ -784,357 +747,92 @@ private function add_style_section() { 'button_border_color', [ 'label' => esc_html__( 'Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, - 'default' => '#000000', // Default to black if no color is selected - 'selectors' => [ - '{{WRAPPER}} .zigzag-button a' => 'border-color: {{VALUE}}', - ], - 'condition' => [ - 'show_border' => 'yes', - ], - ] - ); - - $this->add_responsive_control( - 'button_border_radius', - [ - 'label' => __( 'Border Radius', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, - 'size_units' => [ 'px', '%', 'em', 'rem' ], - 'range' => [ - 'px' => [ - 'min' => 0, - 'max' => 100, - 'step' => 1, - ], - '%' => [ - 'min' => 0, - 'max' => 100, - ], - ], - 'selectors' => [ - '{{WRAPPER}} .zigzag-button a' => 'border-radius: {{SIZE}}{{UNIT}};', - ], - ] - ); - - $this->add_control( - 'show_button_border_shadow', - [ - 'label' => esc_html__( 'Box Shadow', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SWITCHER, - 'label_on' => esc_html__( 'Yes', 'hello-plus' ), - 'label_off' => esc_html__( 'No', 'hello-plus' ), - 'return_value' => 'yes', - 'default' => 'no', - ] - ); - - $this->add_control( - 'zigzag_button_box_shadow', - [ - 'label' => esc_html__( 'Box Shadow', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::BOX_SHADOW, - 'condition' => [ - 'show_button_border_shadow' => 'yes', - ], - 'selectors' => [ - '{{WRAPPER}} .zigzag-button a' => 'box-shadow: {{HORIZONTAL}}px {{VERTICAL}}px {{BLUR}}px {{SPREAD}}px {{COLOR}};', - ], - ] - ); - - $this->end_controls_section(); - } - - private function add_border_style_section( ) { - $this->start_controls_section( - 'border_style_section', - [ - 'label' => esc_html__( 'Border', 'hello-plus' ), - 'tab' => \Elementor\Controls_Manager::TAB_STYLE, - ] - ); - - $this->add_control( - 'show_widget_border', - [ - 'label' => esc_html__( 'Border', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SWITCHER, - 'label_on' => esc_html__( 'Show', 'hello-plus' ), - 'label_off' => esc_html__( 'Hide', 'hello-plus' ), - 'return_value' => 'yes', - 'default' => 'no', - ] - ); - - $this->add_responsive_control( - 'widget_border_width', - [ - 'label' => esc_html__( 'Border Width', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, - 'size_units' => [ 'px', '%', 'vw' ], - 'range' => [ - 'px' => [ - 'min' => 0, - 'max' => 2000, - ], - '%' => [ - 'min' => 0, - 'max' => 100, - ], - 'vw' => [ - 'min' => 0, - 'max' => 100, - ], - ], - 'default' => [ - 'unit' => 'px', - 'size' => 2, - ], - 'condition' => [ - 'show_widget_border' => 'yes', - ], + 'type' => Controls_Manager::COLOR, 'selectors' => [ - '{{WRAPPER}} .zigzag-widget-container' => 'border-width: {{SIZE}}{{UNIT}};', - ], - ] - ); - - $this->add_control( - 'widget_border_color', - [ - 'label' => esc_html__( 'Border Color', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::COLOR, - 'condition' => [ - 'show_widget_border' => 'yes', - ], - 'selectors' => [ - '{{WRAPPER}} .zigzag-widget-container' => 'border-color: {{VALUE}}', - ], - ] - ); - - $this->add_responsive_control( - 'widget_border_radius', - [ - 'label' => esc_html__( 'Border Radius', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, - 'size_units' => [ 'px', '%' ], - 'range' => [ - 'px' => [ - 'min' => 0, - 'max' => 1000, - 'step' => 2, - ], - '%' => [ - 'min' => 0, - 'max' => 100, - ], - ], - 'default' => [ - 'unit' => 'px', - 'size' => 0, + '{{WRAPPER}} .e-zigzag' => '--zigzag-button-border-color: {{VALUE}}', ], 'condition' => [ - 'show_widget_border' => 'yes', - ], - 'selectors' => [ - '{{WRAPPER}} .zigzag-widget-container' => 'border-radius: {{SIZE}}{{UNIT}};', + 'show_button_border' => 'yes', ], ] ); $this->add_control( - 'show_widget_shadow', + 'button_shape', [ - 'label' => esc_html__( 'Box Shadow', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SWITCHER, - 'label_on' => esc_html__( 'Yes', 'hello-plus' ), - 'label_off' => esc_html__( 'No', 'hello-plus' ), - 'return_value' => 'yes', - 'default' => 'no', - 'condition' => [ - 'show_widget_border' => 'yes', + 'label' => esc_html__( 'Shape', 'hello-plus' ), + 'type' => Controls_Manager::SELECT, + 'default' => 'default', + 'options' => [ + 'default' => esc_html__( 'Default', 'hello-plus' ), + 'sharp' => esc_html__( 'Sharp', 'hello-plus' ), + 'round' => esc_html__( 'Round', 'hello-plus' ), + 'rounded' => esc_html__( 'Rounded', 'hello-plus' ), ], - ] - ); - - $this->add_control( - 'widget_box_shadow', - [ - 'label' => esc_html__( 'Box Shadow', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::BOX_SHADOW, 'condition' => [ - 'show_widget_shadow' => 'yes', - ], - 'selectors' => [ - '{{WRAPPER}} .zigzag-widget-container' => 'box-shadow: {{HORIZONTAL}}px {{VERTICAL}}px {{BLUR}}px {{SPREAD}}px {{COLOR}};', + 'button_type' => 'button', ], ] ); - $this->end_controls_section(); - } - - private function add_background_style_section( ) { - $this->start_controls_section( - 'background_style-section', - [ - 'label' => esc_html__( 'Background', 'hello-plus' ), - 'tab' => \Elementor\Controls_Manager::TAB_STYLE, - ] - ); - $this->add_group_control( - \Elementor\Group_Control_Background::get_type(), + Group_Control_Box_Shadow::get_type(), [ - 'name' => 'background', - 'types' => [ 'classic', 'gradient' ], - 'exclude' => ['image'], - 'selector' => '{{WRAPPER}} .zigzag-widget-container', - - ] - ); - - $this->add_control( - 'show_alternate_background', - [ - 'label' => esc_html__( 'Alternate Background', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SWITCHER, - 'label_on' => esc_html__( 'Show', 'hello-plus' ), - 'label_off' => esc_html__( 'Hide', 'hello-plus' ), - 'return_value' => 'yes', - 'default' => 'no', - ] - ); - - $this->add_group_control( - \Elementor\Group_Control_Background::get_type(), - [ - 'name' => 'alternate_background', - 'types' => [ 'classic', 'gradient' ], - 'exclude' => ['image'], + 'name' => 'button_box_shadow', + 'selector' => '{{WRAPPER}} .e-zigzag__button', 'condition' => [ - 'show_alternate_background' => 'yes', + 'button_type' => 'button', ], - 'selector' => '{{WRAPPER}} .zigzag-block-item-container:nth-child(even)', - ] - ); - - $this->end_controls_section(); - } - - private function add_advanced_section() { - $this->start_controls_section( - 'advanced_section', - [ - 'label' => esc_html__( 'Layout', 'hello-plus' ), - 'tab' => \Elementor\Controls_Manager::TAB_ADVANCED, - ] - ); - - $this->add_control( - 'full_width', - [ - 'label' => __( 'Full Width', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SWITCHER, - 'label_on' => __( 'Yes', 'hello-plus' ), - 'label_off' => __( 'No', 'hello-plus' ), - 'return_value' => 'yes', - 'default' => 'yes', ] ); $this->add_responsive_control( - 'zigzag_width', + 'button_padding', [ - 'label' => esc_html__( 'Zig-Zag Width', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, - 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ], - 'range' => [ - 'px' => [ - 'min' => 0, - 'max' => 1600, - 'step' => 2, - ], - '%' => [ - 'min' => 0, - 'max' => 100, - ], - ], - 'default' => [ - 'unit' => 'px', - 'size' => 1000, - ], - + 'label' => esc_html__( 'Padding', 'hello-plus' ), + 'type' => Controls_Manager::DIMENSIONS, + 'size_units' => [ 'px', '%', 'em', 'rem' ], 'selectors' => [ - '{{WRAPPER}} .zigzag-widget-container' => 'width: {{SIZE}}{{UNIT}};', + '{{WRAPPER}} .e-zigzag' => '--zigzag-button-padding-block-end: {{BOTTOM}}{{UNIT}}; --zigzag-button-padding-block-start: {{TOP}}{{UNIT}}; --zigzag-button-padding-inline-end: {{RIGHT}}{{UNIT}}; --zigzag-button-padding-inline-start: {{LEFT}}{{UNIT}};', ], + 'separator' => 'before', 'condition' => [ - 'full_width!' => 'yes', + 'button_type' => 'button', ], ] ); $this->add_responsive_control( - 'main_content_width', + 'content_width', [ 'label' => esc_html__( 'Content Width', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, - 'size_units' => [ 'px', '%' ], - 'range' => [ - 'px' => [ - 'min' => 0, - 'max' => 500, - 'step' => 1, - ], - '%' => [ - 'min' => 0, - 'max' => 100, - ], - ], - 'selectors' => [ - '{{WRAPPER}} .zigzag-widget-container' => 'padding-right: calc(100% - {{SIZE}}{{UNIT}}); padding-left: calc(100% - {{SIZE}}{{UNIT}});', -// '{{WRAPPER}} .zigzag-widget-container' => 'padding-right: calc(500px - {{SIZE}}{{UNIT}}); padding-left: calc(500px - {{SIZE}}{{UNIT}});', - ], - ] - ); - - $this->add_responsive_control( - 'padding_top', - [ - 'label' => esc_html__( 'Top Padding', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, - 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ], + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em', 'rem', '%', 'custom' ], 'range' => [ 'px' => [ - 'min' => 0, - 'max' => 1000, - 'step' => 1, + 'max' => 1600, ], '%' => [ - 'min' => 0, 'max' => 100, ], ], 'selectors' => [ - '{{WRAPPER}} .zigzag-widget-container' => 'padding-top: {{SIZE}}{{UNIT}};', + '{{WRAPPER}} .e-zigzag' => '--zigzag-content-width: {{SIZE}}{{UNIT}};', ], + 'separator' => 'before', ] ); $this->add_responsive_control( - 'padding_bottom', + 'space_rows', [ - 'label' => esc_html__( 'Bottom Padding', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SLIDER, + 'label' => esc_html__( 'Space Between', 'hello-plus' ), + 'type' => Controls_Manager::SLIDER, 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ], 'range' => [ 'px' => [ 'min' => 0, - 'max' => 1000, - 'step' => 1, + 'max' => 200, ], '%' => [ 'min' => 0, @@ -1142,22 +840,7 @@ private function add_advanced_section() { ], ], 'selectors' => [ - '{{WRAPPER}} .zigzag-widget-container' => 'padding-bottom: {{SIZE}}{{UNIT}};', - ], - ] - ); - - $this->add_responsive_control( - 'element_spacing', - [ - 'label' => esc_html__( 'Element Spacing', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::SELECT, - 'default' => 'default', - 'options' => [ - 'default' => esc_html__( 'Default', 'hello-plus' ), - ], - 'selectors' => [ - '{{WRAPPER}} .your-class' => 'margin: {{VALUE}};', + '{{WRAPPER}} .e-zigzag' => '--zigzag-rows-spacing: {{SIZE}}{{UNIT}};', ], ] ); @@ -1165,110 +848,38 @@ private function add_advanced_section() { $this->end_controls_section(); } - private function add_motion_effects_section() { - // Motion Effects Section + private function add_box_style_section() { $this->start_controls_section( - 'zigzag_motion_effects', - [ - 'label' => esc_html__('Motion Effects', 'hello-plus'), - 'tab' => Controls_Manager::TAB_ADVANCED, - ] - ); - - $this->add_control( - 'zigzag_entrance_animation', + 'box_style_section', [ - 'label' => esc_html__( 'Entrance Animation', 'hello-plus' ), - 'type' => Controls_Manager::ANIMATION, - 'default' => 'none', + 'label' => esc_html__( 'Box', 'hello-plus' ), + 'tab' => Controls_Manager::TAB_STYLE, ] ); $this->add_control( - 'zigzag_animation_duration', + 'box_background_label', [ - 'label' => esc_html__('Animation Duration', 'hello-plus'), - 'type' => Controls_Manager::SELECT, - 'default' => 'normal', - 'options' => [ - 'slow' => esc_html__('Slow', 'hello-plus'), - 'normal' => esc_html__('Normal', 'hello-plus'), - 'fast' => esc_html__('Fast', 'hello-plus'), - ], - 'condition' => [ - 'zigzag_entrance_animation!' => 'none', - ], - ] - ); - - $this->add_control( - 'zigzag_animation_delay', - [ - 'label' => esc_html__('Animation Delay (ms)', 'hello-plus'), - 'type' => Controls_Manager::NUMBER, - 'default' => 0, - 'min' => 0, - 'max' => 3000, - 'condition' => [ - 'zigzag_entrance_animation!' => 'none', - ], - ] - ); - - $this->end_controls_section(); - } - - private function add_advanced_responsive_section() { - // Responsive Section - $this->start_controls_section( - 'zigzag_advanced_responsive', - [ - 'label' => esc_html__( 'Responsive', 'hello-plus' ), - 'tab' => Controls_Manager::TAB_ADVANCED, - ] - ); - - // Responsive controls - $this->add_control( - 'zigzag_responsive_description', - [ - 'raw' => esc_html__( 'Responsive visibility will take effect only on preview mode or live page, and not while editing in Elementor.', 'hello-plus' ), - 'type' => Controls_Manager::RAW_HTML, - 'content_classes' => 'elementor-descriptor', + 'label' => esc_html__( 'Background', 'hello-plus' ), + 'type' => Controls_Manager::HEADING, ] ); - // Hide On Desktop control - $this->add_control( - 'zigzag_hide_on_desktop', + $this->add_group_control( + Group_Control_Background::get_type(), [ - 'label' => esc_html__( 'Hide On Desktop', 'hello-plus' ), - 'type' => Controls_Manager::SWITCHER, - 'label_on' => esc_html__( 'Yes', 'hello-plus' ), - 'label_off' => esc_html__( 'No', 'hello-plus' ), - 'return_value' => 'yes', - 'default' => 'no', - ] - ); + 'name' => 'background', + 'types' => [ 'classic', 'gradient' ], + 'exclude' => [ 'image' ], + 'selector' => '{{WRAPPER}} .e-zigzag__item-wrapper', - // Hide On Tablet control - $this->add_control( - 'zigzag_hide_on_tablet', - [ - 'label' => esc_html__( 'Hide On Tablet', 'hello-plus' ), - 'type' => Controls_Manager::SWITCHER, - 'label_on' => esc_html__( 'Yes', 'hello-plus' ), - 'label_off' => esc_html__( 'No', 'hello-plus' ), - 'return_value' => 'yes', - 'default' => 'no', ] ); - // Hide On Mobile control $this->add_control( - 'zigzag_hide_on_mobile', + 'show_alternate_background', [ - 'label' => esc_html__( 'Hide On Mobile', 'hello-plus' ), + 'label' => esc_html__( 'Alternate Background', 'hello-plus' ), 'type' => Controls_Manager::SWITCHER, 'label_on' => esc_html__( 'Yes', 'hello-plus' ), 'label_off' => esc_html__( 'No', 'hello-plus' ), @@ -1277,361 +888,19 @@ private function add_advanced_responsive_section() { ] ); - $this->end_controls_section(); - } - - private function add_custom_section( ) { - $this->start_controls_section( - 'Custom_section', - [ - 'label' => esc_html__( 'Custom', 'hello-plus' ), - 'tab' => \Elementor\Controls_Manager::TAB_ADVANCED, - ] - ); - - //CSS ID control - $this->add_control( - 'css_id', - [ - 'label' => esc_html__( 'CSS ID', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::TEXT, - 'dynamic' => [ - 'active' => true, - ], - 'default' => '', - 'title' => esc_html__( 'Add your custom ID without the "#" prefix.', 'hello-plus' ), - 'separator' => 'before', - ] - ); - - // CSS Classes control - $this->add_control( - 'css_classes', - [ - 'label' => esc_html__( 'CSS Classes', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::TEXT, - 'dynamic' => [ - 'active' => true, - ], - 'prefix_class' => '', - 'title' => esc_html__( 'Add your custom class without the dot. e.g: my-class', 'hello-plus' ), - ] - ); - - // Custom CSS control - $this->add_control( - 'custom_css', - [ - 'label' => esc_html__( 'Custom CSS', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::CODE, - 'language' => 'css', - 'rows' => 20, - 'separator' => 'before', - ] - ); - - // Custom Attributes control - $this->add_control( - 'zigzag_custom_attributes', + $this->add_group_control( + Group_Control_Background::get_type(), [ - 'label' => esc_html__( 'Custom Attributes', 'hello-plus' ), - 'type' => \Elementor\Controls_Manager::TEXTAREA, - 'dynamic' => [ - 'active' => true, + 'name' => 'alternate_background', + 'types' => [ 'classic', 'gradient' ], + 'exclude' => [ 'image' ], + 'condition' => [ + 'show_alternate_background' => 'yes', ], - 'placeholder' => esc_html__( 'key|value', 'hello-plus' ), - 'description' => esc_html__( 'Set custom attributes for the wrapper element. Each attribute in a separate line. Separate attribute key from the value using | character.', 'hello-plus' ), - 'separator' => 'before', + 'selector' => '{{WRAPPER}} .e-zigzag__item-wrapper:nth-child(even)', ] ); $this->end_controls_section(); } - - /** - * Render zigzag widget output on the frontend. - * - * Written in PHP and used to generate the final HTML. - * - * @since 1.0.0 - * @access protected - */ - public function render() { - $settings = $this->get_settings_for_display(); - -/* // Custom Attributes - $custom_attributes = $settings['zigzag_custom_attributes']; - $custom_attribute_string = ''; - if (!empty($custom_attributes)) { - $custom_attributes = explode("\n", $custom_attributes); - $custom_attributes = array_filter($custom_attributes); - foreach ($custom_attributes as $attribute) { - if (strpos($attribute, '|') !== false) { - list($key, $value) = explode('|', $attribute); - $custom_attribute_string .= ' ' . $key . '="' . esc_attr($value) . '"'; - } - } - } -*/ - $wrapper_classes = 'zigzag-widget-container'; -/* - if ( 'yes' === $settings['zigzag_hide_on_desktop'] ) { - $wrapper_classes .= ' elementor-hidden-desktop'; - } - - if ('yes' === $settings['zigzag_hide_on_tablet']) { - $wrapper_classes .= ' elementor-hidden-tablet'; - } - - if ('yes' === $settings['zigzag_hide_on_mobile']) { - $wrapper_classes .= ' elementor-hidden-mobile'; - } -*/ - $animation_styles = ''; - if ( ! empty( $settings['zigzag_entrance_animation'] ) ) { - $wrapper_classes .= ' animated ' . esc_attr( $settings['zigzag_entrance_animation'] ); - - $animation_duration_map = [ - 'slow' => 2000, - 'normal' => 1000, - 'fast' => 500, - ]; - - $animation_duration_setting = $settings['zigzag_animation_duration']; - - if ( is_numeric( $animation_duration_setting ) ) { - if ( $animation_duration_setting <= 500 ) { - $animation_duration_setting = 'fast'; - } elseif ( $animation_duration_setting <= 1000 ) { - $animation_duration_setting = 'normal'; - } else { - $animation_duration_setting = 'slow'; - } - } - - $animation_duration = $animation_duration_map[ $animation_duration_setting ] ?? $animation_duration_map['normal']; - $animation_delay = isset( $settings['zigzag_animation_delay'] ) ? intval( $settings['zigzag_animation_delay'] ) : 0; - - $animation_styles = sprintf( ' style="animation-duration: %dms; animation-delay: %dms;"', $animation_duration, $animation_delay ); - } - - // Open main widget container - echo '
'; - - $first_block_direction = $settings['first_block_direction']; - // Start the loop for the block items - foreach ( $settings['block_items'] as $index => $item ) { - // Determine if the item is odd or even - $is_odd = 0 !== $index % 2; - - // Add a prefix to the CSS class of the item - $item_class = $first_block_direction . ( $is_odd ? '-odd' : '-even' ); - - // Start block item container - echo '
'; - $this->render_graphic_element_container( $item, $settings ); - $this->render_text_element_container( $item, $settings ); - echo '
'; - } - // Close main widget container - echo '
'; - } - - /** - * Render zigzag widget output in the editor. - * - * Written as a Backbone JavaScript template and used to generate the live preview. - * - * @since 1.0.0 - * @access protected - */ - public function _content_template() { - ?> - <# - var custom_attributes = settings.zigzag_custom_attributes; - var custom_attribute_string = ''; - if (custom_attributes) { - var attributes = custom_attributes.split("\n"); - _.each(attributes, function(attribute) { - if (attribute.includes('|')) { - var parts = attribute.split('|'); - custom_attribute_string += ' ' + parts[0] + '="' + parts[1] + '"'; - } - }); - } - - var wrapper_classes = 'zigzag-widget-container'; - if ('yes' === settings.zigzag_hide_on_desktop) { - wrapper_classes += ' elementor-hidden-desktop'; - } - if ('yes' === settings.zigzag_hide_on_tablet) { - wrapper_classes += ' elementor-hidden-tablet'; - } - if ('yes' === settings.zigzag_hide_on_mobile) { - wrapper_classes += ' elementor-hidden-mobile'; - } - - var animation_styles = ''; - if (settings.zigzag_entrance_animation) { - wrapper_classes += ' animated ' + settings.zigzag_entrance_animation; - - var animation_duration_map = { - 'slow': 2000, - 'normal': 1000, - 'fast': 500, - }; - - var animation_duration_setting = settings.zigzag_animation_duration; - if (_.isNumber(animation_duration_setting)) { - if (animation_duration_setting <= 500) { - animation_duration_setting = 'fast'; - } else if (animation_duration_setting <= 1000) { - animation_duration_setting = 'normal'; - } else { - animation_duration_setting = 'slow'; - } - } - - var animation_duration = animation_duration_map[animation_duration_setting] || animation_duration_map['normal']; - var animation_delay = settings.zigzag_animation_delay; - - animation_styles = ' style="'; - animation_styles += 'animation-duration: ' + animation_duration + 'ms;'; - animation_styles += 'animation-delay: ' + animation_delay + 'ms;'; - animation_styles += '"'; - } - #> -
- <# - var first_block_direction = settings.first_block_direction; - _.each(settings.block_items, function(item, index) { - var is_odd = index % 2 == 0; - var item_class = first_block_direction + (is_odd ? '-odd' : '-even'); - #> -
-
-
- <# if (item.graphic_element === 'image' && item.graphic_image && item.graphic_image.url) { #> - {{{ item.graphic_image.alt }}} - <# } else if (item.graphic_element === 'icon' && item.graphic_icon && item.graphic_icon.value) { #> -
- -
- <# } else { #> - - <# } #> -
-
- -
- <# }); #> -
- '; - - // Start of the image container - echo '
'; - - // Graphic Element - if ( 'image' === $item['graphic_element'] && ! empty( $item['graphic_image']['url'] ) ) { - // Output the image - $this->add_render_attribute( 'image', 'src', $item['graphic_image']['url'] ); - $this->add_render_attribute( 'image', 'alt', \Elementor\Control_Media::get_image_alt( $item['graphic_image'] ) ); - $this->add_render_attribute( 'image', 'title', \Elementor\Control_Media::get_image_title( $item['graphic_image'] ) ); -// $this->add_render_attribute( 'image', 'class', 'my-custom-class' ); - echo \Elementor\Group_Control_Image_Size::get_attachment_image_html( [ 'image' => $item['graphic_image'] ], 'thumbnail', 'image' ); - } elseif ( 'icon' === $item['graphic_element'] && !empty( $item['graphic_icon']['value'] ) ) { - // Output the icon - echo '
'; - \Elementor\Icons_Manager::render_icon( $item['graphic_icon'], [ 'aria-hidden' => 'true' ] ); - echo '
'; - - } else { - // Output a default image - echo ''; - } - - // End of the image container - echo '
'; - - // End graphic element container - echo ''; - - } - - private function render_text_element_container( $item, $settings ) { - // Start text and button container - echo '
'; - - // Title - echo '

' . esc_html( $item['title'] ) . '

'; - - // Description - echo '

' . esc_html( $item['description'] ) . '

'; - - - // Get the button text, link, and icon from the item - $button_text = $item['button_text'] ?? 'Lean More'; - $button_link = $item['button_link']['url'] ?? '#'; - $button_icon = $item['button_icon'] ?? ''; - $icon_color = $item['icon_color'] ?? ''; // Default to black if no color is selected - - // Get the hover animation for the button - $button_hover_animation = $settings['button_hover_animation'] ?? ''; - - if ( ! empty( $button_text ) ) : - $btn_hover_animation_class = $button_hover_animation ? 'elementor-animation-' . $button_hover_animation : ''; - ?> - - - -
- 'install-elementor', - 'url' => wp_nonce_url( - add_query_arg( - [ - 'action' => 'install-plugin', - 'plugin' => 'elementor', - ], - admin_url( 'update.php' ) - ), - 'install-plugin_elementor' - ), - ]; - } - - if ( ! defined( 'ELEMENTOR_VERSION' ) ) { - $action_links_data[] = [ - 'type' => 'activate-elementor', - 'url' => wp_nonce_url( 'plugins.php?action=activate&plugin=elementor/elementor.php', 'activate-plugin_elementor/elementor.php' ), - ]; - } - - if ( ! defined( 'ELEMENTOR_PRO_VERSION' ) ) { - $action_links_data[] = [ - 'type' => 'go-pro', - 'url' => 'https://elementor.com/pricing-plugin', - ]; - } - - if ( ! defined( 'ELEMENTOR_AI_VERSION' ) ) { - $action_links_data[] = [ - 'type' => 'go-ai', - 'url' => 'https://elementor.com/pricing-ai', - ]; - } - - if ( ! defined( 'ELEMENTOR_IMAGE_OPTIMIZER_VERSION' ) ) { - $action_links_data[] = [ - 'type' => 'go-image-optimizer', - 'url' => 'https://elementor.com/pricing-plugin', - ]; - } - - wp_localize_script( - $handle, - 'helloPlusAdminData', - [ - 'links' => $action_links_data, - 'templateDirectoryURI' => HELLO_PLUS_URL, - ] - ); - } - - /** - * Render settings page wrapper element. - */ - public static function settings_page_render() { - ?> -
- '_description_meta_tag', - 'SKIP_LINK' => '_skip_link', - 'HEADER_FOOTER' => '_header_footer', - 'PAGE_TITLE' => '_page_title', - 'HELLO_PLUS_STYLE' => '_hello_plus_style', - 'HELLO_PLUS_THEME' => '_hello_plus_theme', - ]; - - /** - * allow child theme and 3rd party plugins to extend the Theme settings - * - * @param array $settings , the filtered value, array of key/value settings options pairs - */ - $settings = apply_filters( 'hello-plus/settings', $settings ); - - $this->register_settings( self::SETTINGS_GROUP, $settings ); - $this->render_tweaks( self::SETTINGS_GROUP, $settings ); - } - - /** - * Register theme settings. - */ - public function register_settings( $settings_group, $settings ) { - - foreach ( $settings as $setting_key => $setting_value ) { - register_setting( - $settings_group, - $settings_group . $setting_value, - [ - 'default' => '', - 'show_in_rest' => true, - 'type' => 'string', - ] - ); - } - - } - - /** - * Run a tweak only if the user requested it. - */ - private function do_tweak( $setting, $tweak_callback ) { - - $option = get_option( $setting ); - if ( isset( $option ) && ( 'true' === $option ) && is_callable( $tweak_callback ) ) { - $tweak_callback(); - } - - } - - /** - * @return array - */ - private function get_default_action_tweaks(): array { - $tweaks = [ - 'DESCRIPTION_META_TAG' => [ - 'hook' => 'wp_head', - 'callback' => [ - 'HelloPlus\Modules\Theme\Module', - 'add_description_meta_tag' - ], - ], - ]; - - /** - * Allow child theme and 3rd party plugins to extend the list of tweaks controlled by the Theme settings - */ - return apply_filters( 'hello-plus/settings/tweaks-list/actions', $tweaks ); - } - - /** - * @return array - */ - private function get_default_filter_tweaks(): array { - $tweaks = [ - 'SKIP_LINK' => [ - 'hook' => 'hello_plus_enable_skip_link', - 'callback' => '__return_false', - ], - 'HEADER_FOOTER' => [ - 'hook' => 'hello_plus_header_footer', - 'callback' => '__return_false', - ], - 'PAGE_TITLE' => [ - 'hook' => 'hello_plus_page_title', - 'callback' => '__return_false', - ], - 'HELLO_PLUS_THEME' => [ - 'hook' => 'hello_plus_enqueue_theme_style', - 'callback' => '__return_false', - ] - ]; - - /** - * Allow child theme and 3rd party plugins to extend the list of tweaks controlled by the Theme settings - */ - return apply_filters( 'hello-plus/settings/tweaks-list/filters', $tweaks ); - } - /** - * Render theme tweaks. - */ - public function render_tweaks( $settings_group, $settings ) { - - $tweaks = $this->get_default_action_tweaks(); - - foreach ( $tweaks as $tweak_key => $tweak_value ) { - $this->do_tweak( $settings_group . $settings[ $tweak_key ], function () use ( $tweak_value ) { - remove_action( $tweak_value[ 'hook' ], $tweak_value[ 'callback' ] ); - } ); - } - - $tweaks = $this->get_default_filter_tweaks(); - - foreach ( $tweaks as $tweak_key => $tweak_value ) { - $this->do_tweak( $settings_group . $settings[ $tweak_key ], function () use ( $tweak_value ) { - add_filter( $tweak_value[ 'hook' ], $tweak_value[ 'callback' ] ); - } ); - } - } - - /** - * class constructor - */ - public function __construct( ) { - add_action( 'admin_menu', [ $this, 'settings_page' ] ); - add_action( 'init', [ $this, 'tweak_settings' ], 0 ); - } -} diff --git a/modules/settings/module.php b/modules/settings/module.php deleted file mode 100644 index ec4a78e8..00000000 --- a/modules/settings/module.php +++ /dev/null @@ -1,35 +0,0 @@ -add_category( self::HELLO_PLUS_EDITOR_CATEGORY_SLUG, [ - 'title' => esc_html__('Hello+', 'hello-plus'), + 'title' => esc_html__( 'Hello+', 'hello-plus' ), 'icon' => 'fa fa-plug', ] ); diff --git a/package-lock.json b/package-lock.json index 6ea2f8a4..78b04faf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "react-dom": "^18.3.1" }, "devDependencies": { + "@elementor/eslint-plugin": "^1.0.0", "@wordpress/scripts": "^27.1.0", "eslint-plugin-babel": "^5.3.1", "eslint-plugin-no-jquery": "^3.0.2", @@ -2054,6 +2055,15 @@ "node": ">=10.0.0" } }, + "node_modules/@elementor/eslint-plugin": { + "version": "1.0.0", + "resolved": "https://npm.pkg.github.com/download/@elementor/eslint-plugin/1.0.0/fcabef597a471720551e8daa780a26986c519c17", + "integrity": "sha512-Iu9lxdsqHgreHUv4DWT/GILm2WMn28CzRc4sQK8oON/1oATkga1BWqrDKJJftN1qe1pLx4zi5VkB2/KvnA2Mqw==", + "dev": true, + "dependencies": { + "tslib": "^2.3.0" + } + }, "node_modules/@elementor/icons": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@elementor/icons/-/icons-1.11.0.tgz", diff --git a/package.json b/package.json index 73e0ea0e..00b027dd 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "eslint-plugin-react": "^7.35.2", "path": "^0.12.7", "webpack-cli": "^5.1.4", - "webpack-remove-empty-scripts": "^1.0.4" + "webpack-remove-empty-scripts": "^1.0.4", + "@elementor/eslint-plugin": "^1.0.0" }, "dependencies": { "@elementor/icons": "^1.11.0", diff --git a/phpcs.xml b/phpcs.xml index 9b35bf5d..4467dc9a 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,6 +1,6 @@ - Hello Plus Theme Coding Standard + Elementor Coding Standards @@ -10,6 +10,15 @@ build/ node_modules/ tests/*.php + *.js + *.css + *.scss + + + + + + @@ -27,8 +36,6 @@ - - @@ -38,12 +45,6 @@ - - - - - - diff --git a/screenshot.png b/screenshot.png index 5ca322a2..bd8850cb 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/style.css b/style.css index 9767325f..eb28c8ad 100644 --- a/style.css +++ b/style.css @@ -1 +1,16 @@ -/* Theme Name: Hello Plus Theme URI: https://elementor.com/hello-plus/?utm_source=wp-themes&utm_campaign=theme-uri&utm_medium=wp-dash Description: Hello Plus is a minimalist WordPress theme designed to get your site up & running in a few quick clicks. The theme is free, open-source, and designed for users who want a flexible, easy-to-use, and customizable website. The theme, which is optimized for performance, provides a solid foundation for users to build their own unique designs using the Elementor drag-and-drop site builder. Author: Elementor Team Author URI: https://elementor.com/?utm_source=wp-themes&utm_campaign=author-uri&utm_medium=wp-dash Version: 0.0.1 Stable tag: 0.0.1 Requires at least: 6.0 Tested up to: 6.5 Requires PHP: 7.4 License: GNU General Public License v3 or later. License URI: https://www.gnu.org/licenses/gpl-3.0.html Text Domain: hello-plus Tags: accessibility-ready, flexible-header, custom-colors, custom-menu, custom-logo, featured-images, rtl-language-support, threaded-comments, translation-ready, */ \ No newline at end of file +/* + Theme Name: Hello Plus + Theme URI: https://elementor.com/hello-plus/?utm_source=wp-themes&utm_campaign=theme-uri&utm_medium=wp-dash + Description: Hello Plus is a minimalist WordPress theme designed to get your site up & running in a few quick clicks. The theme is free, open-source, and designed for users who want a flexible, easy-to-use, and customizable website. The theme, which is optimized for performance, provides a solid foundation for users to build their own unique designs using the Elementor drag-and-drop site builder. + Author: Elementor Team + Author URI: https://elementor.com/?utm_source=wp-themes&utm_campaign=author-uri&utm_medium=wp-dash + Version: 0.0.1 + Stable tag: 0.0.1 + Requires at least: 6.0 + Tested up to: 6.5 + Requires PHP: 7.4 + License: GNU General Public License v3 or later. + License URI: https://www.gnu.org/licenses/gpl-3.0.html + Text Domain: hello-plus + Tags: accessibility-ready, flexible-header, custom-colors, custom-menu, custom-logo, featured-images, rtl-language-support, threaded-comments, translation-ready, +*/ diff --git a/theme.php b/theme.php index 361d6fc5..b653a163 100644 --- a/theme.php +++ b/theme.php @@ -18,7 +18,7 @@ final class Theme { /** * @var ?Theme */ - private static ?Theme $_instance = null; + private static ?Theme $instance = null; /** * @var Module_Base[] @@ -83,23 +83,23 @@ public static function get_min_suffix(): string { } /** - * @param $class + * @param $class_name * * @return void */ - public function autoload( $class ) { - if ( 0 !== strpos( $class, __NAMESPACE__ ) ) { + public function autoload( $class_name ) { + if ( 0 !== strpos( $class_name, __NAMESPACE__ ) ) { return; } - $has_class_alias = isset( $this->classes_aliases[ $class ] ); + $has_class_alias = isset( $this->classes_aliases[ $class_name ] ); // Backward Compatibility: Save old class name for set an alias after the new class is loaded if ( $has_class_alias ) { - $class_alias_name = $this->classes_aliases[ $class ]; + $class_alias_name = $this->classes_aliases[ $class_name ]; $class_to_load = $class_alias_name; } else { - $class_to_load = $class; + $class_to_load = $class_name; } if ( ! class_exists( $class_to_load ) ) { @@ -113,12 +113,12 @@ public function autoload( $class ) { $filename = trailingslashit( HELLO_PLUS_PATH ) . $filename . '.php'; if ( is_readable( $filename ) ) { - include( $filename ); + include $filename; } } if ( $has_class_alias ) { - class_alias( $class_alias_name, $class ); + class_alias( $class_alias_name, $class_name ); } } @@ -128,11 +128,11 @@ class_alias( $class_alias_name, $class ); * @return Theme */ public static function instance(): Theme { - if ( is_null( self::$_instance ) ) { - self::$_instance = new self(); + if ( is_null( self::$instance ) ) { + self::$instance = new self(); } - return self::$_instance; + return self::$instance; } /** @@ -171,7 +171,6 @@ private function init_modules() { $modules_list = [ 'Theme', 'Customizer', - 'Settings', 'Admin', 'Content', ]; @@ -179,7 +178,7 @@ private function init_modules() { foreach ( $modules_list as $module_name ) { $class_name = str_replace( '-', ' ', $module_name ); $class_name = str_replace( ' ', '', ucwords( $class_name ) ); - $class_name = __NAMESPACE__ . '\\Modules\\' . $class_name . '\Module'; + $class_name = __NAMESPACE__ . '\\Modules\\' . $class_name . '\Module'; /** @var Module_Base $class_name */ if ( $class_name::is_active() && empty( $this->classes_aliases[ $module_name ] ) ) {