├── assets
├── images
│ ├── logo.png
│ ├── star.png
│ ├── logo-alt.png
│ ├── neve-logo.png
│ ├── placeholder.jpg
│ ├── count-animation.png
│ ├── neve-upsell-img.png
│ ├── guide
│ │ ├── welcome-ai.png
│ │ ├── welcome-css.png
│ │ ├── welcome-pro.png
│ │ ├── welcome-finish.png
│ │ ├── welcome-logo.png
│ │ └── welcome-section.png
│ ├── typing-animation.png
│ ├── black-friday-banner.png
│ ├── dashboard-feedback.png
│ └── live-search-thumbnail.png
├── icons
│ ├── map-dark.png
│ ├── map-night.png
│ ├── map-retro.png
│ ├── map-silver.png
│ ├── map-aubergine.png
│ ├── map-standard.png
│ ├── featured.svg
│ ├── acf.svg
│ ├── meta.svg
│ ├── author.svg
│ ├── user.svg
│ └── woo.svg
├── leaflet
│ ├── images
│ │ ├── layers.png
│ │ ├── layers-2x.png
│ │ ├── marker-icon.png
│ │ ├── marker-icon-2x.png
│ │ └── marker-shadow.png
│ └── leaflet-gesture-handling.min.css
├── fontawesome
│ ├── webfonts
│ │ ├── fa-brands-400.eot
│ │ ├── fa-brands-400.ttf
│ │ ├── fa-solid-900.eot
│ │ ├── fa-solid-900.ttf
│ │ ├── fa-solid-900.woff
│ │ ├── fa-brands-400.woff
│ │ ├── fa-brands-400.woff2
│ │ ├── fa-regular-400.eot
│ │ ├── fa-regular-400.ttf
│ │ ├── fa-regular-400.woff
│ │ ├── fa-regular-400.woff2
│ │ └── fa-solid-900.woff2
│ └── LICENSE.txt
└── glide
│ ├── glide.core.min.css
│ └── glide.theme.min.css
├── .browserslistrc
├── docs
├── blocks
│ ├── images
│ │ ├── save-code.png
│ │ ├── save-error.png
│ │ ├── save-backend.png
│ │ ├── save-frontend.png
│ │ ├── save-error-inspector.png
│ │ ├── simple-block-react.png
│ │ ├── styled-simple-react.png
│ │ └── dynamic-simple-block-react.png
│ ├── index.md
│ └── deprecation.md
├── images
│ ├── copy-paste-flow.png
│ ├── sticky-triggers-1.png
│ ├── template-library.png
│ ├── copy-paste-local-storage.png
│ └── local-by-flywheel-overview.png
├── knowledge-stash.md
├── index.md
├── adding-patterns.md
├── blocks.md
├── uniit-and-e2e-testing.md
├── otter-family-plugins.md
├── woocommerce-extensions.md
├── live-search.md
├── form-block-workflow.md
└── project-structure.md
├── plugins
├── blocks-animation
│ ├── assets
│ │ └── images
│ │ │ └── welcome-notice.png
│ ├── readme.txt
│ ├── readme.md
│ └── blocks-animation.php
├── otter-pro
│ └── inc
│ │ ├── css
│ │ └── blocks
│ │ │ ├── class-modal-css.php
│ │ │ ├── class-form-file-css.php
│ │ │ ├── class-review-comparison-css.php
│ │ │ ├── class-business-hours-item-css.php
│ │ │ ├── class-form-stripe-field-css.php
│ │ │ └── class-business-hours-css.php
│ │ ├── render
│ │ ├── woocommerce
│ │ │ ├── tpl
│ │ │ │ └── content-single-product.php
│ │ │ ├── class-product-meta-block.php
│ │ │ ├── class-product-price-block.php
│ │ │ ├── class-product-title-block.php
│ │ │ ├── class-product-upsells-block.php
│ │ │ ├── class-product-add-to-cart-block.php
│ │ │ ├── class-product-short-description-block.php
│ │ │ ├── class-product-related-products-block.php
│ │ │ ├── class-product-stock-block.php
│ │ │ ├── class-product-rating-block.php
│ │ │ ├── class-product-tabs-block.php
│ │ │ └── class-product-images-block.php
│ │ ├── class-add-to-cart-button-block.php
│ │ ├── class-form-hidden-block.php
│ │ ├── class-form-file-block.php
│ │ └── class-form-stripe-block.php
│ │ ├── plugins
│ │ ├── class-options-settings.php
│ │ ├── class-stripe-pro-features.php
│ │ ├── class-review-woo-integration.php
│ │ ├── class-posts-acf-integration.php
│ │ └── class-fonts-module.php
│ │ └── server
│ │ └── class-posts-acf-server.php
├── blocks-css
│ ├── readme.txt
│ ├── readme.md
│ └── blocks-css.php
└── blocks-export-import
│ ├── readme.txt
│ ├── blocks-export-import.php
│ └── readme.md
├── .editorconfig
├── inc
├── render
│ ├── class-form-nonce-block.php
│ ├── class-about-author-block.php
│ ├── class-leaflet-map-block.php
│ ├── class-google-map-block.php
│ ├── amp
│ │ ├── class-slider-block.php
│ │ └── class-lottie.block.php
│ └── class-masonry-variant.php
├── css
│ └── blocks
│ │ ├── class-form-multiple-choice-css.php
│ │ ├── class-form-textarea-css.php
│ │ ├── class-icon-list-item-css.php
│ │ ├── class-form-input-css.php
│ │ ├── class-google-map-css.php
│ │ ├── class-leaflet-map-css.php
│ │ ├── class-timeline-item-css.php
│ │ ├── class-sharing-icons-css.php
│ │ ├── class-slider-css.php
│ │ ├── class-core-image-plugin-css.php
│ │ ├── class-progress-bar-css.php
│ │ └── class-timeline-css.php
├── integrations
│ └── interfaces
│ │ └── interface-form-subscribe-service.php
├── Tracker.php
├── class-blocks-export-import.php
├── patterns
│ ├── large-quote.php
│ ├── call-to-action-1.php
│ ├── hero-area-with-button.php
│ ├── call-to-action-5.php
│ ├── call-to-action-4.php
│ ├── testimonial-with-inline-image.php
│ ├── call-to-action-3.php
│ └── image-and-text-over-dark-background.php
└── server
│ └── class-fse-onboarding-server.php
├── phpcs.xml.dist
├── phpstan.neon
├── tsconfig.json
├── .wp-env.override.json
├── development.php
├── CONTRIBUTING.md
├── webpack.config.pro.js
└── webpack.config.plugins.js
/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/logo.png
--------------------------------------------------------------------------------
/assets/images/star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/star.png
--------------------------------------------------------------------------------
/assets/icons/map-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/icons/map-dark.png
--------------------------------------------------------------------------------
/assets/icons/map-night.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/icons/map-night.png
--------------------------------------------------------------------------------
/assets/icons/map-retro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/icons/map-retro.png
--------------------------------------------------------------------------------
/assets/icons/map-silver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/icons/map-silver.png
--------------------------------------------------------------------------------
/assets/images/logo-alt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/logo-alt.png
--------------------------------------------------------------------------------
/assets/images/neve-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/neve-logo.png
--------------------------------------------------------------------------------
/assets/icons/map-aubergine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/icons/map-aubergine.png
--------------------------------------------------------------------------------
/assets/icons/map-standard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/icons/map-standard.png
--------------------------------------------------------------------------------
/assets/images/placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/placeholder.jpg
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | # Browsers that we support
2 |
3 | last 1 version
4 | > 1%
5 | not ie > 0
6 | not ie_mob > 0
7 | not dead
--------------------------------------------------------------------------------
/assets/images/count-animation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/count-animation.png
--------------------------------------------------------------------------------
/assets/images/neve-upsell-img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/neve-upsell-img.png
--------------------------------------------------------------------------------
/assets/leaflet/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/leaflet/images/layers.png
--------------------------------------------------------------------------------
/docs/blocks/images/save-code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/blocks/images/save-code.png
--------------------------------------------------------------------------------
/docs/blocks/images/save-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/blocks/images/save-error.png
--------------------------------------------------------------------------------
/docs/images/copy-paste-flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/images/copy-paste-flow.png
--------------------------------------------------------------------------------
/docs/images/sticky-triggers-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/images/sticky-triggers-1.png
--------------------------------------------------------------------------------
/docs/images/template-library.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/images/template-library.png
--------------------------------------------------------------------------------
/assets/images/guide/welcome-ai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/guide/welcome-ai.png
--------------------------------------------------------------------------------
/assets/images/guide/welcome-css.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/guide/welcome-css.png
--------------------------------------------------------------------------------
/assets/images/guide/welcome-pro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/guide/welcome-pro.png
--------------------------------------------------------------------------------
/assets/images/typing-animation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/typing-animation.png
--------------------------------------------------------------------------------
/assets/leaflet/images/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/leaflet/images/layers-2x.png
--------------------------------------------------------------------------------
/docs/blocks/images/save-backend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/blocks/images/save-backend.png
--------------------------------------------------------------------------------
/assets/images/black-friday-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/black-friday-banner.png
--------------------------------------------------------------------------------
/assets/images/dashboard-feedback.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/dashboard-feedback.png
--------------------------------------------------------------------------------
/assets/images/guide/welcome-finish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/guide/welcome-finish.png
--------------------------------------------------------------------------------
/assets/images/guide/welcome-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/guide/welcome-logo.png
--------------------------------------------------------------------------------
/assets/leaflet/images/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/leaflet/images/marker-icon.png
--------------------------------------------------------------------------------
/docs/blocks/images/save-frontend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/blocks/images/save-frontend.png
--------------------------------------------------------------------------------
/assets/images/guide/welcome-section.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/guide/welcome-section.png
--------------------------------------------------------------------------------
/assets/images/live-search-thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/images/live-search-thumbnail.png
--------------------------------------------------------------------------------
/assets/leaflet/images/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/leaflet/images/marker-icon-2x.png
--------------------------------------------------------------------------------
/assets/leaflet/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/leaflet/images/marker-shadow.png
--------------------------------------------------------------------------------
/docs/images/copy-paste-local-storage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/images/copy-paste-local-storage.png
--------------------------------------------------------------------------------
/docs/blocks/images/save-error-inspector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/blocks/images/save-error-inspector.png
--------------------------------------------------------------------------------
/docs/blocks/images/simple-block-react.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/blocks/images/simple-block-react.png
--------------------------------------------------------------------------------
/docs/blocks/images/styled-simple-react.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/blocks/images/styled-simple-react.png
--------------------------------------------------------------------------------
/docs/images/local-by-flywheel-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/images/local-by-flywheel-overview.png
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-brands-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-brands-400.eot
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-brands-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-brands-400.ttf
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-solid-900.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-solid-900.eot
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-solid-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-solid-900.woff
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-brands-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-brands-400.woff
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-brands-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-brands-400.woff2
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-regular-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-regular-400.eot
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-regular-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-regular-400.woff
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-regular-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-regular-400.woff2
--------------------------------------------------------------------------------
/assets/fontawesome/webfonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/assets/fontawesome/webfonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/docs/blocks/images/dynamic-simple-block-react.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/docs/blocks/images/dynamic-simple-block-react.png
--------------------------------------------------------------------------------
/plugins/blocks-animation/assets/images/welcome-notice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeinwp/otter-blocks/HEAD/plugins/blocks-animation/assets/images/welcome-notice.png
--------------------------------------------------------------------------------
/docs/blocks/index.md:
--------------------------------------------------------------------------------
1 | ## Creating Blocks for Otter in Gutenberg
2 |
3 | ### Chapters
4 | - [Your first block](first-block.md)
5 | - [Editor - attributes & edit function](editor.md)
6 | - [Style your block](styling.md)
7 | - [Save](save.md)
8 | - [Style with PHP](style-with-php.md)
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | [*]
7 | indent_style = tab
8 | indent_size = 4
9 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = true
12 | insert_final_newline = true
13 |
14 | [*.yml]
15 | indent_style = space
16 | indent_size = 2
17 |
18 | [*.md]
19 | trim_trailing_whitespace = false
20 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/css/blocks/class-modal-css.php:
--------------------------------------------------------------------------------
1 | A collection of useful information that helps with the knowledge necessary to work with the project.
4 |
5 | | Link | Description |
6 | | :- | :- |
7 | | [WordPress Data Series: Overview and Introduction](https://unfoldingneurons.com/2020/wordpress-data-series-overview-and-introduction) | Great series on exploring Gutenberg data store|
8 | | [4 reasons your z-index isn’t working (and how to fix it)](https://www.freecodecamp.org/news/4-reasons-your-z-index-isnt-working-and-how-to-fix-it-coder-coder-6bc05f103e6c/) | A page which explain some quirk for `z-index` property. `z-index` does not always work on how you expect. When fixing issue related to Modal component, keep in mind the context of `z-index`. |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/render/woocommerce/tpl/content-single-product.php:
--------------------------------------------------------------------------------
1 |
20 |
>
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/assets/glide/glide.core.min.css:
--------------------------------------------------------------------------------
1 | .glide{position:relative;width:100%;box-sizing:border-box}.glide *{box-sizing:inherit}.glide__track{overflow:hidden}.glide__slides{position:relative;width:100%;list-style:none;backface-visibility:hidden;transform-style:preserve-3d;touch-action:pan-Y;overflow:hidden;padding:0;white-space:nowrap;display:flex;flex-wrap:nowrap;will-change:transform}.glide__slides--dragging{user-select:none}.glide__slide{width:100%;height:100%;flex-shrink:0;white-space:normal;user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}.glide__slide a{user-select:none;-webkit-user-drag:none;-moz-user-select:none;-ms-user-select:none}.glide__arrows{-webkit-touch-callout:none;user-select:none}.glide__bullets{-webkit-touch-callout:none;user-select:none}.glide--rtl{direction:rtl}
2 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/render/woocommerce/class-product-meta-block.php:
--------------------------------------------------------------------------------
1 | ';
26 | if ( isset( $attributes['formId'] ) ) {
27 | $output .= wp_nonce_field( 'form-verification', $attributes['formId'] . '_nonce_field', true, false );
28 | } else {
29 | $output .= wp_nonce_field( 'form-verification', '_nonce_field', true, false );
30 | }
31 | $output .= ' ';
32 | $output .= '';
33 | return $output;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/plugins/blocks-css/readme.txt:
--------------------------------------------------------------------------------
1 | === Blocks CSS: CSS Editor for Gutenberg Blocks ===
2 | Contributors: themeisle, hardeepasrani
3 | Tags: gutenberg, block, css, css editor, blocks css
4 | Requires at least: 6.2
5 | Tested up to: 6.9
6 | Requires PHP: 5.4
7 | Stable tag: 3.1.4
8 | License: GPLv3
9 | License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
10 |
11 | Blocks CSS allows you add custom CSS to your Blocks straight from the Block Editor (Gutenberg).
12 |
13 | == Description ==
14 |
15 | Blocks CSS allows you add custom CSS to your Blocks straight from the Block Editor (Gutenberg).
16 |
17 | It adds a syntax-highlighted CSS Editor where you can add additional CSS to your Gutenberg Blocks to style them the way you want.
18 |
19 | All the code and sources for this plugin are publicly available as part of https://github.com/Codeinwp/otter-blocks.
20 |
21 | == Screenshots ==
22 |
23 | 1. CSS Editor
24 | 2. CSS Editor
25 |
26 | == Changelog ==
27 |
28 | You can check the changelog [here.](https://github.com/Codeinwp/otter-blocks/blob/master/CHANGELOG.md)
29 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/render/woocommerce/class-product-rating-block.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | ThemeIsle ruleset
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | vendor/*
28 | assets/*
29 | build/*
30 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/css/blocks/class-form-file-css.php:
--------------------------------------------------------------------------------
1 | add_item(
37 | array(
38 | 'properties' => array(
39 | array(
40 | 'property' => '--label-color',
41 | 'value' => 'labelColor',
42 | ),
43 | ),
44 | )
45 | );
46 |
47 | $style = $css->generate();
48 |
49 | return $style;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/render/woocommerce/class-product-tabs-block.php:
--------------------------------------------------------------------------------
1 | add_item(
37 | array(
38 | 'properties' => array(
39 | array(
40 | 'property' => '--label-color',
41 | 'value' => 'labelColor',
42 | ),
43 | ),
44 | )
45 | );
46 |
47 | $style = $css->generate();
48 |
49 | return $style;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/render/woocommerce/class-product-images-block.php:
--------------------------------------------------------------------------------
1 | add_item(
37 | array(
38 | 'properties' => array(
39 | array(
40 | 'property' => '--label-color',
41 | 'value' => 'labelColor',
42 | ),
43 | array(
44 | 'property' => '--input-width',
45 | 'value' => 'inputWidth',
46 | ),
47 | ),
48 | )
49 | );
50 |
51 | $style = $css->generate();
52 |
53 | return $style;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/inc/css/blocks/class-icon-list-item-css.php:
--------------------------------------------------------------------------------
1 | add_item(
38 | array(
39 | 'properties' => array(
40 | array(
41 | 'property' => '--content-color',
42 | 'value' => 'contentColor',
43 | ),
44 | array(
45 | 'property' => '--icon-color',
46 | 'value' => 'iconColor',
47 | ),
48 | ),
49 | )
50 | );
51 |
52 | $style = $css->generate();
53 |
54 | return $style;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/inc/css/blocks/class-form-input-css.php:
--------------------------------------------------------------------------------
1 | add_item(
37 | array(
38 | 'properties' => array(
39 | array(
40 | 'property' => '--label-color',
41 | 'value' => 'labelColor',
42 | ),
43 | array(
44 | 'property' => '--input-width',
45 | 'value' => 'inputWidth',
46 | 'unit' => '%',
47 | ),
48 | ),
49 | )
50 | );
51 |
52 | $style = $css->generate();
53 |
54 | return $style;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/assets/icons/featured.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Gutenberg Blocks
2 |
3 | Otter Blocks
4 | - [Environment installation](environment.md)
5 | - [Handbook](handbook.md)
6 | - [Otter Family Plugins](otter-family-plugins.md)
7 | - [Project Structure](project-structure.md)
8 | - [Creating a new block](creating-blocks.md)
9 | - [Dynamic CSS with PHP](dynamic-css-with-php.md)
10 | - [Adding Patterns](adding-patterns.md)
11 | - [Form Workflow](form-block-workflow.md)
12 | - [Dynamic Conditions and Content](dynamic-conditions-and-content.md)
13 | - [Sticky Block](sticky-blocks.md)
14 | - [Copy/Paste Block Style](copy-paste.md)
15 | - [WooCommerce Extensions](woocommerce-extensions.md)
16 | - [Live Search](live-search.md)
17 | - [Testing Cheatsheet](testing-cheatsheet.md)
18 | - [Testing Checklist](testing-checklist.md)
19 | - [Unit Testing & E2E](uniit-and-e2e-testing.md)
20 | - [Pull Request Best Practices](pull-request-best-practices.md)
21 | - [Coding Best Practices](coding-best-practices.md)
22 | - [Knowledge Stash](knowledge-stash.md)
23 |
24 | Other
25 |
26 | - [Creating Blocks for Gutenberg](blocks/index.md)
27 | - [Blocks Basics](blocks.md)
28 | - [Registration](blocks.md#registration)
29 | - [Server-side Rendering](blocks.md#server-side-rendering)
30 | - [Custom CSS & Google Fonts](blocks.md#custom-css--google-fonts)
31 |
--------------------------------------------------------------------------------
/assets/glide/glide.theme.min.css:
--------------------------------------------------------------------------------
1 | .glide__arrow{position:absolute;display:block;top:50%;z-index:2;color:white;text-transform:uppercase;padding:9px 12px;background-color:transparent;border:2px solid rgba(255,255,255,0.5);border-radius:4px;box-shadow:0 0.25em 0.5em 0 rgba(0,0,0,0.1);text-shadow:0 0.25em 0.5em rgba(0,0,0,0.1);opacity:1;cursor:pointer;transition:opacity 150ms ease, border 300ms ease-in-out;transform:translateY(-50%);line-height:1}.glide__arrow:focus{outline:none}.glide__arrow:hover{border-color:white}.glide__arrow--left{left:2em}.glide__arrow--right{right:2em}.glide__arrow--disabled{opacity:0.33}.glide__bullets{position:absolute;z-index:2;bottom:2em;left:50%;display:inline-flex;list-style:none;transform:translateX(-50%)}.glide__bullet{background-color:rgba(255,255,255,0.5);width:9px;height:9px;padding:0;border-radius:50%;border:2px solid transparent;transition:all 300ms ease-in-out;cursor:pointer;line-height:0;box-shadow:0 0.25em 0.5em 0 rgba(0,0,0,0.1);margin:0 0.25em}.glide__bullet:focus{outline:none}.glide__bullet:hover,.glide__bullet:focus{border:2px solid white;background-color:rgba(255,255,255,0.5)}.glide__bullet--active{background-color:white}.glide--swipeable{cursor:grab;cursor:-moz-grab;cursor:-webkit-grab}.glide--dragging{cursor:grabbing;cursor:-moz-grabbing;cursor:-webkit-grabbing}
2 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/css/blocks/class-review-comparison-css.php:
--------------------------------------------------------------------------------
1 | add_item(
38 | array(
39 | 'selector' => ' .o-review-comparison_buttons a',
40 | 'properties' => array(
41 | array(
42 | 'property' => 'color',
43 | 'value' => 'buttonText',
44 | ),
45 | array(
46 | 'property' => 'background-color',
47 | 'value' => 'buttonColor',
48 | ),
49 | ),
50 | )
51 | );
52 |
53 | $style = $css->generate();
54 |
55 | return $style;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 6
3 | paths:
4 | - %currentWorkingDirectory%/inc
5 | - %currentWorkingDirectory%/plugins/otter-pro
6 | - %currentWorkingDirectory%/plugins/blocks-css/blocks-css.php
7 | - %currentWorkingDirectory%/plugins/blocks-export-import/blocks-export-import.php
8 | - %currentWorkingDirectory%/plugins/blocks-animation/blocks-animation.php
9 | scanDirectories:
10 | - %currentWorkingDirectory%/vendor/stripe/stripe-php
11 | bootstrapFiles:
12 | - %currentWorkingDirectory%/vendor/php-stubs/wordpress-stubs/wordpress-stubs.php
13 | - %currentWorkingDirectory%/vendor/php-stubs/woocommerce-stubs/woocommerce-stubs.php
14 | - %currentWorkingDirectory%/vendor/php-stubs/acf-pro-stubs/acf-pro-stubs.php
15 | - %currentWorkingDirectory%/vendor/wptt/webfont-loader/wptt-webfont-loader.php
16 | - %currentWorkingDirectory%/tests/php/static-analysis-stubs/otter.php
17 | - %currentWorkingDirectory%/tests/php/static-analysis-stubs/learndash.php
18 | dynamicConstantNames:
19 | - COOKIEPATH
20 | - COOKIE_DOMAIN
21 | - OTTER_BLOCKS_PRO_SUPPORT
22 | - OTTER_BLOCKS_SHOW_NOTICES
23 | ignoreErrors:
24 | -
25 | identifiers:
26 | - include.fileNotFound
27 | - requireOnce.fileNotFound
28 | includes:
29 | - %currentWorkingDirectory%/vendor/szepeviktor/phpstan-wordpress/extension.neon
30 | - %currentWorkingDirectory%/phpstan-baseline.neon
31 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
4 | "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
5 | "allowJs": true /* Allow javascript files to be compiled. */,
6 | "checkJs": false /* Report errors in .js files. */,
7 | "outDir": "./build" /* Redirect output structure to the directory. */,
8 | "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
9 | "strict": true /* Enable all strict type-checking options. */,
10 | "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
11 | "resolveJsonModule": true,
12 | "jsx": "preserve",
13 | "noUncheckedIndexedAccess": true,
14 | "lib": [ "dom", "esnext" ],
15 | "moduleResolution": "node",
16 | "allowSyntheticDefaultImports": true,
17 | "esModuleInterop": false,
18 | "declaration": true,
19 | "declarationMap": true,
20 | "isolatedModules": true,
21 | "typeRoots": ["./node_modules/@types"]
22 | },
23 | "include": ["src/**/*" ],
24 | "exclude": [
25 | "node_modules/**/*",
26 | "build",
27 | "dist",
28 | "assets",
29 | "artifact"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/docs/adding-patterns.md:
--------------------------------------------------------------------------------
1 | # Patterns
2 |
3 | Patterns are big part of Gutenberg ecosystem. In the old days, plugin developer made their own mechanism to add them, but things are now more organized.
4 |
5 | Adding a new pattern for Otter is straight forward.
6 |
7 | - All the patterns are located in `./src/patterns` folder.
8 | - Every pattern is just an array with keys described by the [Gutenberg documentation](https://developer.wordpress.org/block-editor/developers/block-api/block-patterns/).
9 | - After creating a file for it, register it on `./inc/patterns.php` file in `$block_patterns` array.
10 |
11 | ## Mentions
12 |
13 | - The pattern name should be unique.
14 | - Do not use specific theme CSS vars as values for attributes. Like `"color": "var(--neve-custom-color)"`. This will make the pattern unusable on other themes. Patterns should be theme agnostic. Exceptions can be made, but only if it is intended.
15 | - Pay attention to image links. The images should the accessible from internet. If use the image that are in a private network, they can not used by users.
16 | - Always test the pattern. There is chance that you might have doing a small modification without thinking it will affect the code.
17 | - Pay attention to the blocks that you use. You accidentally might use a block that is not available in Otter or Gutenberg. Of course, you can add any block, but if it is external, it must intended.
18 |
19 |
20 |
--------------------------------------------------------------------------------
/docs/blocks.md:
--------------------------------------------------------------------------------
1 | # Blocks
2 |
3 | Blocks are the fundamental element of the editor. They are the primary way in which plugins and themes can register their own functionality and extend the capabilities of the editor.
4 |
5 | ## Registration
6 |
7 | For each block, you create a new folder in the `blocks` directory. If the block is a structural block, like Testimonial, Service or Pricing, then you can keep them in `blocks/structural` folder instead.
8 |
9 | You need to have an index.js file for the block registration, and rest of the registration process is simple. You can find more info on Block API on [Gutenberg Handbook](https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/).
10 |
11 | For styles, you can have two files:
12 |
13 | - style.scss
14 | - editor.scss
15 |
16 | Styles that are put in `style.scss` will only be loaded on the front-end, while `editor.scss` styles will only be loaded on the backend.
17 |
18 | ## Custom CSS & Google Fonts
19 |
20 | If your block needs to add any dynamic CSS that can't be added inline, such as pseudo-elements or media queries, you can use `cycle_through_blocks` method of [`GutenbergBlocks`](https://github.com/Codeinwp/gutenberg-blocks/blob/master/class-gutenberg-blocks.php) class.
21 |
22 | Similarly, if your block loads Google Fonts then you can use `get_google_fonts` method. Your Google Fonts attributes should be `fontFamily` and `fontVariant`.
--------------------------------------------------------------------------------
/plugins/blocks-animation/readme.md:
--------------------------------------------------------------------------------
1 | # Blocks Animation: CSS Animations for Gutenberg Blocks #
2 | **Contributors:** [themeisle](https://profiles.wordpress.org/themeisle/), [hardeepasrani](https://profiles.wordpress.org/hardeepasrani/), [mariamunteanu1](https://profiles.wordpress.org/mariamunteanu1/)
3 | **Tags:** gutenberg, block, block editor, editor, animation, animations, animate, styles, block animations
4 | **Requires at least:** 6.2
5 | **Tested up to:** 6.9
6 | **Requires PHP:** 5.4
7 | **Stable tag:** 3.1.4
8 | **License:** GPLv3
9 | **License URI:** https://www.gnu.org/licenses/gpl-3.0.en.html
10 |
11 | Blocks Animation allows you to add CSS Animations to all of your Gutenberg blocks in the most elegant way.
12 |
13 | ## Description ##
14 |
15 |
16 | Blocks Animation allows you to add CSS Animations to all of your Gutenberg blocks in the most elegant way.
17 |
18 | The UI for Blocks Animation feels so native and intuitive, you won't even notice it's installed. Just install, and you will see animation settings in all the blocks, right in the Block Settings Sidebar.
19 |
20 | All the code and sources for this plugin are publicly available as part of https://github.com/Codeinwp/otter-blocks.
21 |
22 | ## Screenshots ##
23 |
24 | 1. Block Animations
25 |
26 |
27 | ## Changelog ##
28 |
29 | You can check the changelog [here.](https://github.com/Codeinwp/otter-blocks/blob/master/CHANGELOG.md)
30 |
--------------------------------------------------------------------------------
/inc/css/blocks/class-google-map-css.php:
--------------------------------------------------------------------------------
1 | add_item(
37 | array(
38 | 'properties' => array(
39 | array(
40 | 'property' => '--height',
41 | 'value' => 'height',
42 | 'format' => function ( $value, $attrs ) {
43 | return is_numeric( $value ) ? $value . 'px' : $value;
44 | },
45 | ),
46 | array(
47 | 'property' => '--height-tablet',
48 | 'value' => 'heightTablet',
49 | ),
50 | array(
51 | 'property' => '--height-mobile',
52 | 'value' => 'heightMobile',
53 | ),
54 | ),
55 | )
56 | );
57 |
58 | return $css->generate();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/plugins/blocks-export-import/readme.txt:
--------------------------------------------------------------------------------
1 | === Blocks Export Import ===
2 | Contributors: themeisle, hardeepasrani
3 | Tags: gutenberg, block, blocks, export, import, exporter, importer, block exporter, block export, block import, block importer
4 | Requires at least: 6.2
5 | Tested up to: 6.9
6 | Requires PHP: 5.4
7 | Stable tag: 3.1.4
8 | License: GPLv3
9 | License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
10 |
11 | Blocks Export Import allows to Export and Import blocks as JSON in Gutenberg Block Editor.
12 |
13 | == Description ==
14 |
15 | Blocks Export Import plugin allows you to import and export blocks as JSON in Gutenberg Block Editor.
16 |
17 | All the code and sources for this plugin are publicly available as part of https://github.com/Codeinwp/otter-blocks.
18 |
19 | == Installation ==
20 | Activating this plugin is just like any other plugin. If you’ve uploaded the plugin package to your server already, skip to step 5 below:
21 |
22 | 1. Install using the WordPress built-in Plugin installer, or Extract the zip file and drop the contents in the wp-content/plugins/ directory of your WordPress installation.
23 | 2. Activate the plugin through the ‘Plugins’ menu in WordPress.
24 | 3. Go to Gutenberg editor and play around with the block.
25 |
26 | == Screenshots ==
27 |
28 | 1. Export Blocks.
29 | 2. Import Blocks
30 |
31 |
32 | == Changelog ==
33 |
34 | You can check the changelog [here.](https://github.com/Codeinwp/otter-blocks/blob/master/CHANGELOG.md)
35 |
--------------------------------------------------------------------------------
/.wp-env.override.json:
--------------------------------------------------------------------------------
1 | {
2 | "core": null,
3 | "plugins": [
4 | "."
5 | ],
6 | "config": {
7 | "WP_DEBUG": true,
8 | "WP_DEBUG_DISPLAY": true,
9 | "FS_METHOD": "direct",
10 | "WP_DEFAULT_THEME": "twentytwentythree"
11 | },
12 | "phpVersion": "7.4",
13 | "env": {
14 | "development": {
15 | "themes": [ "./test/emptytheme" ],
16 | "mappings": {
17 | "wp-content/themes/raft": "https://downloads.wordpress.org/theme/raft.zip"
18 | }
19 | },
20 | "tests": {
21 | "config": {
22 | "WP_DEBUG": false,
23 | "WP_DEBUG_DISPLAY": false,
24 | "ENABLE_OTTER_PRO_DEV": true
25 | },
26 | "plugins": [
27 | "."
28 | ],
29 | "themes": [ "./test/emptytheme" ],
30 | "mappings": {
31 | "wp-content/mu-plugins": "./packages/e2e-tests/mu-plugins",
32 | "wp-content/plugins/gutenberg-test-plugins": "./packages/e2e-tests/plugins",
33 | "wp-content/themes/gutenberg-test-themes": "./test/gutenberg-test-themes",
34 | "wp-content/themes/gutenberg-test-themes/twentytwentyone": "https://downloads.wordpress.org/theme/twentytwentyone.zip",
35 | "wp-content/themes/gutenberg-test-themes/twentytwentythree": "https://downloads.wordpress.org/theme/twentytwentythree.zip",
36 | "wp-content/themes/raft": "https://downloads.wordpress.org/theme/raft.zip"
37 | }
38 | }
39 | },
40 | "lifecycleScripts": {
41 | "afterStart": "bash bin/e2e-tests.sh"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/inc/render/class-about-author-block.php:
--------------------------------------------------------------------------------
1 | ',
27 | esc_url( get_author_posts_url( intval( get_the_author_meta( 'ID' ) ) ) ),
28 | esc_attr( get_avatar_url( get_the_author_meta( 'ID' ), array( 'size' => 130 ) ) )
29 | );
30 |
31 | $title_markup = sprintf(
32 | '%1$s ',
33 | esc_html( get_the_author_meta( 'display_name' ) )
34 | );
35 |
36 | $content_markup = '';
37 | if ( ! empty( get_the_author_meta( 'description' ) ) ) {
38 | $content_markup = sprintf(
39 | '%1$s
',
40 | esc_html( wp_strip_all_tags( get_the_author_meta( 'description' ) ) )
41 | );
42 | }
43 |
44 | return sprintf(
45 | '',
46 | get_block_wrapper_attributes(),
47 | $img_markup,
48 | $title_markup,
49 | $content_markup
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/plugins/blocks-export-import/blocks-export-import.php:
--------------------------------------------------------------------------------
1 | add_item(
37 | array(
38 | 'properties' => array(
39 | array(
40 | 'property' => '--height',
41 | 'value' => 'height',
42 | 'format' => function ( $value, $attrs ) {
43 |
44 | // Check if the value is a number.
45 | if ( is_numeric( $value ) ) {
46 | $suffix = substr( $value, -2 );
47 | if ( 'px' !== $suffix ) {
48 | return $value . 'px';
49 | }
50 | }
51 |
52 | return $value;
53 | },
54 | ),
55 | array(
56 | 'property' => '--height-tablet',
57 | 'value' => 'heightTablet',
58 | ),
59 | array(
60 | 'property' => '--height-mobile',
61 | 'value' => 'heightMobile',
62 | ),
63 | ),
64 | )
65 | );
66 |
67 | return $css->generate();
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/inc/integrations/interfaces/interface-form-subscribe-service.php:
--------------------------------------------------------------------------------
1 | add_item(
38 | array(
39 | 'properties' => array(
40 | array(
41 | 'property' => 'background-color',
42 | 'value' => 'backgroundColor',
43 | ),
44 | ),
45 | )
46 | );
47 |
48 | $css->add_item(
49 | array(
50 | 'selector' => ' .otter-business-hour-item__label',
51 | 'properties' => array(
52 | array(
53 | 'property' => 'color',
54 | 'value' => 'labelColor',
55 | ),
56 | ),
57 | )
58 | );
59 |
60 | $css->add_item(
61 | array(
62 | 'selector' => ' .otter-business-hour-item__time',
63 | 'properties' => array(
64 | array(
65 | 'property' => 'color',
66 | 'value' => 'timeColor',
67 | ),
68 | ),
69 | )
70 | );
71 |
72 | $style = $css->generate();
73 |
74 | return $style;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/inc/Tracker.php:
--------------------------------------------------------------------------------
1 | $events Data to track.
26 | * @param array $options Options.
27 | * @return void
28 | */
29 | public static function track( $events, $options = array() ) {
30 |
31 | if ( ! self::has_consent() && ( ! isset( $options['hasConsent'] ) || ! $options['hasConsent'] ) ) {
32 | return;
33 | }
34 |
35 | try {
36 | $payload = array();
37 |
38 | $license = apply_filters( 'product_otter_license_key', 'free' );
39 |
40 | if ( 'free' !== $license ) {
41 | $license = wp_hash( $license );
42 | }
43 |
44 | foreach ( $events as $event ) {
45 | $payload[] = array(
46 | 'slug' => 'otter',
47 | 'site' => get_site_url(),
48 | 'license' => $license,
49 | 'data' => $event,
50 | );
51 | }
52 |
53 | $args = array(
54 | 'headers' => array(
55 | 'Content-Type' => 'application/json',
56 | ),
57 | 'body' => wp_json_encode( $payload ),
58 | );
59 |
60 | wp_remote_post( self::$track_url, $args );
61 | } finally {
62 | return;
63 | }
64 | }
65 |
66 | /**
67 | * Check if the user has consented to tracking.
68 | *
69 | * @return bool
70 | */
71 | public static function has_consent() {
72 | return (bool) get_option( 'otter_blocks_logger_flag', false );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/css/blocks/class-form-stripe-field-css.php:
--------------------------------------------------------------------------------
1 | add_item(
37 | array(
38 | 'properties' => array(
39 | array(
40 | 'property' => '--label-color',
41 | 'value' => 'labelColor',
42 | ),
43 | array(
44 | 'property' => '--stripe-border-color',
45 | 'value' => 'borderColor',
46 | ),
47 | array(
48 | 'property' => '--stripe-border-radius',
49 | 'value' => 'borderRadius',
50 | 'format' => function ( $value ) {
51 | return CSS_Utility::render_box( $value );
52 | },
53 | ),
54 | array(
55 | 'property' => '--stripe-border-width',
56 | 'value' => 'borderWidth',
57 | 'format' => function ( $value ) {
58 | return CSS_Utility::render_box( $value );
59 | },
60 | ),
61 | ),
62 | )
63 | );
64 |
65 | $style = $css->generate();
66 |
67 | return $style;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/docs/uniit-and-e2e-testing.md:
--------------------------------------------------------------------------------
1 | # Automated Testing
2 |
3 | #### [Testing overview from Gutenberg.](https://developer.wordpress.org/block-editor/contributors/code/testing-overview/)
4 |
5 | ## Unit Testing
6 |
7 | Unit testing will be used to test functions (with [Jest](https://jestjs.io/docs/getting-started)) and React components (with [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)).
8 |
9 | The test will pe places in `tests/unit`
10 |
11 | They can be run with the command `npm run test:unit`.
12 |
13 | For debugging the test, use `npm run test:unit:debug`
14 |
15 | ## E2E Testing
16 |
17 | E2E are used to test the code on a running WordPress instance. They are very helpful for testing component that depends on the WP ecosystem like block, hooks (e.g.: `blockInit`).
18 |
19 | [Docs for Gutenberg utils](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-e2e-test-utils/)
20 |
21 | :warning: Most the code from Gutenberg is written in Puppeter, but they are migrating to Playwright which make the feature to not a very stable situation like Unit testing. [Source](https://make.wordpress.org/core/2022/03/23/migrating-wordpress-e2e-tests-to-playwright/)
22 |
23 | - [Puppeter Docs](https://pptr.dev)
24 | - [Playwright Docs](https://playwright.dev/docs/intro) and [Gutenberg Repo](https://github.com/WordPress/gutenberg/tree/trunk/test/e2e)
25 |
26 | You will need to use Docker for creating the WP Instace via `npm run wp-env start` command.
27 |
28 | The tests can be run with the command `npm run test:e2e'.
29 |
30 | For interactive mode (a Chromium instance will be created to watch), use `npm run test:e2e:interactive'
31 |
32 | For debugging the test, use `npm run test:e2e:debug`
33 |
34 | :warning: The e2e is a very slow test. Expect minutes of running.
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/development.php:
--------------------------------------------------------------------------------
1 | ', '', $message );
35 | }
36 | );
37 |
38 | add_filter( 'otter_pro_hide_license_field', '__return_true' );
39 |
40 | \ThemeIsle\OtterPro\Main::instance();
41 |
42 | if ( class_exists( '\ThemeIsle\OtterPro\Plugins\License' ) && ! ThemeIsle\OtterPro\Plugins\License::has_active_license() ) {
43 | add_action( 'init', function() {
44 | $license_file = dirname( __FILE__ ) . '/license.json';
45 |
46 | global $wp_filesystem;
47 |
48 | if ( ! is_file( $license_file ) ) {
49 | return false;
50 | }
51 |
52 | require_once ABSPATH . '/wp-admin/includes/file.php';
53 |
54 | \WP_Filesystem();
55 |
56 | $content = json_decode( $wp_filesystem->get_contents( $license_file ) );
57 |
58 | if ( ! is_object( $content ) ) {
59 | return false;
60 | }
61 |
62 | if ( ! isset( $content->key ) ) {
63 | return false;
64 | }
65 |
66 | $license_key = $content->key;
67 |
68 | apply_filters( 'themeisle_sdk_license_process_otter', $license_key, 'activate' );
69 | } );
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/render/class-add-to-cart-button-block.php:
--------------------------------------------------------------------------------
1 | $product->add_to_cart_description(),
37 | 'data-quantity' => '1',
38 | 'data-product_id' => $product->get_id(),
39 | 'data-product_sku' => $product->get_sku(),
40 | 'rel' => 'nofollow',
41 | 'class' => 'wp-block-button__link wp-element-button add_to_cart_button',
42 | );
43 |
44 | if (
45 | $product->supports( 'ajax_add_to_cart' ) &&
46 | $product->is_purchasable() &&
47 | ( $product->is_in_stock() || $product->backorders_allowed() )
48 | ) {
49 | $attrs['class'] .= ' ajax_add_to_cart';
50 | }
51 |
52 | $button = sprintf(
53 | ' %s ',
54 | esc_url( $product->add_to_cart_url() ),
55 | wc_implode_html_attributes( $attrs ),
56 | esc_html( isset( $attributes['label'] ) ? $attributes['label'] : $product->add_to_cart_text() )
57 | );
58 |
59 | return sprintf(
60 | '%2$s
',
61 | $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => 'wp-block-button' ) ),
62 | $button
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/render/class-form-hidden-block.php:
--------------------------------------------------------------------------------
1 | $id,
41 | )
42 | );
43 |
44 | $output = '';
45 |
46 | $output .= '' . $label . ' ';
47 |
48 | $output .= ' ';
53 |
54 | $output .= '
';
55 |
56 |
57 | return $output;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/assets/icons/acf.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/otter-family-plugins.md:
--------------------------------------------------------------------------------
1 | # The big four
2 |
3 | As you can see, there are four other plugins besides Otter that are part of the family. They are:
4 | - Block Animation: allow you to add animation to any block.
5 | - Blocks CSS: allow you to add custom CSS to any block.
6 | - Block Export & Import: allow you to export and import blocks as JSON files.
7 |
8 | ## Block Animation
9 |
10 | This plugin offer the option to the user to animate the block via:
11 | - `animate.css` library ([link](https://animate.style)): we just add this classes to `className` attribute of the block.
12 | - Typing (text only). We use a format tag (`o-anim-typing`) to mark the text that should be animated. We use a custom script to animate the text.
13 | - Counting: Same as Typing, but with the tag `o-anim-counting`.
14 |
15 | When it come to upgrading, the `animate.css` library is sometime troublesome. We need to check if the new version is compatible with the old one. If not, we need to update the code to make it compatible.
16 |
17 | For Typing and Counting, we have total control over the code (since their are made in-house). So, it is easier to upgrade.
18 |
19 | ## Blocks CSS
20 |
21 | This plugin allow the user to add custom CSS to any block. The CSS is added to the block via a `style` tag. This is handy for edge cases where the user need to enhance a block with an option that is not available in Inspector.
22 |
23 | Also, it allow us to provide quick hacks to the user until we fix the issue with styling in a Block.
24 |
25 | ## Block Export & Import
26 |
27 | This is a utility plugin that allow the user to export and import blocks as JSON files. It is useful for the user to backup their blocks and for us to debug issues. Sometime we need to test a block with a specific configuration. This plugin allow us to do the sharing more easily.
28 |
29 | For importing, the trick is simple: deserialize the JSON file and replace the block with the new one. For exporting, we need to serialize the block and save it to a JSON file.
--------------------------------------------------------------------------------
/docs/woocommerce-extensions.md:
--------------------------------------------------------------------------------
1 | # WooCommerce Extensions
2 |
3 | In WordPress, WooCommerce is the most popular plugin for e-commerce. In a simple view of a plugin developer: people with business that have a high chance to pay for a premium plugin. The market is so big that we can't ignore it. Otter can not a respectable plugin, without WooCommerce integration.
4 |
5 | The available WooCommerce extensions are:
6 | - Add to cart Block
7 | - Product Review with Woo Sync
8 | - Live Search (show product information in search results)
9 | - Small Showcase Blocks (title, price, rating, stock, etc.)
10 |
11 | Woo Commerce own plugin offer a lot of features for Gutenberg, and is mostly redundant to re-invent the wheel for most of them. So winning strategy is to allow Otter users to integrate WooCommerce with Otter Blocks. You use Product Review at the beginning then migrate to WooCommerce, no need to redo things, you can just sync it. The feeling is more like a 'handy feature` than a full blow WooCommerce extension plugin.
12 |
13 | ## Structure
14 |
15 | | Feature | Location |
16 | | :-- | :-- |
17 | | Frontend Render Add to Cart | `./plugins/otter-pro/inc/render/class-add-to-cart-button-block.php` |
18 | | Frontend Render Small Blocks | `./plugins/otter-pro/inc/render/woocommerce` |
19 | | Editor Add to Cart | `./src/pro/blocks/add-to-cart-button` |
20 | | Editor Small Blocks | `./src/pro/woocommerce` |
21 |
22 | For Live Search, learn more [here](live-search.md).
23 |
24 | ## Mentions
25 |
26 | - All of those feature require WooCommerce to be installed and activated. If WooCommerce is not installed, the block will be disabled. The features are built on top of WooCommerce API, so it is not possible to use them without WooCommerce.
27 | - When developing a new feature, you should always check if WooCommerce is installed and activated. If not, you should disable the feature.
28 | - Have stability always in mind. An e-commerce website is extremely important for the owner. Crashing the website is like hiding the owner's wallet.
--------------------------------------------------------------------------------
/docs/live-search.md:
--------------------------------------------------------------------------------
1 | # Live Search
2 |
3 | Live Search plugin is an enhancement to default Search block. It unlock new style and the ability to preview search results.
4 |
5 | ## Structure
6 |
7 | | Feature | Location |
8 | | :-- | :-- |
9 | | Editor Block Extension Upsell | `./src/blocks/plugins/live-search` |
10 | | Editor Block Extension | `./src/pro/plugins/live-search` |
11 | | Frontend | `./src/blocks/frontend/live-search` |
12 | | Backend | `./plugins/otter-pro/inc/plugins/class-live-search` |
13 |
14 |
15 | ## How it works
16 |
17 | The normal search will only show the results when you press the Submit button, and the result will be a page with a list of posts. Live Search will show the results as you type, and the result will be shown as a dropdown with list of posts, pages, products, and other custom post types.
18 |
19 | Every time you type a new character, the search will be triggered with [this function](https://github.com/Codeinwp/otter-blocks/blob/4d9eafabaec64c02d0e522d78f08404e56a80396/src/blocks/frontend/live-search/index.ts#L59-L79). The request will be processed [here](https://github.com/Codeinwp/otter-blocks/blob/4d9eafabaec64c02d0e522d78f08404e56a80396/plugins/otter-pro/inc/server/class-live-search-server.php#L131-L171) by leveraging WordPress `WP_Query`.
20 |
21 | In a nutshell, this is just fancy interface that makes the classic Search Block to feel more modern. The inspiration point was the [search bar for MDN Web Docs](https://developer.mozilla.org/en-US/) [#1135](https://github.com/Codeinwp/otter-blocks/issues/1135).
22 |
23 | The main selling point of this plugin is showing useful information to the end user. This information is mostly from metadata, like: date, author, product price, category, etc. Users to run e-commerce websites will find this plugin very useful.
24 |
25 | When you are developing a new feature for it have those in mind:
26 | - Monitor the request time, it should be as fast as possible.
27 | - Watch the requests number. You don't want to overload the server.
28 | - Pay attention to error handling when integrating with other plugins.
29 |
--------------------------------------------------------------------------------
/inc/css/blocks/class-timeline-item-css.php:
--------------------------------------------------------------------------------
1 | add_item(
38 | array(
39 | 'properties' => array(
40 | array(
41 | 'property' => '--o-timeline-cnt-bg',
42 | 'value' => 'containerBackgroundColor',
43 | ),
44 | array(
45 | 'property' => '--o-timeline-cnt-br-c',
46 | 'value' => 'containerBorderColor',
47 | ),
48 | array(
49 | 'property' => '--o-timeline-i-color',
50 | 'value' => 'iconColor',
51 | ),
52 | array(
53 | 'property' => '--o-timeline-cnt-br-w',
54 | 'value' => 'containerBorder',
55 | 'format' => function ( $value, $attrs ) {
56 | return CSS_Utility::box_values(
57 | $value,
58 | array(
59 | 'left' => '8px',
60 | 'right' => '8px',
61 | 'top' => '8px',
62 | 'bottom' => '8px',
63 | )
64 | );
65 | },
66 | ),
67 | array(
68 | 'property' => '--o-timeline-cnt-br-r',
69 | 'value' => 'containerRadius',
70 | 'format' => function ( $value, $attrs ) {
71 | return CSS_Utility::box_values(
72 | $value,
73 | array(
74 | 'left' => '8px',
75 | 'right' => '8px',
76 | 'top' => '8px',
77 | 'bottom' => '8px',
78 | )
79 | );
80 | },
81 | ),
82 | ),
83 | )
84 | );
85 |
86 | $style = $css->generate();
87 |
88 | return $style;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Setup
2 |
3 | More details about the setup can be found in [docs/environment-installation.md](docs/environment-installation.md).
4 |
5 | This projects requires you to have Node.js (with npm) and Composer.
6 |
7 | - You can run `npm ci` & `composer install` to install dependencies.
8 | - Once done, you can run `npm run build` to generate build files.
9 | - You can also use `npm run start` to generate dev build if you are working on the files.
10 |
11 | The project also ships with a `docker-compose.yml` file, you can run `docker compose up -d` to bring the instance up.
12 |
13 | ## Project Structure
14 |
15 | This repo is codebase for five different plugins, which are:
16 |
17 | - Otter Blocks
18 | - Otter Pro
19 | - Blocks Animation
20 | - Blocks CSS
21 | - Blocks Export Import
22 |
23 | Blocks Animation, CSS & Export Import are also shipped as part of Otter Blocks. Codebase of each sister-plugin of Otter, which is plugin-specific, can be found in `/plugins` folder of the repo, while the code which is shared in both Otter & sister-plugins is kept inside `/inc` folder.
24 |
25 | You can take a look at `/bin/dist.sh` file to see how each plugin is generated. Each sister-plugin has its own `.distignore` and `.wordpress-org` file/directory that needs to be maintained with latest changes.
26 |
27 | And finally, `blocks.json` file defines the build path of block assets.
28 |
29 | ## Compatibility
30 |
31 | Any change you make, you should test with at least last 2 major versions of WordPress.
32 |
33 | ## Releasing
34 |
35 | This repository uses conventional [changelog commit](https://github.com/Codeinwp/conventional-changelog-simple-preset) messages to trigger release
36 |
37 | How to release a new version:
38 |
39 | - Clone the master branch
40 | - Do your changes
41 | - Send a PR to master and merge it using the following subject message
42 | - `release: ` - for patch release
43 | - `release(minor): ` - for minor release
44 | - `release(major): ` - for major release
45 | The release notes will inherit the body of the commit message which triggered the release. For more details check the [simple-preset](https://github.com/Codeinwp/conventional-changelog-simple-preset) that we use.
46 |
--------------------------------------------------------------------------------
/inc/css/blocks/class-sharing-icons-css.php:
--------------------------------------------------------------------------------
1 | $attrs ) {
38 | $css->add_item(
39 | array(
40 | 'selector' => ' .is-' . $icon,
41 | 'properties' => array(
42 | array(
43 | 'property' => '--icon-bg-color',
44 | 'value' => $icon,
45 | 'format' => function ( $value, $attrs ) {
46 | return $value['backgroundColor'];
47 | },
48 | 'condition' => function ( $attrs ) use ( $icon ) {
49 | return isset( $attrs[ $icon ]['backgroundColor'] );
50 | },
51 | ),
52 | array(
53 | 'property' => '--text-color',
54 | 'value' => $icon,
55 | 'format' => function ( $value, $attrs ) {
56 | return $value['textColor'];
57 | },
58 | 'condition' => function ( $attrs ) use ( $icon ) {
59 | return isset( $attrs[ $icon ]['textColor'] );
60 | },
61 | ),
62 | ),
63 | )
64 | );
65 | }
66 |
67 | $css->add_item(
68 | array(
69 | 'properties' => array(
70 | array(
71 | 'property' => '--icons-gap',
72 | 'value' => 'gap',
73 | 'unit' => 'px',
74 | ),
75 | array(
76 | 'property' => '--border-radius',
77 | 'value' => 'borderRadius',
78 | 'unit' => 'px',
79 | ),
80 | ),
81 | )
82 | );
83 |
84 | return $css->generate();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/inc/css/blocks/class-slider-css.php:
--------------------------------------------------------------------------------
1 | add_item(
38 | array(
39 | 'properties' => array(
40 | array(
41 | 'property' => '--height',
42 | 'value' => 'height',
43 | 'format' => function ( $value, $attrs ) {
44 | return is_numeric( $value ) ? $value . 'px' : $value;
45 | },
46 | ),
47 | array(
48 | 'property' => '--height-tablet',
49 | 'value' => 'heightTablet',
50 | ),
51 | array(
52 | 'property' => '--height-mobile',
53 | 'value' => 'heightMobile',
54 | ),
55 | array(
56 | 'property' => '--width',
57 | 'value' => 'width',
58 | ),
59 | array(
60 | 'property' => '--arrows-color',
61 | 'value' => 'arrowsColor',
62 | ),
63 | array(
64 | 'property' => '--arrows-background-color',
65 | 'value' => 'arrowsBackgroundColor',
66 | ),
67 | array(
68 | 'property' => '--pagination-color',
69 | 'value' => 'paginationColor',
70 | ),
71 | array(
72 | 'property' => '--pagination-active-color',
73 | 'value' => 'paginationActiveColor',
74 | ),
75 | array(
76 | 'property' => '--border-color',
77 | 'value' => 'borderColor',
78 | ),
79 | array(
80 | 'property' => '--border-width',
81 | 'value' => 'borderWidth',
82 | ),
83 | array(
84 | 'property' => '--border-radius',
85 | 'value' => 'borderRadius',
86 | ),
87 | ),
88 | )
89 | );
90 |
91 | $style = $css->generate();
92 |
93 | return $style;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/docs/form-block-workflow.md:
--------------------------------------------------------------------------------
1 | # Form Block Workflow
2 |
3 | A guide about how Form workflow works.
4 |
5 | ## The scope
6 |
7 | Allowing the end user to send some data to the website owner. Data can be: text, number, email, date, files, etc. The can be sent to a third party service or to the website owner. It can go via email or internal storage.
8 |
9 | When doing this we need to consider the following:
10 | - Bots. We need to prevent bots from sending data.
11 | - Security. We need to prevent malicious data from being sent. Data sanitization, validation, etc. For files we have to consider the numbers, the size and the type.
12 | - 3rd party services. We need to consider the API of the service and how to send the data.
13 |
14 | ## How it works from the Submit click to the data being sent
15 |
16 | When the user clicks on the Submit button, the following happens:
17 | - The data is validated with JS and collected. Then sended to the server via `wp-json/form/frontend` endpoint (definition in `./inc/server/class-form-server.php`).
18 | - The data is validated with PHP via `otter_form_validate_form` filter hook. If the data is invalid, we check if it was sended by a bot with `otter_form_anti_spam_validation` filter hook.
19 | - If all ok, we apply some data preparation `otter_form_data_preparation`. This will add or change the data from the `$form_data` variable.
20 | - If everything goes well, we get the provider (the service that will receive the data) and run with the current data request of `$form_data`.
21 | - At the end we do a `otter_form_after_submit` to trigger extra actions. (deleting files, sending data to 3rd party services, auto-responder, etc.)
22 |
23 | You will see in the server a lot of error handling. This is because we need to be sure that the data is sent to the user. If something goes wrong, we need to inform the user or the admin (in critical cases). For the server part, the PHP utility files are in `./inc/integrations/`.
24 |
25 | ## Where are the options for the form?
26 |
27 | As you know, you can not trust the request that come to the server. It might be malicious. When we process a request, we pull the options of the form that send the request with the `get_option` function (the data is saved in WordPress options and you can see the definition in `./inc/plugins/class-options-settings.php` ) and check if request respect the options. If not, we return an error.
28 |
29 | If you add a new feature and need to save in options, make sure to change the definition from `./inc/plugins/class-options-settings.php`.
30 |
31 |
--------------------------------------------------------------------------------
/inc/render/class-leaflet-map-block.php:
--------------------------------------------------------------------------------
1 | ';
29 | $output .= ' ';
30 | $output .= '';
31 |
32 | return $output;
33 | }
34 |
35 | // Set the ID and the class name.
36 | $id = isset( $attributes['id'] ) ? esc_attr( $attributes['id'] ) : 'wp-block-themeisle-blocks-map-' . wp_rand( 10, 100 );
37 | $class = '';
38 | $style = '';
39 |
40 | if ( isset( $attributes['height'] ) ) {
41 | $style .= 'height:' . esc_attr( $attributes['height'] . 'px;' );
42 | }
43 |
44 | if ( isset( $attributes['align'] ) ) {
45 | $class .= 'align' . esc_attr( $attributes['align'] );
46 | }
47 |
48 | $wrapper_attributes = get_block_wrapper_attributes(
49 | array(
50 | 'id' => $id,
51 | 'class' => $class,
52 | 'style' => $style,
53 | )
54 | );
55 |
56 | // Load the attributes in the page and make a placeholder to render the map.
57 | $output = '
' . "\n";
58 | $output .= '' . "\n";
64 |
65 | return $output;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/assets/icons/meta.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/inc/render/class-google-map-block.php:
--------------------------------------------------------------------------------
1 | ';
35 | $output .= ' ';
36 | $output .= '';
37 |
38 | return $output;
39 | }
40 |
41 | $id = isset( $attributes['id'] ) ? esc_attr( $attributes['id'] ) : 'wp-block-themeisle-blocks-google-map-' . wp_rand( 10, 100 );
42 | $class = '';
43 | $style = '';
44 |
45 | if ( isset( $attributes['align'] ) ) {
46 | $class .= 'align' . esc_attr( $attributes['align'] );
47 | }
48 |
49 | if ( isset( $attributes['height'] ) ) {
50 | $style .= 'height:' . esc_attr( is_numeric( $attributes['height'] ) ? $attributes['height'] . 'px' : $attributes['height'] );
51 | }
52 |
53 | $wrapper_attributes = get_block_wrapper_attributes(
54 | array(
55 | 'class' => $class,
56 | 'style' => $style,
57 | )
58 | );
59 |
60 | $output = '
' . "\n";
61 | $output .= '' . "\n";
67 |
68 | return $output;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/webpack.config.pro.js:
--------------------------------------------------------------------------------
1 | const { BundleAnalyzerPlugin } = require( 'webpack-bundle-analyzer' );
2 | const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
3 | const NODE_ENV = process.env.NODE_ENV || 'development';
4 | const ANALYZER = 'true' === process.env.NODE_ANALYZER ? true : false;
5 | const path = require( 'path' );
6 | const FileManagerPlugin = require( 'filemanager-webpack-plugin' );
7 | const blocks = require( './blocks.json' );
8 |
9 | defaultConfig.plugins.splice( 1, 1 ); // We need to remove Core's Copy Files plugin.
10 |
11 | const blockFilesPro = Object.keys( blocks ).filter( block => blocks[ block ].block !== undefined && true === blocks[ block ]?.isPro )
12 | .map( block => {
13 | return {
14 | source: `src/${ blocks[ block ].block }`,
15 | destination: `build/pro/${ block }/`
16 | };
17 | });
18 |
19 | const blockFoldersPro = Object.keys( blocks ).filter( block => true === blocks[ block ]?.isPro ).map( block => `build/pro/${ block }` );
20 |
21 | const changeTextDomain = textdomain => {
22 | return {
23 | test: /\.(j|t)sx?$/,
24 | exclude: /node_modules/,
25 | use: [
26 | {
27 | loader: require.resolve( 'babel-loader' ),
28 | options: {
29 | cacheDirectory:
30 | process.env.BABEL_CACHE_DIRECTORY || true,
31 | babelrc: false,
32 | configFile: false,
33 | presets: [
34 | require.resolve(
35 | '@wordpress/babel-preset-default'
36 | )
37 | ],
38 | plugins: [
39 | [ '@automattic/babel-plugin-replace-textdomain', { textdomain }]
40 | ]
41 | }
42 | }
43 | ]
44 | };
45 | };
46 |
47 | module.exports = [
48 | {
49 |
50 | // OTTER PRO
51 | ...defaultConfig,
52 | stats: 'minimal',
53 | devtool: 'development' === NODE_ENV ? 'eval-source-map' : undefined,
54 | mode: NODE_ENV,
55 | entry: {
56 | blocks: [
57 | './src/pro/blocks/index.js',
58 | './src/pro/plugins/index.js'
59 | ],
60 | dashboard: './src/pro/dashboard/index.js',
61 | woocommerce: './src/pro/woocommerce/index.js'
62 | },
63 | output: {
64 | path: path.resolve( __dirname, './build/pro' ),
65 | filename: '[name].js',
66 | chunkFilename: 'chunk-[name].js'
67 | },
68 | module: {
69 | rules: [
70 | changeTextDomain('otter-pro'),
71 | ...defaultConfig.module.rules
72 | ]
73 | },
74 | plugins: [
75 | ...defaultConfig.plugins,
76 | new FileManagerPlugin({
77 | events: {
78 | onEnd: {
79 | mkdir: blockFoldersPro,
80 | copy: blockFilesPro
81 | }
82 | },
83 | runOnceInWatchMode: false,
84 | runTasksInSeries: true
85 | }),
86 | new BundleAnalyzerPlugin({
87 | analyzerMode: 'disabled',
88 | generateStatsFile: ANALYZER
89 | })
90 | ]
91 | }
92 | ];
93 |
--------------------------------------------------------------------------------
/plugins/blocks-css/blocks-css.php:
--------------------------------------------------------------------------------
1 | 'free',
78 | ),
79 | tsdk_translate_link( tsdk_utmify( 'https://themeisle.link/otter-bf', 'bfcm', 'blocks-css' ) )
80 | );
81 |
82 | $configs[ BLOCKS_CSS_PRODUCT_SLUG ] = $config;
83 |
84 | return $configs;
85 | }
86 | );
87 |
--------------------------------------------------------------------------------
/inc/class-blocks-export-import.php:
--------------------------------------------------------------------------------
1 | init();
68 | }
69 |
70 | return self::$instance;
71 | }
72 |
73 | /**
74 | * Throw error on object clone
75 | *
76 | * The whole idea of the singleton design pattern is that there is a single
77 | * object therefore, we don't want the object to be cloned.
78 | *
79 | * @access public
80 | * @since 1.0.0
81 | * @return void
82 | */
83 | public function __clone() {
84 | // Cloning instances of the class is forbidden.
85 | _doing_it_wrong( __FUNCTION__, 'Cheatin’ huh?', '1.0.0' );
86 | }
87 |
88 | /**
89 | * Disable unserializing of the class
90 | *
91 | * @access public
92 | * @since 1.0.0
93 | * @return void
94 | */
95 | public function __wakeup() {
96 | // Unserializing instances of the class is forbidden.
97 | _doing_it_wrong( __FUNCTION__, 'Cheatin’ huh?', '1.0.0' );
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/inc/patterns/large-quote.php:
--------------------------------------------------------------------------------
1 | __( 'Large Quote', 'otter-blocks' ),
10 | 'categories' => array( 'otter-blocks', 'text' ),
11 | 'content' => '
"...The greatest victory is that which requires no battle...."
Sun Tzu, The Art of War
',
12 | );
13 |
--------------------------------------------------------------------------------
/inc/css/blocks/class-core-image-plugin-css.php:
--------------------------------------------------------------------------------
1 | /m';
47 | preg_match_all( $re, $block['innerHTML'], $matches, PREG_SET_ORDER, 0 );
48 |
49 | if ( empty( $matches ) || empty( $matches[0][1] ) ) {
50 | return $style;
51 | }
52 |
53 | $id = $matches[0][1];
54 |
55 | $css->set_id( $id );
56 |
57 | $css->add_item(
58 | array(
59 | 'selector' => ' img',
60 | 'properties' => array(
61 | array(
62 | 'property' => 'box-shadow',
63 | 'pattern' => 'horizontal vertical blur color',
64 | 'pattern_values' => array(
65 | 'horizontal' => array(
66 | 'value' => 'boxShadowHorizontal',
67 | 'unit' => 'px',
68 | 'default' => 0,
69 | ),
70 | 'vertical' => array(
71 | 'value' => 'boxShadowVertical',
72 | 'unit' => 'px',
73 | 'default' => 0,
74 | ),
75 | 'blur' => array(
76 | 'value' => 'boxShadowBlur',
77 | 'unit' => 'px',
78 | 'default' => 5,
79 | ),
80 | 'color' => array(
81 | 'value' => 'boxShadowColor',
82 | 'default' => '#000',
83 | 'format' => function ( $value, $attrs ) {
84 | $opacity = ( isset( $attrs['boxShadowColorOpacity'] ) ? $attrs['boxShadowColorOpacity'] : 50 );
85 | return ( strpos( $value, '#' ) !== false && $opacity < 100 ) ? Base_CSS::hex2rgba( $value, $opacity / 100 ) : $value;
86 | },
87 | ),
88 | ),
89 | 'condition' => function ( $attrs ) {
90 | return isset( $attrs['boxShadow'] );
91 | },
92 | ),
93 | ),
94 | )
95 | );
96 |
97 | $style = $css->generate();
98 |
99 | return $style;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/docs/blocks/deprecation.md:
--------------------------------------------------------------------------------
1 | > We recommend to read this article before: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-deprecation/
2 |
3 | ## [When the big change is comming](https://www.youtube.com/watch?v=enuOArEfqGo)
4 |
5 | In the previous chapters we removed the `color` property so that we can add with PHP. Let's add it back and make the migration scheme. **Remember to save the current block (Update or Save draft)**.
6 |
7 | ```jsx
8 | registerBlockType( 'themeisle-blocks/tutorial-2', {
9 | title: __( 'My first Block - Tutorial 2' ),
10 | description: __( 'Small Example 2' ),
11 | icon: 'universal-access-alt',
12 | category: 'themeisle-blocks',
13 | keywords: [ 'tutorial' ],
14 | attributes: {
15 | text: {
16 | type: 'string',
17 | default: 'Hello'
18 | },
19 | color: {
20 | type: 'string',
21 | default: 'green'
22 | }
23 | },
24 | edit: ( props ) => {
25 | console.log( props );
26 | const [ wordsNum, setWordsNum ] = useState( 0 );
27 | const onTextChange = ( value ) => props.setAttributes({ text: value.target.value });
28 |
29 | useEffect( () => {
30 | setWordsNum( props.attributes?.text?.split( ' ' ).length || 0 );
31 | }, [ props.attributes.text ]);
32 |
33 | return (
34 |
35 |
36 |
The text is: {props.attributes.text}
37 |
Words Number: {wordsNum}
38 |
39 | );
40 | },
41 | save: ( props ) => {
42 | return (
43 |
44 |
The text is: {props.attributes.text}
45 |
46 | );
47 | },
48 | deprecated: [ {
49 | attributes: {
50 | text: {
51 | type: 'string',
52 | default: 'Hello'
53 | },
54 | color: {
55 | type: 'string',
56 | default: 'green'
57 | }
58 | },
59 | save: ( props ) => {
60 | return (
61 |
62 |
The text is: {props.attributes.text}
63 |
64 | );
65 | }
66 | } ]
67 | });
68 | ```
69 |
70 | If we refesh the page, the transition will be made and no error will appear.
71 |
72 | ```html
73 |
74 |
75 |
76 | ```
77 |
78 | Blocks for reference:
79 |
80 | - Section Block: `src/blocks/section/column/deprecated.js` | `src/blocks/section/columns/deprecated.js`
81 | - Posts: `src/blocks/posts/deprecated.js`
82 | - Font Awesome Icons: `src/blocks/font-awesome-icons/deprecated.js`
83 | - Advanced Heading: `src/blocks/advanced-heading/deprecated.js`
84 |
85 | We do not have many blocks with the `deprecated` feature; we try as much as possible to avoid this.
86 |
87 |
88 |
--------------------------------------------------------------------------------
/plugins/blocks-animation/blocks-animation.php:
--------------------------------------------------------------------------------
1 | 'free',
82 | ),
83 | tsdk_translate_link( tsdk_utmify( 'https://themeisle.link/otter-bf', 'bfcm', 'blocks-animation' ) )
84 | );
85 |
86 | $configs[ BLOCKS_ANIMATION_PRODUCT_SLUG ] = $config;
87 |
88 | return $configs;
89 | }
90 | );
91 |
--------------------------------------------------------------------------------
/assets/icons/author.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/inc/render/amp/class-slider-block.php:
--------------------------------------------------------------------------------
1 | loadHTML( $block['innerHTML'] );
41 | $id = $block['attrs']['id'];
42 | $images = $dom->getElementsByTagName( 'figure' );
43 | $block_content = '';
44 |
45 | foreach ( $images as $image ) {
46 | $block_content .= $html5->saveHTML( $image );
47 | }
48 |
49 | $block_content .= ' ';
50 |
51 | return $block_content;
52 | }
53 |
54 | return $block_content;
55 | }
56 |
57 | /**
58 | * The instance method for the static class.
59 | * Defines and returns the instance of the static class.
60 | *
61 | * @static
62 | * @since 1.7.1
63 | * @access public
64 | * @return Slider_Block
65 | */
66 | public static function instance() {
67 | if ( is_null( self::$instance ) ) {
68 | self::$instance = new self();
69 | self::$instance->init();
70 | }
71 |
72 | return self::$instance;
73 | }
74 |
75 | /**
76 | * Throw error on object clone
77 | *
78 | * The whole idea of the singleton design pattern is that there is a single
79 | * object therefore, we don't want the object to be cloned.
80 | *
81 | * @access public
82 | * @since 1.7.1
83 | * @return void
84 | */
85 | public function __clone() {
86 | // Cloning instances of the class is forbidden.
87 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-blocks' ), '1.0.0' );
88 | }
89 |
90 | /**
91 | * Disable unserializing of the class
92 | *
93 | * @access public
94 | * @since 1.7.1
95 | * @return void
96 | */
97 | public function __wakeup() {
98 | // Unserializing instances of the class is forbidden.
99 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-blocks' ), '1.0.0' );
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/inc/render/amp/class-lottie.block.php:
--------------------------------------------------------------------------------
1 | ';
49 | return $block_content;
50 | }
51 |
52 | return $block_content;
53 | }
54 |
55 | /**
56 | * The instance method for the static class.
57 | * Defines and returns the instance of the static class.
58 | *
59 | * @static
60 | * @since 1.7.1
61 | * @access public
62 | * @return Lottie_Block
63 | */
64 | public static function instance() {
65 | if ( is_null( self::$instance ) ) {
66 | self::$instance = new self();
67 | self::$instance->init();
68 | }
69 |
70 | return self::$instance;
71 | }
72 |
73 | /**
74 | * Throw error on object clone
75 | *
76 | * The whole idea of the singleton design pattern is that there is a single
77 | * object therefore, we don't want the object to be cloned.
78 | *
79 | * @access public
80 | * @since 1.7.1
81 | * @return void
82 | */
83 | public function __clone() {
84 | // Cloning instances of the class is forbidden.
85 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-blocks' ), '1.0.0' );
86 | }
87 |
88 | /**
89 | * Disable unserializing of the class
90 | *
91 | * @access public
92 | * @since 1.7.1
93 | * @return void
94 | */
95 | public function __wakeup() {
96 | // Unserializing instances of the class is forbidden.
97 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-blocks' ), '1.0.0' );
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/webpack.config.plugins.js:
--------------------------------------------------------------------------------
1 | const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
2 | const FileManagerPlugin = require( 'filemanager-webpack-plugin' );
3 | const NODE_ENV = process.env.NODE_ENV || 'development';
4 | const path = require( 'path' );
5 |
6 | defaultConfig.plugins.splice( 1, 1 ); // We need to remove Core's Copy Files plugin.
7 |
8 | const changeTextDomain = textdomain => {
9 | return {
10 | test: /\.(j|t)sx?$/,
11 | exclude: /node_modules/,
12 | use: [
13 | {
14 | loader: require.resolve( 'babel-loader' ),
15 | options: {
16 | cacheDirectory:
17 | process.env.BABEL_CACHE_DIRECTORY || true,
18 | babelrc: false,
19 | configFile: false,
20 | presets: [
21 | require.resolve(
22 | '@wordpress/babel-preset-default'
23 | )
24 | ],
25 | plugins: [
26 | [ '@automattic/babel-plugin-replace-textdomain', { textdomain }]
27 | ]
28 | }
29 | }
30 | ]
31 | };
32 | };
33 |
34 | const plugins = {
35 | plugins: [
36 | ...defaultConfig.plugins,
37 | new FileManagerPlugin({
38 | events: {
39 | onEnd: {
40 | delete: [
41 | 'build/animation/blocks/',
42 | 'build/animation/pro/',
43 | 'build/css/blocks/',
44 | 'build/css/pro/',
45 | 'build/export-import/blocks/',
46 | 'build/export-import/pro/'
47 | ]
48 | }
49 | },
50 | runOnceInWatchMode: false,
51 | runTasksInSeries: true
52 | })
53 | ]
54 | };
55 |
56 | module.exports = [
57 | {
58 |
59 | // ANIMATION
60 | ...defaultConfig,
61 | stats: 'minimal',
62 | mode: NODE_ENV,
63 | entry: {
64 | index: './src/animation/index.js',
65 | frontend: './src/animation/frontend.js',
66 | 'anim-count': './src/animation/frontend/count/index.js',
67 | 'anim-typing': './src/animation/frontend/typing/index.js',
68 | 'welcome-notice': './src/animation/welcome-notice/index.js'
69 | },
70 | output: {
71 | path: path.resolve( __dirname, './build/animation' )
72 | },
73 | module: {
74 | rules: [
75 | changeTextDomain('blocks-animation'),
76 | ...defaultConfig.module.rules
77 | ]
78 | },
79 | ...plugins
80 | },
81 | {
82 |
83 | // CSS
84 | ...defaultConfig,
85 | stats: 'minimal',
86 | mode: NODE_ENV,
87 | entry: {
88 | index: './src/css/index.js'
89 | },
90 | output: {
91 | path: path.resolve( __dirname, './build/css' )
92 | },
93 | module: {
94 | rules: [
95 | changeTextDomain('blocks-css'),
96 | ...defaultConfig.module.rules
97 | ]
98 | },
99 | ...plugins
100 | },
101 | {
102 |
103 | // Export Import
104 | ...defaultConfig,
105 | stats: 'minimal',
106 | mode: NODE_ENV,
107 | entry: {
108 | index: './src/export-import/index.js'
109 | },
110 | output: {
111 | path: path.resolve( __dirname, './build/export-import' )
112 | },
113 | module: {
114 | rules: [
115 | changeTextDomain('blocks-export-import'),
116 | ...defaultConfig.module.rules
117 | ]
118 | },
119 | ...plugins
120 | }
121 | ];
122 |
--------------------------------------------------------------------------------
/inc/css/blocks/class-progress-bar-css.php:
--------------------------------------------------------------------------------
1 | add_item(
40 | array(
41 | 'properties' => array(
42 | array(
43 | 'property' => '--percentage',
44 | 'value' => 'percentage',
45 | 'unit' => '%',
46 | ),
47 | array(
48 | 'property' => '--title-color',
49 | 'value' => 'titleColor',
50 | ),
51 | array(
52 | 'property' => '--percentage-color',
53 | 'value' => 'percentageColor',
54 | 'condition' => function ( $attrs ) {
55 | return ! isset( $attrs['percentagePosition'] );
56 | },
57 | ),
58 | array(
59 | 'property' => '--percentage-color-outer',
60 | 'value' => 'percentageColor',
61 | 'condition' => function ( $attrs ) {
62 | return isset( $attrs['percentagePosition'] ) && 'outer' === $attrs['percentagePosition'];
63 | },
64 | ),
65 | array(
66 | 'property' => '--percentage-color-tooltip',
67 | 'value' => 'percentageColor',
68 | 'condition' => function ( $attrs ) {
69 | return isset( $attrs['percentagePosition'] ) && 'tooltip' === $attrs['percentagePosition'];
70 | },
71 | ),
72 | array(
73 | 'property' => '--percentage-color-append',
74 | 'value' => 'percentageColor',
75 | 'condition' => function ( $attrs ) {
76 | return isset( $attrs['percentagePosition'] ) && 'append' === $attrs['percentagePosition'];
77 | },
78 | ),
79 | array(
80 | 'property' => '--background-color',
81 | 'value' => 'backgroundColor',
82 | ),
83 | array(
84 | 'property' => '--border-radius',
85 | 'value' => 'borderRadius',
86 | 'unit' => 'px',
87 | ),
88 | array(
89 | 'property' => '--height',
90 | 'value' => 'height',
91 | 'unit' => 'px',
92 | ),
93 | array(
94 | 'property' => '--bar-background',
95 | 'value' => 'barBackgroundColor',
96 | ),
97 | array(
98 | 'property' => '--title-font-size',
99 | 'value' => 'titleFontSize',
100 | ),
101 | ),
102 | )
103 | );
104 |
105 | $style = $css->generate();
106 |
107 | return $style;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/inc/css/blocks/class-timeline-css.php:
--------------------------------------------------------------------------------
1 | add_item(
38 | array(
39 | 'properties' => array(
40 | array(
41 | 'property' => '--o-timeline-cnt-bg',
42 | 'value' => 'containerBackgroundColor',
43 | ),
44 | array(
45 | 'property' => '--o-timeline-cnt-br-c',
46 | 'value' => 'containerBorderColor',
47 | ),
48 | array(
49 | 'property' => '--o-timeline-i-font-size',
50 | 'value' => 'iconSize',
51 | ),
52 | array(
53 | 'property' => '--o-timeline-i-color',
54 | 'value' => 'iconColor',
55 | ),
56 | array(
57 | 'property' => '--o-timeline-v-color',
58 | 'value' => 'verticalLineColor',
59 | ),
60 | array(
61 | 'property' => '--o-timeline-v-width',
62 | 'value' => 'verticalLineWidth',
63 | ),
64 | array(
65 | 'property' => '--o-timeline-cnt-br-w',
66 | 'value' => 'containerBorder',
67 | 'format' => function ( $value, $attrs ) {
68 | return CSS_Utility::box_values(
69 | $value,
70 | array(
71 | 'left' => '8px',
72 | 'right' => '8px',
73 | 'top' => '8px',
74 | 'bottom' => '8px',
75 | )
76 | );
77 | },
78 | ),
79 | array(
80 | 'property' => '--o-timeline-cnt-br-r',
81 | 'value' => 'containerRadius',
82 | 'format' => function ( $value, $attrs ) {
83 | return CSS_Utility::box_values(
84 | $value,
85 | array(
86 | 'left' => '8px',
87 | 'right' => '8px',
88 | 'top' => '8px',
89 | 'bottom' => '8px',
90 | )
91 | );
92 | },
93 | ),
94 | array(
95 | 'property' => '--o-timeline-cnt-pd',
96 | 'value' => 'containerPadding',
97 | 'format' => function ( $value, $attrs ) {
98 | return CSS_Utility::box_values(
99 | $value,
100 | array(
101 | 'left' => '20px',
102 | 'right' => '20px',
103 | 'top' => '20px',
104 | 'bottom' => '20px',
105 | )
106 | );
107 | },
108 | ),
109 | ),
110 | )
111 | );
112 |
113 | $style = $css->generate();
114 |
115 | return $style;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/inc/patterns/call-to-action-1.php:
--------------------------------------------------------------------------------
1 | __( 'Call to Action', 'otter-blocks' ),
10 | 'categories' => array( 'otter-blocks', 'call-to-action' ),
11 | 'content' => '
A call to action section A Call to action section
', // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation
12 | );
13 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/render/class-form-file-block.php:
--------------------------------------------------------------------------------
1 | 1 );
37 | $allowed_files = isset( $attributes['allowedFileTypes'] ) ? implode( ',', $attributes['allowedFileTypes'] ) : '';
38 |
39 | $wrapper_attributes = get_block_wrapper_attributes(
40 | array(
41 | 'id' => $id,
42 | )
43 | );
44 |
45 | $output = '';
46 | $mapped_name = isset( $attributes['mappedName'] ) ? esc_attr( $attributes['mappedName'] ) : 'field-' . $id;
47 |
48 | $output .= '' . $label . $this->render_required_sign( $is_required ) . ' ';
49 |
50 | $output .= ' ';
59 |
60 | $output .= ''
61 | . $help_text
62 | . ' ';
63 |
64 | $output .= '
';
65 | return $output;
66 | }
67 |
68 | /**
69 | * Render the required sign.
70 | *
71 | * @param bool $is_required The required status of the field.
72 | * @return string
73 | */
74 | public function render_required_sign( $is_required ) {
75 | return $is_required ? '* ' : '';
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/plugins/class-options-settings.php:
--------------------------------------------------------------------------------
1 | 'boolean',
41 | 'description' => __( 'Inherit license from Neve Pro.', 'otter-pro' ),
42 | 'show_in_rest' => true,
43 | 'default' => false,
44 | )
45 | );
46 |
47 | register_setting(
48 | 'themeisle_blocks_settings',
49 | 'otter_offload_fonts',
50 | array(
51 | 'type' => 'boolean',
52 | 'description' => __( 'Store Google Fonts Offline.', 'otter-pro' ),
53 | 'show_in_rest' => true,
54 | 'default' => true === boolval( get_option( 'nv_pro_enable_local_fonts', false ) ) ? true : false,
55 | )
56 | );
57 |
58 | register_setting(
59 | 'themeisle_blocks_settings',
60 | 'otter_iphub_api_key',
61 | array(
62 | 'type' => 'string',
63 | 'description' => __( 'IPHub API Key.', 'otter-pro' ),
64 | 'sanitize_callback' => 'sanitize_text_field',
65 | 'show_in_rest' => true,
66 | 'default' => '',
67 | )
68 | );
69 | }
70 |
71 | /**
72 | * The instance method for the static class.
73 | * Defines and returns the instance of the static class.
74 | *
75 | * @static
76 | * @since 1.2.0
77 | * @access public
78 | * @return Options_Settings
79 | */
80 | public static function instance() {
81 | if ( is_null( self::$instance ) ) {
82 | self::$instance = new self();
83 | self::$instance->init();
84 | }
85 |
86 | return self::$instance;
87 | }
88 |
89 | /**
90 | * Throw error on object clone
91 | *
92 | * The whole idea of the singleton design pattern is that there is a single
93 | * object therefore, we don't want the object to be cloned.
94 | *
95 | * @access public
96 | * @since 1.2.0
97 | * @return void
98 | */
99 | public function __clone() {
100 | // Cloning instances of the class is forbidden.
101 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
102 | }
103 |
104 | /**
105 | * Disable unserializing of the class
106 | *
107 | * @access public
108 | * @since 1.2.0
109 | * @return void
110 | */
111 | public function __wakeup() {
112 | // Unserializing instances of the class is forbidden.
113 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/assets/icons/user.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/render/class-form-stripe-block.php:
--------------------------------------------------------------------------------
1 | create_request( 'product', $attributes['product'] );
41 |
42 | if ( is_wp_error( $product ) ) {
43 | return sprintf(
44 | '',
45 | get_block_wrapper_attributes(),
46 | __( 'An error occurred! Could not retrieve product information!', 'otter-pro' ) . $this->format_error( $product )
47 | );
48 | }
49 |
50 | $details_markup = '';
51 |
52 | if ( 0 < count( $product['images'] ) ) {
53 | $details_markup .= ' ';
54 | }
55 |
56 | $price = $stripe->create_request( 'price', $attributes['price'] );
57 |
58 | if ( is_wp_error( $price ) ) {
59 | return sprintf(
60 | '',
61 | get_block_wrapper_attributes(),
62 | __( 'An error occurred! Could not retrieve the price of the product!', 'otter-pro' ) . $this->format_error( $price )
63 | );
64 | }
65 |
66 | $currency = Review_Block::get_currency( $price['currency'] );
67 | $amount = number_format( $price['unit_amount'] / 100, 2, '.', ' ' );
68 |
69 | $details_markup .= '';
70 | $details_markup .= '
' . $product['name'] . ' ';
71 | $details_markup .= '' . $currency . $amount . ' ';
72 | $details_markup .= '';
73 |
74 | $html_attributes = 'id="' . $attributes['id'] . '" ' .
75 | ( isset( $attributes['mappedName'] ) ? ( ' name="' . $attributes['mappedName'] . '"' ) : '' ) .
76 | ( isset( $attributes['fieldOptionName'] ) ? ( ' data-field-option-name="' . $attributes['fieldOptionName'] . '"' ) : '' );
77 |
78 | return sprintf(
79 | '',
80 | get_block_wrapper_attributes() . $html_attributes,
81 | $details_markup
82 | );
83 | }
84 |
85 | /**
86 | * Format the error message.
87 | *
88 | * @param \WP_Error $error The error.
89 | * @return string
90 | */
91 | private function format_error( $error ) {
92 | return defined( 'WP_DEBUG' ) && WP_DEBUG ? (
93 | '' . __( 'Error message: ', 'otter-pro' ) . ' ' . $error->get_error_message() . ' '
94 | ) : '';
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/inc/render/class-masonry-variant.php:
--------------------------------------------------------------------------------
1 | .otter-masonry .blocks-gallery-grid .blocks-gallery-item img{ width:100% }';
66 |
67 | $block_content = $style . '' . $block_content . '
';
68 |
69 | return $block_content;
70 | }
71 |
72 | return $block_content;
73 | }
74 |
75 | /**
76 | * The instance method for the static class.
77 | * Defines and returns the instance of the static class.
78 | *
79 | * @static
80 | * @since 1.7.1
81 | * @access public
82 | * @return Masonry_Variant
83 | */
84 | public static function instance() {
85 | if ( is_null( self::$instance ) ) {
86 | self::$instance = new self();
87 | self::$instance->init();
88 | }
89 |
90 | return self::$instance;
91 | }
92 |
93 | /**
94 | * Throw error on object clone
95 | *
96 | * The whole idea of the singleton design pattern is that there is a single
97 | * object therefore, we don't want the object to be cloned.
98 | *
99 | * @access public
100 | * @since 1.7.1
101 | * @return void
102 | */
103 | public function __clone() {
104 | // Cloning instances of the class is forbidden.
105 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-blocks' ), '1.0.0' );
106 | }
107 |
108 | /**
109 | * Disable unserializing of the class
110 | *
111 | * @access public
112 | * @since 1.7.1
113 | * @return void
114 | */
115 | public function __wakeup() {
116 | // Unserializing instances of the class is forbidden.
117 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-blocks' ), '1.0.0' );
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/plugins/class-stripe-pro-features.php:
--------------------------------------------------------------------------------
1 | get_session_email( $session_id );
57 | if ( ! $email ) {
58 | return;
59 | }
60 |
61 | $to = $email;
62 | $headers[] = 'Content-Type: text/html';
63 | $headers[] = 'From: ' . get_bloginfo( 'name', 'display' );
64 | $subject = $attributes['autoresponder']['subject'];
65 | $body = $attributes['autoresponder']['body'];
66 |
67 | // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.wp_mail_wp_mail
68 | if ( wp_mail( $to, $subject, $body, $headers ) ) {
69 | set_transient( $transient_key, true, WEEK_IN_SECONDS );
70 | }
71 | }
72 |
73 | /**
74 | * The instance method for the static class.
75 | * Defines and returns the instance of the static class.
76 | *
77 | * @static
78 | * @since 1.7.1
79 | * @access public
80 | * @return Stripe_Pro_Features
81 | */
82 | public static function instance() {
83 | if ( is_null( self::$instance ) ) {
84 | self::$instance = new self();
85 | self::$instance->init();
86 | }
87 |
88 | return self::$instance;
89 | }
90 |
91 | /**
92 | * Throw error on object clone
93 | *
94 | * The whole idea of the singleton design pattern is that there is a single
95 | * object therefore, we don't want the object to be cloned.
96 | *
97 | * @access public
98 | * @since 1.7.1
99 | * @return void
100 | */
101 | public function __clone() {
102 | // Cloning instances of the class is forbidden.
103 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
104 | }
105 |
106 | /**
107 | * Disable unserializing of the class
108 | *
109 | * @access public
110 | * @since 1.7.1
111 | * @return void
112 | */
113 | public function __wakeup() {
114 | // Unserializing instances of the class is forbidden.
115 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/inc/patterns/hero-area-with-button.php:
--------------------------------------------------------------------------------
1 | __( 'Hero Area with Button', 'otter-blocks' ),
10 | 'categories' => array( 'otter-blocks', 'featured', 'columns', 'header' ),
11 | 'content' => '
Pumpkins & Penguins Sed ut perspiciatis unde omnis iste natus
',
12 | );
13 |
--------------------------------------------------------------------------------
/inc/server/class-fse-onboarding-server.php:
--------------------------------------------------------------------------------
1 | namespace . $this->version;
50 |
51 | register_rest_route(
52 | $namespace,
53 | '/onboarding/templates',
54 | array(
55 | array(
56 | 'methods' => \WP_REST_Server::READABLE,
57 | 'callback' => array( $this, 'get_templates' ),
58 | 'permission_callback' => function () {
59 | return current_user_can( 'manage_options' );
60 | },
61 | ),
62 | )
63 | );
64 | }
65 |
66 | /**
67 | * List Templates.
68 | *
69 | * @param \WP_REST_Request $request The request.
70 | *
71 | * @return \WP_REST_Response
72 | * @access public
73 | */
74 | public function get_templates( \WP_REST_Request $request ) {
75 | $fse_onboarding = FSE_Onboarding::instance();
76 |
77 | $templates = $fse_onboarding->get_templates();
78 |
79 | if ( ! $templates ) {
80 | return rest_ensure_response(
81 | array(
82 | 'success' => false,
83 | 'data' => array(
84 | 'message' => __( 'Missing templates', 'otter-blocks' ),
85 | ),
86 | )
87 | );
88 | }
89 |
90 | return rest_ensure_response(
91 | array(
92 | 'success' => true,
93 | 'data' => $templates,
94 | )
95 | );
96 | }
97 |
98 | /**
99 | * The instance method for the static class.
100 | * Defines and returns the instance of the static class.
101 | *
102 | * @static
103 | * @since 1.7.0
104 | * @access public
105 | * @return FSE_Onboarding_Server
106 | */
107 | public static function instance() {
108 | if ( is_null( self::$instance ) ) {
109 | self::$instance = new self();
110 | self::$instance->init();
111 | }
112 |
113 | return self::$instance;
114 | }
115 |
116 | /**
117 | * Throw error on object clone
118 | *
119 | * The whole idea of the singleton design pattern is that there is a single
120 | * object therefore, we don't want the object to be cloned.
121 | *
122 | * @access public
123 | * @since 1.7.0
124 | * @return void
125 | */
126 | public function __clone() {
127 | // Cloning instances of the class is forbidden.
128 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-blocks' ), '1.0.0' );
129 | }
130 |
131 | /**
132 | * Disable unserializing of the class
133 | *
134 | * @access public
135 | * @since 1.7.0
136 | * @return void
137 | */
138 | public function __wakeup() {
139 | // Unserializing instances of the class is forbidden.
140 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-blocks' ), '1.0.0' );
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/plugins/class-review-woo-integration.php:
--------------------------------------------------------------------------------
1 | get_name();
49 | $attributes['description'] = $product->get_short_description();
50 | $attributes['price'] = $product->get_regular_price() ? $product->get_regular_price() : $product->get_price();
51 | $attributes['currency'] = get_woocommerce_currency();
52 |
53 | if ( ! empty( $product->get_sale_price() ) && $attributes['price'] !== $product->get_sale_price() ) {
54 | $attributes['discounted'] = $product->get_sale_price();
55 | }
56 |
57 | $attributes['image'] = array(
58 | 'id' => $product->get_image_id(),
59 | 'url' => wp_get_attachment_image_url( intval( $product->get_image_id() ), '' ),
60 | 'alt' => get_post_meta( intval( $product->get_image_id() ), '_wp_attachment_image_alt', true ),
61 | );
62 |
63 | $attributes['links'] = array(
64 | array(
65 | 'label' => __( 'Buy Now', 'otter-pro' ),
66 | 'href' => method_exists( $product, 'get_product_url' ) ? $product->get_product_url() : $product->get_permalink(),
67 | 'isSponsored' => method_exists( $product, 'get_product_url' ),
68 | ),
69 | );
70 |
71 | return $attributes;
72 | }
73 |
74 | /**
75 | * The instance method for the static class.
76 | * Defines and returns the instance of the static class.
77 | *
78 | * @static
79 | * @since 2.0.1
80 | * @access public
81 | * @return Review_Woo_Integration
82 | */
83 | public static function instance() {
84 | if ( is_null( self::$instance ) ) {
85 | self::$instance = new self();
86 | self::$instance->init();
87 | }
88 |
89 | return self::$instance;
90 | }
91 |
92 | /**
93 | * Throw error on object clone
94 | *
95 | * The whole idea of the singleton design pattern is that there is a single
96 | * object therefore, we don't want the object to be cloned.
97 | *
98 | * @access public
99 | * @since 2.0.1
100 | * @return void
101 | */
102 | public function __clone() {
103 | // Cloning instances of the class is forbidden.
104 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
105 | }
106 |
107 | /**
108 | * Disable unserializing of the class
109 | *
110 | * @access public
111 | * @since 2.0.1
112 | * @return void
113 | */
114 | public function __wakeup() {
115 | // Unserializing instances of the class is forbidden.
116 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/inc/patterns/call-to-action-5.php:
--------------------------------------------------------------------------------
1 | __( 'Call to Action', 'otter-blocks' ),
10 | 'categories' => array( 'otter-blocks', 'call-to-action' ),
11 | 'content' => '
Follow me on Social! Synergestic actionables. Organic growth deep dive but circle back or but what\'s the real problem we\'re trying to solve here?
', // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation
12 | );
13 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/plugins/class-posts-acf-integration.php:
--------------------------------------------------------------------------------
1 | ';
62 | if ( isset( $field['prepend'] ) ) {
63 | $data .= esc_html( $field['prepend'] );
64 | }
65 |
66 | if ( isset( $field['value'] ) ) {
67 | $data .= esc_html( $field['value'] );
68 | } elseif ( isset( $field['default_value'] ) ) {
69 | $data .= esc_html( $field['default_value'] );
70 | }
71 |
72 | if ( isset( $field['append'] ) ) {
73 | $data .= esc_html( $field['append'] );
74 | }
75 | $data .= '';
76 | }
77 | }
78 |
79 | return $data;
80 | }
81 |
82 | /**
83 | * The instance method for the static class.
84 | * Defines and returns the instance of the static class.
85 | *
86 | * @static
87 | * @since 2.0.1
88 | * @access public
89 | * @return Posts_ACF_Integration
90 | */
91 | public static function instance() {
92 | if ( is_null( self::$instance ) ) {
93 | self::$instance = new self();
94 | self::$instance->init();
95 | }
96 |
97 | return self::$instance;
98 | }
99 |
100 | /**
101 | * Throw error on object clone
102 | *
103 | * The whole idea of the singleton design pattern is that there is a single
104 | * object therefore, we don't want the object to be cloned.
105 | *
106 | * @access public
107 | * @since 2.0.1
108 | * @return void
109 | */
110 | public function __clone() {
111 | // Cloning instances of the class is forbidden.
112 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
113 | }
114 |
115 | /**
116 | * Disable unserializing of the class
117 | *
118 | * @access public
119 | * @since 2.0.1
120 | * @return void
121 | */
122 | public function __wakeup() {
123 | // Unserializing instances of the class is forbidden.
124 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/inc/patterns/call-to-action-4.php:
--------------------------------------------------------------------------------
1 | __( 'Call to Action', 'otter-blocks' ),
10 | 'categories' => array( 'otter-blocks', 'call-to-action' ),
11 | 'content' => '
Schedule a free consulting call with a representative ', // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation
12 | );
13 |
--------------------------------------------------------------------------------
/inc/patterns/testimonial-with-inline-image.php:
--------------------------------------------------------------------------------
1 | __( 'Testimonial with Inline Image', 'otter-blocks' ),
10 | 'categories' => array( 'otter-blocks', 'testimonials' ),
11 | 'content' => '
"...Sed ut perspiciatis unde omnis natus error sit voluptatem accusantium doloremque..."
Jason Doe
',
12 | );
13 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/css/blocks/class-business-hours-css.php:
--------------------------------------------------------------------------------
1 | add_item(
38 | array(
39 | 'properties' => array(
40 | array(
41 | 'property' => 'background-color',
42 | 'value' => 'backgroundColor',
43 | ),
44 | array(
45 | 'property' => 'border-radius',
46 | 'value' => 'borderRadius',
47 | 'unit' => 'px',
48 | ),
49 | array(
50 | 'property' => 'border-width',
51 | 'value' => 'borderWidth',
52 | 'unit' => 'px',
53 | ),
54 | array(
55 | 'property' => 'border-color',
56 | 'value' => 'borderColor',
57 | ),
58 | array(
59 | 'property' => 'border-style',
60 | 'default' => 'solid',
61 | 'condition' => function ( $attrs ) {
62 | return isset( $attrs['borderWidth'] ) && ! empty( $attrs['borderWidth'] );
63 | },
64 | ),
65 | ),
66 | )
67 | );
68 |
69 | $css->add_item(
70 | array(
71 | 'selector' => ' .otter-business-hour__container .otter-business-hour__title',
72 | 'properties' => array(
73 | array(
74 | 'property' => 'text-align',
75 | 'value' => 'titleAlignment',
76 | ),
77 | array(
78 | 'property' => 'font-size',
79 | 'value' => 'titleFontSize',
80 | 'unit' => 'px',
81 | ),
82 | array(
83 | 'property' => 'color',
84 | 'value' => 'titleColor',
85 | ),
86 | ),
87 | )
88 | );
89 |
90 | $css->add_item(
91 | array(
92 | 'selector' => ' .otter-business-hour__container .otter-business-hour__content .wp-block-themeisle-blocks-business-hours-item',
93 | 'properties' => array(
94 | array(
95 | 'property' => 'padding-top',
96 | 'value' => 'gap',
97 | 'unit' => 'px',
98 | ),
99 | array(
100 | 'property' => 'padding-bottom',
101 | 'value' => 'gap',
102 | 'unit' => 'px',
103 | ),
104 | ),
105 | )
106 | );
107 |
108 | $css->add_item(
109 | array(
110 | 'selector' => ' .otter-business-hour__container .otter-business-hour__content .wp-block-themeisle-blocks-business-hours-item .otter-business-hour-item__label',
111 | 'properties' => array(
112 | array(
113 | 'property' => 'font-size',
114 | 'value' => 'itemsFontSize',
115 | 'unit' => 'px',
116 | ),
117 | ),
118 | )
119 | );
120 |
121 | $css->add_item(
122 | array(
123 | 'selector' => ' .otter-business-hour__container .otter-business-hour__content .wp-block-themeisle-blocks-business-hours-item .otter-business-hour-item__time',
124 | 'properties' => array(
125 | array(
126 | 'property' => 'font-size',
127 | 'value' => 'itemsFontSize',
128 | 'unit' => 'px',
129 | ),
130 | ),
131 | )
132 | );
133 |
134 | $style = $css->generate();
135 |
136 | return $style;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/inc/patterns/call-to-action-3.php:
--------------------------------------------------------------------------------
1 | __( 'Call to Action', 'otter-blocks' ),
10 | 'categories' => array( 'otter-blocks', 'call-to-action' ),
11 | 'content' => '
Download my eBook for Free Follow me on social and get exclusive recipes and deals!
', // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation
12 | );
13 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/plugins/class-fonts-module.php:
--------------------------------------------------------------------------------
1 | init();
96 | }
97 |
98 | return self::$instance;
99 | }
100 |
101 | /**
102 | * Throw error on object clone
103 | *
104 | * The whole idea of the singleton design pattern is that there is a single
105 | * object therefore, we don't want the object to be cloned.
106 | *
107 | * @access public
108 | * @since 2.0.5
109 | * @return void
110 | */
111 | public function __clone() {
112 | // Cloning instances of the class is forbidden.
113 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
114 | }
115 |
116 | /**
117 | * Disable unserializing of the class
118 | *
119 | * @access public
120 | * @since 2.0.5
121 | * @return void
122 | */
123 | public function __wakeup() {
124 | // Unserializing instances of the class is forbidden.
125 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/docs/project-structure.md:
--------------------------------------------------------------------------------
1 | # The Everlasting Otter
2 |
3 | As time goes by, the project grows and evolves. The codebase becomes more complex. It's important to keep the project organized and easy to understand for everyone.
4 |
5 | ## Project structure
6 |
7 | - `docs/` contains the documentation of the project
8 | - `src/` contains the source code of the project (mainly JS & SCSS files)
9 | - `blocks/` the JS & SCSS files for Otter Blocks plugin
10 | - `components/` contains reusable components
11 | - `blocks/` blocks definition and functionality
12 | - `frontend/` script that add functionality for the end user. E.g.: opening tabs in accordion, sending form to the backend for Form Block.
13 | - `plugins/` global features: Global Defaults, Sticky Blocks, Copy & Paste Styles, Dynamic Content & Conditions
14 | - `helpers/` utility functions: Add an ID to the block, Google Fonts loader.
15 | - `test` contains the test files for the blocks
16 | - `css/` contains the CSS files for Custom CSS plugin
17 | - `animation/` contains the JS & SCSS files for Animation plugin
18 | - `dashboard/` contains the JS & SCSS files for Otter Dashboard (in WP: Tools > Otter )
19 | - `export-import/` contains the JS & SCSS files for Export/Import Block plugin
20 | - `pro/` contains the JS & SCSS files for Otter Pro plugin
21 | - `blocks/` Pro blocks source files
22 | - `components/` reusable components
23 | - `dashboard/` dashboard extension with Pro features
24 | - `helpers/` utility functions
25 | - `plugins/` Pro features for Blocks: Dynamic Content & Conditions, Sticky options, Countdown options, Live Search, etc.
26 | - `woocommerce/` WooCommerce features and extensions
27 | - `inc/` contains the PHP files for all plugins
28 | - `css/` CSS dynamic generator for Blocks. It's used to generate the CSS for the blocks based on the user settings.
29 | - `integration/` Form Block utilities
30 | - `patterns/` contains the patterns for the Pattern Library
31 | - `plugins/` plugins functionality: Dynamic Content & Conditions, Stripe, WordPress Options definitions for Rest API, etc.
32 | - `render/` render classes for dynamic blocks (e.g.: Form File Field, Google/Leaflet Map, Plugin Card, Stripe Checkout, etc.)
33 | - `server/` WP REST API endpoints: Form Block, Dynamic Content & Conditions, Stripe, etc.
34 | - `plugins/` contains PHP files for other plugins
35 | - `blocks-css/` Custom CSS plugin
36 | - `blocks-animation/` Animation plugin
37 | - `blocks-export-import/` Export/Import Block plugin
38 | - `otter-pro/` Otter Pro plugin
39 | - `css/` CSS dynamic generator for Pro blocks
40 | - `plugins/` Pro features for Blocks: Dynamic Content & Conditions, Sticky options, Countdown options, Live Search, etc.
41 | - `render/` render classes for dynamic blocks: WooCommerce
42 | - `server/` WP REST API endpoints: Live Search
43 |
44 | ## Tips on navigation
45 |
46 | If you are working on Form block: `./src/blocks/blocks/form/`, `./inc/integrations/` and `./inc/server/class-form-server.php` are the main hot spots.
47 |
48 | Dealing with the CSS generation? `./inc/css/` are the main files.
49 |
50 | PHP loading related issues: `./inc/class-registration.php` is the main file.
51 |
52 | Add PHP functionality only for Otter Pro: `./plugins/otter-pro/` is the main folder.
53 |
54 | JS is not working on frontend for a block: `./src/blocks/frontend/`
55 |
56 | Add a new tab in Global Default interface for a block: `./src/blocks/plugins/options/global-defaults/controls`
57 |
58 | Add a new options in WordPress Options Settings: `./inc/plugins/class-options-settings.php`
59 |
60 | When you make a PHP file and don't know where to hook it up (make it visible to others) look at how similar file do it. API Endpoint? `./inc/server/`. CSS Generator? `./inc/css/`. Dynamic block rendering? `./inc/render/`.
--------------------------------------------------------------------------------
/assets/icons/woo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/inc/patterns/image-and-text-over-dark-background.php:
--------------------------------------------------------------------------------
1 | __( 'Image and Text over Dark Background', 'otter-blocks' ),
10 | 'categories' => array( 'otter-blocks', 'featured', 'columns' ),
11 | 'content' => '
Overline
Section with image Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta.
',
12 | );
13 |
--------------------------------------------------------------------------------
/plugins/otter-pro/inc/server/class-posts-acf-server.php:
--------------------------------------------------------------------------------
1 | namespace . $this->version;
50 |
51 | register_rest_route(
52 | $namespace,
53 | '/acf-fields',
54 | array(
55 | array(
56 | 'methods' => \WP_REST_Server::READABLE,
57 | 'callback' => array( $this, 'get_acf_fields' ),
58 | 'permission_callback' => function () {
59 | return current_user_can( 'edit_posts' );
60 | },
61 | ),
62 | )
63 | );
64 | }
65 |
66 | /**
67 | * Get the ACF data about custom meta fields.
68 | *
69 | * @param mixed $request Rest request.
70 | * @since 1.7.6
71 | * @return mixed|\WP_REST_Response
72 | */
73 | public function get_acf_fields( $request ) {
74 | $return = array(
75 | 'success' => false,
76 | );
77 |
78 | if ( ! ( function_exists( 'acf_get_field_groups' ) && function_exists( 'acf_get_fields' ) ) ) {
79 | $return['error'] = esc_html__( 'ACF is not installed!', 'otter-pro' );
80 | $return['eror_code'] = 1;
81 | return rest_ensure_response( $return );
82 | }
83 |
84 | $return['groups'] = array();
85 | $groups = acf_get_field_groups();
86 |
87 | foreach ( $groups as $group ) {
88 | $group_data = array(
89 | 'data' => $group,
90 | 'fields' => array(),
91 | );
92 |
93 | $fields = acf_get_fields( $group );
94 |
95 | foreach ( $fields as $field ) {
96 | array_push( $group_data['fields'], $field );
97 | }
98 | array_push( $return['groups'], $group_data );
99 | }
100 |
101 | $return['success'] = true;
102 | return rest_ensure_response( $return );
103 | }
104 |
105 | /**
106 | * The instance method for the static class.
107 | * Defines and returns the instance of the static class.
108 | *
109 | * @static
110 | * @since 1.0.0
111 | * @access public
112 | * @return Posts_ACF_Server
113 | */
114 | public static function instance() {
115 | if ( is_null( self::$instance ) ) {
116 | self::$instance = new self();
117 | self::$instance->init();
118 | }
119 |
120 | return self::$instance;
121 | }
122 |
123 | /**
124 | * Throw error on object clone
125 | *
126 | * The whole idea of the singleton design pattern is that there is a single
127 | * object therefore, we don't want the object to be cloned.
128 | *
129 | * @access public
130 | * @since 1.0.0
131 | * @return void
132 | */
133 | public function __clone() {
134 | // Cloning instances of the class is forbidden.
135 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
136 | }
137 |
138 | /**
139 | * Disable unserializing of the class
140 | *
141 | * @access public
142 | * @since 1.0.0
143 | * @return void
144 | */
145 | public function __wakeup() {
146 | // Unserializing instances of the class is forbidden.
147 | _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'otter-pro' ), '1.0.0' );
148 | }
149 | }
150 |
--------------------------------------------------------------------------------