diff --git a/.github/workflows/plugin-check.yml b/.github/workflows/plugin-check.yml deleted file mode 100644 index f07af1cdc..000000000 --- a/.github/workflows/plugin-check.yml +++ /dev/null @@ -1,232 +0,0 @@ -name: WordPress Plugin Check - -on: - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} - cancel-in-progress: true - -permissions: - contents: read - -jobs: - plugin-check: - name: WordPress.org Guidelines Check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - name: Neutralize wp-env override - run: | - echo '{}' > .wp-env.override.json - - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: 20 - cache: 'npm' - - - name: Install npm dependencies - run: npm ci - - - name: Build assets - run: npm run build - - - name: Install Composer dependencies - run: composer install --no-dev --optimize-autoloader - - - uses: wordpress/plugin-check-action@v1 - id: plugin-check - with: - categories: plugin_repo,security,general - exclude-directories: | - node_modules - vendor - build - tests - bin - .github - ignore-codes: | - WordPress.WP.I18n.TextDomainMismatch - textdomain_mismatch - hidden_files - WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound - WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound - WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound - WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound - WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound - WordPress.PHP.DevelopmentFunctions.error_log_trigger_error - WordPress.WP.EnqueuedResourceParameters.MissingVersion - include-experimental: true - repo-token: '' - - - name: Plugin Check Summary - if: always() - env: - RESULTS_FILE: ${{ runner.temp }}/plugin-check-results.txt - run: | - echo "## WordPress Plugin Check Results" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - if [ ! -s "$RESULTS_FILE" ]; then - echo "No results file found or file is empty." >> $GITHUB_STEP_SUMMARY - echo "Check the action logs for details." >> $GITHUB_STEP_SUMMARY - exit 0 - fi - - PARSED=$(RESULTS_FILE="$RESULTS_FILE" python3 << 'PYEOF' - import json, os, re - - results_path = os.environ["RESULTS_FILE"] - - high_risk_codes = [ - "plugin_updater", "code_obfuscation", "no_unfiltered_uploads", - "trademarked_term", "trademarks" - ] - high_risk_messages = [ - r"Plugin Updater detected", r"Missing.*License.*Plugin Header", - r"restricted term", r"Unescaped parameter.*\$wpdb", - r"Use placeholders and.*\$wpdb->prepare" - ] - medium_risk_codes = [ - "missing_direct_file_access_protection", "trunk_stable_tag", - "mismatched_plugin_name", "application_detected" - ] - medium_risk_messages = [ - r"Missing.*\$domain.*parameter", r"has been deprecated", - r"wp_get_sites", r"cURL functions is highly discouraged" - ] - - high, medium, other = [], [], [] - - try: - with open(results_path, "r") as f: - content = f.read().strip() - - all_issues = [] - try: - data = json.loads(content) - if isinstance(data, list): - all_issues = data - elif isinstance(data, dict): - for fp, issues in data.items(): - if isinstance(issues, list): - for issue in issues: - issue['_file'] = fp - all_issues.append(issue) - except json.JSONDecodeError: - for line in content.split('\n'): - line = line.strip() - if not line: - continue - try: - parsed = json.loads(line) - if isinstance(parsed, list): - all_issues.extend(parsed) - elif isinstance(parsed, dict): - all_issues.append(parsed) - except json.JSONDecodeError: - continue - - for issue in all_issues: - code = issue.get('code', '') - msg = issue.get('message', '') - itype = issue.get('type', 'ERROR') - line_num = issue.get('line', 0) - file_path = issue.get('_file', '') - - prefix = "❌" if itype == "ERROR" else "⚠️" - location = "" - if file_path: - location = f" ({file_path}" - if line_num and line_num > 0: - location += f", line {line_num}" - location += ")" - elif line_num and line_num > 0: - location = f" (line {line_num})" - - readable = f"{prefix} {msg}{location}" - - is_high = code in high_risk_codes - if not is_high: - for p in high_risk_messages: - if re.search(p, msg, re.IGNORECASE): - is_high = True - break - - is_medium = code in medium_risk_codes - if not is_medium and not is_high: - for p in medium_risk_messages: - if re.search(p, msg, re.IGNORECASE): - is_medium = True - break - - if is_high: - high.append(readable) - elif is_medium: - medium.append(readable) - else: - other.append(readable) - - def dedup(lst): - seen = set() - result = [] - for item in lst: - if item not in seen: - seen.add(item) - result.append(item) - return result - - high, medium, other = dedup(high), dedup(medium), dedup(other) - - print("---HIGH---") - for i in high: print(i) - print("---MEDIUM---") - for i in medium: print(i) - print("---OTHER---") - for i in other: print(i) - print("---COUNTS---") - print(f"{len(high)}|{len(medium)}|{len(other)}") - - except Exception as e: - print(f"Parse error: {e}", file=__import__('sys').stderr) - print("---HIGH---\n---MEDIUM---\n---OTHER---\n---COUNTS---\n0|0|0") - PYEOF - ) - - HIGH_SECTION=$(echo "$PARSED" | sed -n '/^---HIGH---$/,/^---MEDIUM---$/p' | sed '1d;$d') - MEDIUM_SECTION=$(echo "$PARSED" | sed -n '/^---MEDIUM---$/,/^---OTHER---$/p' | sed '1d;$d') - OTHER_SECTION=$(echo "$PARSED" | sed -n '/^---OTHER---$/,/^---COUNTS---$/p' | sed '1d;$d') - COUNTS=$(echo "$PARSED" | tail -1) - OTHER_COUNT=$(echo "$COUNTS" | cut -d'|' -f3) - - echo "### 🚨 HIGH RISK — Can cause plugin closure or suspension" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - if [ -n "$HIGH_SECTION" ]; then - echo "$HIGH_SECTION" >> $GITHUB_STEP_SUMMARY - else - echo "✅ No high-risk issues found." >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - - echo "### ⚠️ MEDIUM RISK — Commonly flagged in wordpress.org reviews" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - if [ -n "$MEDIUM_SECTION" ]; then - echo "$MEDIUM_SECTION" >> $GITHUB_STEP_SUMMARY - else - echo "✅ No medium-risk issues found." >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - - echo "
" >> $GITHUB_STEP_SUMMARY - echo "📋 Other issues ($OTHER_COUNT) — click to expand" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - if [ -n "$OTHER_SECTION" ]; then - echo "$OTHER_SECTION" >> $GITHUB_STEP_SUMMARY - else - echo "No other issues." >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY - echo "
" >> $GITHUB_STEP_SUMMARY diff --git a/.wp-env.json b/.wp-env.json index ecc59bbe2..59e766d46 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -17,7 +17,8 @@ }, "mappings": { "wp-content/mu-plugins": "./packages/e2e-tests/mu-plugins", - "wp-content/themes/raft": "https://downloads.wordpress.org/theme/raft.zip" + "wp-content/themes/raft": "https://downloads.wordpress.org/theme/raft.zip", + "wp-content/plugins/woocommerce": "./vendor/wp-content/plugins/woocommerce" }, "lifecycleScripts": { "afterStart": "bash bin/e2e-tests.sh" diff --git a/development.php b/development.php index 689bd8b70..507b2de82 100644 --- a/development.php +++ b/development.php @@ -7,6 +7,10 @@ // phpcs:ignoreFile +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + if ( ! defined( 'ENABLE_OTTER_PRO_DEV' ) ) { define( 'ENABLE_OTTER_PRO_DEV', true ); } diff --git a/inc/patterns/aw-bento-features.php b/inc/patterns/aw-bento-features.php index 4eed6391f..403dae985 100644 --- a/inc/patterns/aw-bento-features.php +++ b/inc/patterns/aw-bento-features.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Bento Feature Grid', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'features' ), diff --git a/inc/patterns/aw-blog-cards.php b/inc/patterns/aw-blog-cards.php index 434ef3fbf..237ce0258 100644 --- a/inc/patterns/aw-blog-cards.php +++ b/inc/patterns/aw-blog-cards.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Blog Post Cards', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'blog' ), diff --git a/inc/patterns/aw-case-study-metrics.php b/inc/patterns/aw-case-study-metrics.php index 780e7ae81..a041d2afa 100644 --- a/inc/patterns/aw-case-study-metrics.php +++ b/inc/patterns/aw-case-study-metrics.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Case Study With Metrics', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'portfolio' ), diff --git a/inc/patterns/aw-cta-banner.php b/inc/patterns/aw-cta-banner.php index d6e1bf484..7adc9f41f 100644 --- a/inc/patterns/aw-cta-banner.php +++ b/inc/patterns/aw-cta-banner.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'CTA Banner', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'call-to-action' ), diff --git a/inc/patterns/aw-faq-cards.php b/inc/patterns/aw-faq-cards.php index 61354fdf8..3fa2ffc6a 100644 --- a/inc/patterns/aw-faq-cards.php +++ b/inc/patterns/aw-faq-cards.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'FAQ Cards', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'faq' ), diff --git a/inc/patterns/aw-feature-cards.php b/inc/patterns/aw-feature-cards.php index 88889096e..5b1096301 100644 --- a/inc/patterns/aw-feature-cards.php +++ b/inc/patterns/aw-feature-cards.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Feature Cards', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'features' ), diff --git a/inc/patterns/aw-feature-split.php b/inc/patterns/aw-feature-split.php index 94f2a6369..b0272e2dc 100644 --- a/inc/patterns/aw-feature-split.php +++ b/inc/patterns/aw-feature-split.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Feature Split', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'features' ), diff --git a/inc/patterns/aw-gallery-grid.php b/inc/patterns/aw-gallery-grid.php index 6a55a4cc5..6597e8260 100644 --- a/inc/patterns/aw-gallery-grid.php +++ b/inc/patterns/aw-gallery-grid.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Gallery Masonry Grid', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'gallery' ), diff --git a/inc/patterns/aw-glow-cta.php b/inc/patterns/aw-glow-cta.php index ca0ccd48d..5506fa3cf 100644 --- a/inc/patterns/aw-glow-cta.php +++ b/inc/patterns/aw-glow-cta.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Glow CTA', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'call-to-action' ), diff --git a/inc/patterns/aw-hero-centered.php b/inc/patterns/aw-hero-centered.php index 981eedd53..df9a5e585 100644 --- a/inc/patterns/aw-hero-centered.php +++ b/inc/patterns/aw-hero-centered.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Centered Hero', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'header' ), diff --git a/inc/patterns/aw-hero-split.php b/inc/patterns/aw-hero-split.php index f9429b104..913b10b09 100644 --- a/inc/patterns/aw-hero-split.php +++ b/inc/patterns/aw-hero-split.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Split Hero', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'header' ), diff --git a/inc/patterns/aw-icon-grid.php b/inc/patterns/aw-icon-grid.php index 51f62372e..96e8b748e 100644 --- a/inc/patterns/aw-icon-grid.php +++ b/inc/patterns/aw-icon-grid.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Icon Feature Grid', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'icons' ), diff --git a/inc/patterns/aw-portfolio-grid.php b/inc/patterns/aw-portfolio-grid.php index c9a4bba75..83c095313 100644 --- a/inc/patterns/aw-portfolio-grid.php +++ b/inc/patterns/aw-portfolio-grid.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Portfolio Showcase Grid', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'portfolio' ), diff --git a/inc/patterns/aw-pricing-tiers.php b/inc/patterns/aw-pricing-tiers.php index a083ff481..609d2d4ed 100644 --- a/inc/patterns/aw-pricing-tiers.php +++ b/inc/patterns/aw-pricing-tiers.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Pricing Tiers', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pricing' ), diff --git a/inc/patterns/aw-quote-spotlight.php b/inc/patterns/aw-quote-spotlight.php index a03f899d9..4dc98480a 100644 --- a/inc/patterns/aw-quote-spotlight.php +++ b/inc/patterns/aw-quote-spotlight.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Spotlight Quote', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'testimonials' ), diff --git a/inc/patterns/aw-review-stars.php b/inc/patterns/aw-review-stars.php index a14169b97..b5419bf1e 100644 --- a/inc/patterns/aw-review-stars.php +++ b/inc/patterns/aw-review-stars.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Star Rating Reviews', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'testimonials' ), diff --git a/inc/patterns/aw-stats-banner.php b/inc/patterns/aw-stats-banner.php index 88f64dd8c..af32a5747 100644 --- a/inc/patterns/aw-stats-banner.php +++ b/inc/patterns/aw-stats-banner.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Gradient Stats Banner', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'stats' ), diff --git a/inc/patterns/aw-team-grid.php b/inc/patterns/aw-team-grid.php index 8ae6e45ad..cff82df04 100644 --- a/inc/patterns/aw-team-grid.php +++ b/inc/patterns/aw-team-grid.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Team Grid with Hover Effect', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'team' ), diff --git a/inc/patterns/aw-testimonial-cards.php b/inc/patterns/aw-testimonial-cards.php index ee7820236..7ad93b2ed 100644 --- a/inc/patterns/aw-testimonial-cards.php +++ b/inc/patterns/aw-testimonial-cards.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Testimonial Cards', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'testimonials' ), diff --git a/inc/patterns/aw-timeline-steps.php b/inc/patterns/aw-timeline-steps.php index f150a509b..56d01b2a9 100644 --- a/inc/patterns/aw-timeline-steps.php +++ b/inc/patterns/aw-timeline-steps.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Timeline Steps', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'timeline' ), diff --git a/inc/patterns/aw-video-feature.php b/inc/patterns/aw-video-feature.php index acb5685d4..719659acb 100644 --- a/inc/patterns/aw-video-feature.php +++ b/inc/patterns/aw-video-feature.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Video Feature', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'video' ), diff --git a/inc/patterns/blog-featured-list.php b/inc/patterns/blog-featured-list.php index 6462781b5..3ff7d35e2 100644 --- a/inc/patterns/blog-featured-list.php +++ b/inc/patterns/blog-featured-list.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Blog Featured & List', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'blog' ), diff --git a/inc/patterns/bold-image-hero.php b/inc/patterns/bold-image-hero.php index 69d2fb937..5d0abbe4f 100644 --- a/inc/patterns/bold-image-hero.php +++ b/inc/patterns/bold-image-hero.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Bold Image Hero', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'header' ), diff --git a/inc/patterns/cafe-about.php b/inc/patterns/cafe-about.php index d44456748..feadb3b31 100644 --- a/inc/patterns/cafe-about.php +++ b/inc/patterns/cafe-about.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Cafe - About', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'cafe-pack' ), diff --git a/inc/patterns/cafe-contact.php b/inc/patterns/cafe-contact.php index 1f7fbcd2c..d44d247f6 100644 --- a/inc/patterns/cafe-contact.php +++ b/inc/patterns/cafe-contact.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Cafe - Contact', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'cafe-pack' ), diff --git a/inc/patterns/cafe-homepage.php b/inc/patterns/cafe-homepage.php index d4aa9e133..98ea5db3e 100644 --- a/inc/patterns/cafe-homepage.php +++ b/inc/patterns/cafe-homepage.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Cafe - Homepage', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'cafe-pack' ), diff --git a/inc/patterns/cafe-menu.php b/inc/patterns/cafe-menu.php index b9d2a04fc..c2539a1c5 100644 --- a/inc/patterns/cafe-menu.php +++ b/inc/patterns/cafe-menu.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Cafe - Menu', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'cafe-pack' ), diff --git a/inc/patterns/contact-form-split.php b/inc/patterns/contact-form-split.php index 49824d65c..cd70db049 100644 --- a/inc/patterns/contact-form-split.php +++ b/inc/patterns/contact-form-split.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Contact Form with Details', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'contact' ), diff --git a/inc/patterns/contact-info-cards.php b/inc/patterns/contact-info-cards.php index a7736ca4d..a2101d527 100644 --- a/inc/patterns/contact-info-cards.php +++ b/inc/patterns/contact-info-cards.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Contact Info Cards', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'contact' ), diff --git a/inc/patterns/content-checklist.php b/inc/patterns/content-checklist.php index 7bd7eabe0..759130c17 100644 --- a/inc/patterns/content-checklist.php +++ b/inc/patterns/content-checklist.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Content with Checklist', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'text' ), diff --git a/inc/patterns/countdown-launch.php b/inc/patterns/countdown-launch.php index c55eb03e9..ef5591ab3 100644 --- a/inc/patterns/countdown-launch.php +++ b/inc/patterns/countdown-launch.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Launch Countdown', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'waitlist' ), diff --git a/inc/patterns/dark-cta-band.php b/inc/patterns/dark-cta-band.php index 869ab409a..4dad6ca05 100644 --- a/inc/patterns/dark-cta-band.php +++ b/inc/patterns/dark-cta-band.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Indigo CTA Band', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'call-to-action' ), diff --git a/inc/patterns/faq-boxed-list.php b/inc/patterns/faq-boxed-list.php index 3ef4cc149..55a284dda 100644 --- a/inc/patterns/faq-boxed-list.php +++ b/inc/patterns/faq-boxed-list.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'FAQ Boxed List', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'faq' ), diff --git a/inc/patterns/faq-two-column.php b/inc/patterns/faq-two-column.php index 66f71817f..17743dff7 100644 --- a/inc/patterns/faq-two-column.php +++ b/inc/patterns/faq-two-column.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'FAQ Two Column', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'faq' ), diff --git a/inc/patterns/form-glow-card.php b/inc/patterns/form-glow-card.php index 03ca59e4e..b13272ade 100644 --- a/inc/patterns/form-glow-card.php +++ b/inc/patterns/form-glow-card.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Get Access Form on Dark', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'forms' ), diff --git a/inc/patterns/form-gradient-split.php b/inc/patterns/form-gradient-split.php index 6811ee13a..26341167d 100644 --- a/inc/patterns/form-gradient-split.php +++ b/inc/patterns/form-gradient-split.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Contact Form with Gradient Panel', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'forms' ), diff --git a/inc/patterns/gallery-feature-split.php b/inc/patterns/gallery-feature-split.php index 6ba9c8027..93c9c9b0e 100644 --- a/inc/patterns/gallery-feature-split.php +++ b/inc/patterns/gallery-feature-split.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Gallery Feature Split', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'gallery' ), diff --git a/inc/patterns/gallery-overlay-grid.php b/inc/patterns/gallery-overlay-grid.php index df580ff7c..dfb226af7 100644 --- a/inc/patterns/gallery-overlay-grid.php +++ b/inc/patterns/gallery-overlay-grid.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Gallery Overlay Grid', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'gallery' ), diff --git a/inc/patterns/icon-feature-trio.php b/inc/patterns/icon-feature-trio.php index 5b9df7993..16aedfef6 100644 --- a/inc/patterns/icon-feature-trio.php +++ b/inc/patterns/icon-feature-trio.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Icon Feature Trio', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'icons' ), diff --git a/inc/patterns/icon-grid-bordered.php b/inc/patterns/icon-grid-bordered.php index 4ea29c5eb..dec44f972 100644 --- a/inc/patterns/icon-grid-bordered.php +++ b/inc/patterns/icon-grid-bordered.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Bordered Icon Grid', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'icons' ), diff --git a/inc/patterns/maps-location.php b/inc/patterns/maps-location.php index 6ba0d5970..5d9eefafa 100644 --- a/inc/patterns/maps-location.php +++ b/inc/patterns/maps-location.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Map And Location Details', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'contact' ), diff --git a/inc/patterns/newsletter-inline-bar.php b/inc/patterns/newsletter-inline-bar.php index ee2fad32f..828b217eb 100644 --- a/inc/patterns/newsletter-inline-bar.php +++ b/inc/patterns/newsletter-inline-bar.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Newsletter Inline Bar', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'newsletter' ), diff --git a/inc/patterns/newsletter-signup.php b/inc/patterns/newsletter-signup.php index d2497f6a4..7de3cb5d8 100644 --- a/inc/patterns/newsletter-signup.php +++ b/inc/patterns/newsletter-signup.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Newsletter Signup', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'newsletter' ), diff --git a/inc/patterns/portfolio-overlay-grid.php b/inc/patterns/portfolio-overlay-grid.php index df5d482c5..dc04881eb 100644 --- a/inc/patterns/portfolio-overlay-grid.php +++ b/inc/patterns/portfolio-overlay-grid.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Portfolio Overlay Grid', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'portfolio' ), diff --git a/inc/patterns/pricing-columns.php b/inc/patterns/pricing-columns.php index fe20c4a89..c01922a38 100644 --- a/inc/patterns/pricing-columns.php +++ b/inc/patterns/pricing-columns.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Pricing Columns', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pricing' ), diff --git a/inc/patterns/pricing-compare-simple.php b/inc/patterns/pricing-compare-simple.php index 8939e3326..c10e53d56 100644 --- a/inc/patterns/pricing-compare-simple.php +++ b/inc/patterns/pricing-compare-simple.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Simple Pricing Comparison', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pricing' ), diff --git a/inc/patterns/stats-row.php b/inc/patterns/stats-row.php index 1c9209c9f..d57f427c9 100644 --- a/inc/patterns/stats-row.php +++ b/inc/patterns/stats-row.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Stats Row', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'stats' ), diff --git a/inc/patterns/team-cards.php b/inc/patterns/team-cards.php index 873d5a3dd..eec97ece0 100644 --- a/inc/patterns/team-cards.php +++ b/inc/patterns/team-cards.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Team Cards', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'team' ), diff --git a/inc/patterns/team-spotlight-lead.php b/inc/patterns/team-spotlight-lead.php index b6476f1cf..85b1306fa 100644 --- a/inc/patterns/team-spotlight-lead.php +++ b/inc/patterns/team-spotlight-lead.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Team Spotlight Lead', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'team' ), diff --git a/inc/patterns/text-lead-statement.php b/inc/patterns/text-lead-statement.php index 908134b8f..72ad6c402 100644 --- a/inc/patterns/text-lead-statement.php +++ b/inc/patterns/text-lead-statement.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Text Lead Statement', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'text' ), diff --git a/inc/patterns/text-two-column-prose.php b/inc/patterns/text-two-column-prose.php index ec87f5fd4..b74059e14 100644 --- a/inc/patterns/text-two-column-prose.php +++ b/inc/patterns/text-two-column-prose.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Text Two Column Prose', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'text' ), diff --git a/inc/patterns/timeline-horizontal.php b/inc/patterns/timeline-horizontal.php index 6df8199ec..c186d1038 100644 --- a/inc/patterns/timeline-horizontal.php +++ b/inc/patterns/timeline-horizontal.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Horizontal Timeline', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'timeline' ), diff --git a/inc/patterns/travel-about.php b/inc/patterns/travel-about.php index 5597a9e87..c70d269f1 100644 --- a/inc/patterns/travel-about.php +++ b/inc/patterns/travel-about.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Travel - About', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'travel-pack' ), diff --git a/inc/patterns/travel-contact.php b/inc/patterns/travel-contact.php index 424ccdf0a..8bac4d770 100644 --- a/inc/patterns/travel-contact.php +++ b/inc/patterns/travel-contact.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Travel - Contact', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'travel-pack' ), diff --git a/inc/patterns/travel-homepage.php b/inc/patterns/travel-homepage.php index 2051e7c3f..c857818f9 100644 --- a/inc/patterns/travel-homepage.php +++ b/inc/patterns/travel-homepage.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Travel - Homepage', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'travel-pack' ), diff --git a/inc/patterns/travel-tours.php b/inc/patterns/travel-tours.php index 68ac18ff7..f41718162 100644 --- a/inc/patterns/travel-tours.php +++ b/inc/patterns/travel-tours.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Travel - Tours', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'travel-pack' ), diff --git a/inc/patterns/video-hero-play.php b/inc/patterns/video-hero-play.php index 1d5362c9c..93e18b136 100644 --- a/inc/patterns/video-hero-play.php +++ b/inc/patterns/video-hero-play.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Video Hero With Play', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'video' ), diff --git a/inc/patterns/waitlist-coming-soon.php b/inc/patterns/waitlist-coming-soon.php index cb30e0944..91c50b636 100644 --- a/inc/patterns/waitlist-coming-soon.php +++ b/inc/patterns/waitlist-coming-soon.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Coming Soon Waitlist', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'waitlist' ), diff --git a/inc/patterns/wellness-classes.php b/inc/patterns/wellness-classes.php index 7b6f5f4e6..d38c962a4 100644 --- a/inc/patterns/wellness-classes.php +++ b/inc/patterns/wellness-classes.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Wellness - Classes', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'wellness-pack' ), diff --git a/inc/patterns/wellness-contact.php b/inc/patterns/wellness-contact.php index 412e25ceb..9618d86ff 100644 --- a/inc/patterns/wellness-contact.php +++ b/inc/patterns/wellness-contact.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Wellness - Contact', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'wellness-pack' ), diff --git a/inc/patterns/wellness-homepage.php b/inc/patterns/wellness-homepage.php index 676186b7a..60dd147f3 100644 --- a/inc/patterns/wellness-homepage.php +++ b/inc/patterns/wellness-homepage.php @@ -5,6 +5,10 @@ * @package ThemeIsle */ +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + return array( 'title' => __( 'Wellness - Homepage', 'otter-blocks' ), 'categories' => array( 'otter-blocks', 'pages', 'wellness-pack' ), diff --git a/inc/plugins/class-atomic-wind-blocks.php b/inc/plugins/class-atomic-wind-blocks.php index 9f99f4746..4f5e89822 100644 --- a/inc/plugins/class-atomic-wind-blocks.php +++ b/inc/plugins/class-atomic-wind-blocks.php @@ -482,8 +482,8 @@ private function render_css_warm_page_html( \WP_Post $post_obj ) { $html .= ''; $html .= $content; $html .= ''; - $html .= ''; - $html .= ''; + $html .= ''; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- standalone iframe document, not a WordPress page. + $html .= ''; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- standalone iframe document, not a WordPress page. $html .= ''; $html .= ''; diff --git a/inc/server/class-dynamic-content-server.php b/inc/server/class-dynamic-content-server.php index 9864b2e46..034365805 100644 --- a/inc/server/class-dynamic-content-server.php +++ b/inc/server/class-dynamic-content-server.php @@ -261,7 +261,7 @@ public function get( $request ) { if ( $size = @getimagesize( $path ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure ob_start(); - readfile( $path ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile + readfile( $path ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile, WordPress.WP.AlternativeFunctions.file_system_operations_readfile $output = ob_get_contents(); if ( ! empty( $size['mime'] ) ) { @@ -271,7 +271,7 @@ public function get( $request ) { } ob_start(); - readfile( $path ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile + readfile( $path ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile, WordPress.WP.AlternativeFunctions.file_system_operations_readfile $output = ob_get_contents(); if ( isset( $size['mime'] ) ) { diff --git a/src/blocks/test/e2e/blocks/woocommerce-builder.spec.js b/src/blocks/test/e2e/blocks/woocommerce-builder.spec.js new file mode 100644 index 000000000..dfe164e19 --- /dev/null +++ b/src/blocks/test/e2e/blocks/woocommerce-builder.spec.js @@ -0,0 +1,108 @@ +/** + * WordPress dependencies + */ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; + +/** + * External dependencies + */ +import { execSync } from 'child_process'; + +/** + * E2E coverage for the `WooCommerce Builder by Otter` integration (issue #2822). + * + * The Otter metabox hooks into the product edit screen and lets merchants + * toggle the builder. Enabling it stores the `_themeisle_gutenberg_woo_builder` + * meta, and `WooCommerce_Builder::enable_block_editor()` then routes the product + * into the block editor. These tests verify the hooking is wired correctly and + * that the Otter elements show up in the metabox for the WooCommerce Builder. + */ + +const runWpCli = ( command ) => execSync( `npx wp-env run cli -- ${ command }`, { encoding: 'utf8' }); + +const tryRunWpCli = ( command ) => { + try { + return runWpCli( command ); + } catch ( error ) { + return ''; + } +}; + +// Reports whether a post meta key exists without leaking WP-CLI failures: +// runWpCli() propagates infrastructure errors, and the eval always prints 0/1. +const postMetaExists = ( postId, key ) => + runWpCli( `wp eval "echo metadata_exists( 'post', ${ postId }, '${ key }' ) ? 1 : 0;"` ).trim(); + +const createProduct = ( title ) => { + const output = runWpCli( `wp post create --post_type=product --post_status=publish --post_title="${ title }" --porcelain` ); + const match = output.match( /^\s*(\d+)\s*$/m ); + return Number( match[ 1 ]); +}; + +test.describe( 'WooCommerce Builder product editing (issue #2822)', () => { + let productId; + + test.beforeAll( () => { + + // WooCommerce is mounted by wp-env but only activated for this spec — + // the rest of the suite runs without it, as its editor integrations + // change load behavior for every other test. Serial project only. + runWpCli( 'wp plugin activate woocommerce' ); + + // Prevent the WooCommerce activation redirect from hijacking admin page loads. + tryRunWpCli( 'wp transient delete _wc_activation_redirect' ); + }); + + test.afterAll( () => { + tryRunWpCli( 'wp plugin deactivate woocommerce' ); + }); + + test.beforeEach( async({}, testInfo ) => { + productId = createProduct( `Woo Builder ${ testInfo.workerIndex }-${ testInfo.retry }-${ Date.now() }` ); + }); + + test.afterEach( () => { + tryRunWpCli( `wp post delete ${ productId } --force` ); + }); + + test( 'the Otter metabox hooks into the product edit screen with the enable toggle', async({ admin, page }) => { + await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit` ); + + // The license is stubbed as active in e2e, so the Otter metabox must render. + await expect( page.locator( '#otter_woo_builder' ) ).toBeVisible(); + await expect( page.locator( 'a#otter-woo-builder' ) ).toHaveText( /Enable WooCommerce Builder/ ); + }); + + test( 'enabling the builder persists the flag and shows the disable toggle', async({ admin, page }) => { + await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit` ); + await page.locator( 'a#otter-woo-builder' ).click({ timeout: 120000 }); + await page.waitForLoadState( 'domcontentloaded', { timeout: 120000 }); + + // The toggle must persist the builder flag server-side. + expect( runWpCli( `wp post meta get ${ productId } _themeisle_gutenberg_woo_builder` ) ).toContain( '1' ); + + // Re-open the edit screen the way a merchant would after the toggle. + await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit` ); + + // The builder must actually route the product into the block editor. + await expect( page.locator( 'body.block-editor-page' ) ).toBeVisible(); + + // The Otter metabox stays hooked in and now offers the disable toggle. + await expect( page.locator( '#otter_woo_builder' ) ).toBeVisible(); + await expect( page.locator( 'a#otter-woo-builder' ) ).toHaveText( /Disable WooCommerce Builder/ ); + }); + + test( 'disabling the builder removes the flag and restores the enable toggle', async({ admin, page }) => { + + // Enable, then disable through the same query-arg toggle the metabox buttons use. + await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit&otter-woo-builder=1` ); + await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit&otter-woo-builder=0` ); + + expect( postMetaExists( productId, '_themeisle_gutenberg_woo_builder' ) ).toBe( '0' ); + + await admin.visitAdminPage( 'post.php', `post=${ productId }&action=edit` ); + + await expect( page.locator( '#otter_woo_builder' ) ).toBeVisible(); + await expect( page.locator( 'a#otter-woo-builder' ) ).toHaveText( /Enable WooCommerce Builder/ ); + }); +}); diff --git a/src/blocks/test/e2e/playwright.config.js b/src/blocks/test/e2e/playwright.config.js index cac9dd4c7..5ddba014d 100644 --- a/src/blocks/test/e2e/playwright.config.js +++ b/src/blocks/test/e2e/playwright.config.js @@ -57,7 +57,10 @@ const SERIAL_SPECS = [ '**/blocks/design-library.spec.js', // Flips the site-wide atomic-wind blocks option. - '**/blocks/atomic-wind-list-view.spec.js' + '**/blocks/atomic-wind-list-view.spec.js', + + // Activates/deactivates the WooCommerce plugin site-wide; must not race parallel specs. + '**/blocks/woocommerce-builder.spec.js' ]; const config = defineConfig({ diff --git a/src/blocks/test/performance/playwright.config.ts b/src/blocks/test/performance/playwright.config.ts index 2f50e5bd7..47d3873dd 100644 --- a/src/blocks/test/performance/playwright.config.ts +++ b/src/blocks/test/performance/playwright.config.ts @@ -77,9 +77,9 @@ const config = defineConfig({ use: { ...devices[ 'Desktop Chrome' ], video: 'off' } } ], - reporter: process.env.CI ? - './config/performance-reporter.ts' : - [[ 'list' ], [ './config/performance-reporter.ts' ]], + // Keep the list reporter on CI too — the custom reporter implements no + // onError, so without it global-setup and test failures exit silently. + reporter: [[ 'list' ], [ './config/performance-reporter.ts' ]], forbidOnly: !! process.env.CI, fullyParallel: false, retries: 0, diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 51701404f..4bc16848a 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -20,7 +20,17 @@ function _manually_load_plugin() { require dirname( dirname( __FILE__ ) ) . '/otter-blocks.php'; - require dirname( dirname( __FILE__ ) ) . '/vendor/wp-content/plugins/woocommerce/woocommerce.php'; + + // Prefer the copy in the plugins directory (mounted there by wp-env) so the + // activate_plugin() call below resolves to the already-loaded file instead + // of redeclaring WooCommerce from the composer-vendored copy. + $woocommerce = WP_PLUGIN_DIR . '/woocommerce/woocommerce.php'; + + if ( ! file_exists( $woocommerce ) ) { + $woocommerce = dirname( dirname( __FILE__ ) ) . '/vendor/wp-content/plugins/woocommerce/woocommerce.php'; + } + + require $woocommerce; } tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );