Compare commits
41 Commits
quality-de
...
29622dd54c
| Author | SHA1 | Date | |
|---|---|---|---|
| 29622dd54c | |||
| 1afa6b71d7 | |||
| 8bb4784204 | |||
| b223165012 | |||
| 4228bcc330 | |||
| 7bac0dc63d | |||
| 7c272b5399 | |||
| 81e5b14604 | |||
| 9dca8880cc | |||
| ad03358e2a | |||
| 7d0ee0adea | |||
| 9fdfa7a8a9 | |||
| d6dcda908c | |||
| 7640f01d0c | |||
| 632dda5952 | |||
| 8fda3f1163 | |||
| 79f78882a6 | |||
| e1ee99ac9c | |||
| 6300f1c545 | |||
| c3738a3106 | |||
| e5d2994e40 | |||
| 7eb7aedc39 | |||
| 9cddf28c09 | |||
| a1e5b166ff | |||
| 79829ddce0 | |||
| ef43525c4a | |||
| 708acc39de | |||
| 40f6f596fa | |||
| 0b17fe8ad9 | |||
| a8f968562c | |||
| 595855ce10 | |||
| 1d41af86c3 | |||
| a6db436a48 | |||
| 4a817ab231 | |||
| 1f96fe9965 | |||
| 5d148f8af9 | |||
| 0e906eb981 | |||
| 02a635f72c | |||
| 6625e8ca4a | |||
| 52632ec322 | |||
| 1c1980bb22 |
@@ -23,34 +23,39 @@ AI assistants can directly monitor GitHub Actions workflows using the GitHub API
|
||||
|
||||
This helps identify failures and diagnose issues:
|
||||
|
||||
```
|
||||
```text
|
||||
github-api /repos/{owner}/{repo}/actions/runs
|
||||
```
|
||||
|
||||
#### Step-by-Step Process
|
||||
|
||||
1. **Get Recent Workflow Runs**:
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/actions/runs
|
||||
```
|
||||
|
||||
2. **Filter for Failed Runs**:
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/actions/runs?status=failure
|
||||
```
|
||||
|
||||
3. **Get Details for a Specific Run**:
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/actions/runs/{run_id}
|
||||
```
|
||||
|
||||
4. **Get Jobs for a Workflow Run**:
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/actions/runs/{run_id}/jobs
|
||||
```
|
||||
|
||||
5. **Analyze Job Logs** (if accessible via API):
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/actions/jobs/{job_id}/logs
|
||||
```
|
||||
|
||||
@@ -61,6 +66,7 @@ github-api /repos/{owner}/{repo}/actions/runs
|
||||
**Error**: `Missing download info for actions/upload-artifact@v3`
|
||||
|
||||
**Solution**: Update to the latest version of the action:
|
||||
|
||||
```yaml
|
||||
uses: actions/upload-artifact@v4
|
||||
```
|
||||
@@ -70,7 +76,8 @@ uses: actions/upload-artifact@v4
|
||||
**Error**: `The current host is 127.0.0.1:8888, but WordPress multisites do not support custom ports.`
|
||||
|
||||
**Solution**: Use port 80 for multisite environments:
|
||||
```yaml
|
||||
|
||||
```bash
|
||||
npx @wp-playground/cli server --blueprint playground/multisite-blueprint.json --port 80 --login &
|
||||
```
|
||||
|
||||
@@ -79,6 +86,7 @@ npx @wp-playground/cli server --blueprint playground/multisite-blueprint.json --
|
||||
**Error**: Invalid path syntax for artifacts
|
||||
|
||||
**Solution**: Use multi-line format for better readability:
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
cypress/videos
|
||||
@@ -90,6 +98,7 @@ path: |
|
||||
**Problem**: Redundant workflow runs when multiple commits land quickly
|
||||
|
||||
**Solution**: Add concurrency control to cancel in-progress runs:
|
||||
|
||||
```yaml
|
||||
concurrency:
|
||||
group: playground-tests-${{ github.ref }}
|
||||
@@ -125,16 +134,19 @@ npm run test:playground:multisite
|
||||
### Capturing and Analyzing Test Output
|
||||
|
||||
1. **Run Tests with Output Capture**:
|
||||
|
||||
```bash
|
||||
npm run test:single > test-output.log 2>&1
|
||||
```
|
||||
|
||||
2. **Analyze Output for Errors**:
|
||||
|
||||
```bash
|
||||
cat test-output.log | grep -i 'error\|fail\|exception'
|
||||
grep -E -i '\b(error|fail|exception)' test-output.log
|
||||
```
|
||||
|
||||
3. **Parse Structured Test Results** (if available):
|
||||
|
||||
```bash
|
||||
cat cypress/results/results.json
|
||||
```
|
||||
@@ -146,6 +158,7 @@ npm run test:playground:multisite
|
||||
**Error**: `The current host is 127.0.0.1:8888, but WordPress multisites do not support custom ports.`
|
||||
|
||||
**Solution**: Modify the port in the blueprint or test configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"features": {
|
||||
@@ -159,6 +172,7 @@ npm run test:playground:multisite
|
||||
**Error**: `Timed out retrying after 4000ms: expected '<body...>' to have class 'wp-admin'`
|
||||
|
||||
**Solution**: Update selectors to be more robust and handle login states:
|
||||
|
||||
```javascript
|
||||
cy.get('body').then(($body) => {
|
||||
if ($body.hasClass('login')) {
|
||||
@@ -199,16 +213,19 @@ npm run lint:css
|
||||
### Parsing Code Quality Tool Output
|
||||
|
||||
1. **Run Code Quality Check**:
|
||||
|
||||
```bash
|
||||
composer run phpcs > phpcs-output.log 2>&1
|
||||
```
|
||||
|
||||
2. **Analyze Output for Errors**:
|
||||
|
||||
```bash
|
||||
cat phpcs-output.log | grep -i 'ERROR\|WARNING'
|
||||
grep -E -i '\b(ERROR|WARNING)' phpcs-output.log
|
||||
```
|
||||
|
||||
3. **Automatically Fix Issues** (when possible):
|
||||
|
||||
```bash
|
||||
composer run phpcbf
|
||||
```
|
||||
@@ -221,13 +238,13 @@ AI assistants can check these comments to identify and address issues.
|
||||
|
||||
#### Accessing PR Comments via GitHub API
|
||||
|
||||
```
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/pulls/{pull_number}/comments
|
||||
```
|
||||
|
||||
#### Accessing PR Review Comments
|
||||
|
||||
```
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/pulls/{pull_number}/reviews
|
||||
```
|
||||
|
||||
@@ -236,7 +253,8 @@ github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/pulls/{pul
|
||||
CodeRabbit provides AI-powered code review comments via the GitHub API.
|
||||
|
||||
1. **Get PR Comments**:
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/pulls/{pull_number}/comments
|
||||
```
|
||||
|
||||
@@ -254,12 +272,14 @@ CodeRabbit provides AI-powered code review comments via the GitHub API.
|
||||
These tools provide automated code quality checks and post results as PR comments.
|
||||
|
||||
1. **Check PR Status Checks**:
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/commits/{sha}/check-runs
|
||||
```
|
||||
|
||||
2. **Get Detailed Reports** (if available via API):
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/commits/{sha}/check-runs/{id}
|
||||
```
|
||||
|
||||
@@ -275,7 +295,8 @@ These tools provide automated code quality checks and post results as PR comment
|
||||
SonarCloud provides detailed code quality and security analysis.
|
||||
|
||||
1. **Check SonarCloud Status**:
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/commits/{sha}/check-runs?check_name=SonarCloud
|
||||
```
|
||||
|
||||
@@ -293,6 +314,7 @@ SonarCloud provides detailed code quality and security analysis.
|
||||
**Error**: `ERROR: Expected snake_case for function name, but found camelCase`
|
||||
|
||||
**Solution**: Rename functions to follow snake_case convention:
|
||||
|
||||
```php
|
||||
// Before
|
||||
function getPluginVersion() { ... }
|
||||
@@ -306,6 +328,7 @@ function get_plugin_version() { ... }
|
||||
**Error**: `ERROR: Missing doc comment for function`
|
||||
|
||||
**Solution**: Add proper docblocks:
|
||||
|
||||
```php
|
||||
/**
|
||||
* Get the plugin version.
|
||||
@@ -332,7 +355,8 @@ function get_plugin_version() { ... }
|
||||
#### Extracting Actionable Items from PR Comments
|
||||
|
||||
1. **Collect All Feedback**:
|
||||
```
|
||||
|
||||
```text
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/pulls/{number}/comments
|
||||
github-api /repos/wpallstars/wp-plugin-starter-template-for-ai-coding/pulls/{number}/reviews
|
||||
```
|
||||
@@ -364,7 +388,7 @@ function get_plugin_version() { ... }
|
||||
|
||||
### Complete Feedback Loop System
|
||||
|
||||
```
|
||||
```text
|
||||
Code Changes ──► Local Testing ──► GitHub Actions
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
@@ -395,7 +419,7 @@ These can be directly accessed and processed.
|
||||
|
||||
#### Example CodeRabbit Feedback
|
||||
|
||||
```
|
||||
```text
|
||||
coderabbitai bot left a comment
|
||||
Actionable comments posted: 1
|
||||
|
||||
@@ -424,14 +448,14 @@ These tools provide structured feedback that can be systematically addressed.
|
||||
|
||||
#### Example SonarCloud Feedback
|
||||
|
||||
```
|
||||
```text
|
||||
SonarCloud Quality Gate failed
|
||||
- 3 Bugs
|
||||
- 5 Code Smells
|
||||
- 1 Security Hotspot
|
||||
```
|
||||
|
||||
#### Processing Steps
|
||||
#### SonarCloud Processing Steps
|
||||
|
||||
1. **Access Detailed Reports**:
|
||||
* Use the SonarCloud API or web interface
|
||||
@@ -479,6 +503,7 @@ AI assistants can contribute fixes upstream.
|
||||
### Workflow for External Contributions
|
||||
|
||||
1. **Clone the Repository Locally**:
|
||||
|
||||
```bash
|
||||
cd ~/Git
|
||||
git clone https://github.com/owner/repo.git
|
||||
@@ -487,6 +512,7 @@ AI assistants can contribute fixes upstream.
|
||||
```
|
||||
|
||||
2. **Make Changes and Commit**:
|
||||
|
||||
```bash
|
||||
# Make your changes
|
||||
git add -A
|
||||
@@ -498,6 +524,7 @@ AI assistants can contribute fixes upstream.
|
||||
```
|
||||
|
||||
3. **Fork and Push**:
|
||||
|
||||
```bash
|
||||
# Create a fork (if not already forked)
|
||||
gh repo fork owner/repo --clone=false --remote=true
|
||||
@@ -510,6 +537,7 @@ AI assistants can contribute fixes upstream.
|
||||
```
|
||||
|
||||
4. **Create Pull Request**:
|
||||
|
||||
```bash
|
||||
gh pr create \
|
||||
--repo owner/repo \
|
||||
|
||||
17
.eslintrc.js
17
.eslintrc.js
@@ -2,8 +2,7 @@ module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
'cypress/globals': true
|
||||
node: true
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended'
|
||||
@@ -16,9 +15,23 @@ module.exports = {
|
||||
sourceType: 'module'
|
||||
},
|
||||
rules: {
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'no-console': 'warn',
|
||||
'no-unused-vars': 'warn'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
// cypress.config.js uses CommonJS (require/module.exports).
|
||||
// Override sourceType to 'script' so ESLint does not flag require as undefined.
|
||||
files: ['cypress.config.js', 'cypress.config.cjs'],
|
||||
parserOptions: {
|
||||
sourceType: 'script'
|
||||
},
|
||||
env: {
|
||||
node: true
|
||||
}
|
||||
}
|
||||
],
|
||||
globals: {
|
||||
cy: 'readonly',
|
||||
Cypress: 'readonly',
|
||||
|
||||
20
.github/workflows/code-quality.yml
vendored
20
.github/workflows/code-quality.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
clean: 'true'
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
extensions: mbstring, intl, zip
|
||||
@@ -29,11 +29,6 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: composer install --prefer-dist --no-progress
|
||||
|
||||
- name: Install WordPress Coding Standards
|
||||
run: |
|
||||
composer require --dev wp-coding-standards/wpcs dealerdirect/phpcodesniffer-composer-installer
|
||||
vendor/bin/phpcs --config-set installed_paths vendor/wp-coding-standards/wpcs
|
||||
|
||||
- name: Run PHPCS
|
||||
run: composer phpcs
|
||||
continue-on-error: true
|
||||
@@ -52,7 +47,7 @@ jobs:
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
extensions: mbstring, intl, zip
|
||||
@@ -61,9 +56,6 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: composer install --prefer-dist --no-progress
|
||||
|
||||
- name: Install PHPStan WordPress stubs
|
||||
run: composer require --dev szepeviktor/phpstan-wordpress
|
||||
|
||||
- name: Run PHPStan
|
||||
run: composer phpstan
|
||||
continue-on-error: true
|
||||
@@ -76,7 +68,7 @@ jobs:
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
extensions: mbstring, intl, zip
|
||||
@@ -127,7 +119,7 @@ jobs:
|
||||
#
|
||||
# - name: SonarCloud Scan
|
||||
# if: steps.check_sonar_token.outputs.skip != 'true'
|
||||
# uses: SonarSource/sonarqube-scan-action@master
|
||||
# uses: SonarSource/sonarqube-scan-action@9598b8a83feef37de07f549027fab50ecffe6a6e # master
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
@@ -160,7 +152,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Run Codacy Analysis CLI
|
||||
uses: codacy/codacy-analysis-cli-action@v4
|
||||
uses: codacy/codacy-analysis-cli-action@562ee3e92b8e92df8b67e0a5ff8aa8e261919c08 # v4
|
||||
with:
|
||||
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
||||
verbose: true
|
||||
@@ -175,7 +167,7 @@ jobs:
|
||||
|
||||
- name: Upload SARIF results file
|
||||
if: steps.check_codacy_token.outputs.skip_upload != 'true'
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
uses: github/codeql-action/upload-sarif@603b797f8b14b413fe025cd935a91c16c4782713 # v3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
continue-on-error: true
|
||||
|
||||
2
.github/workflows/phpunit.yml
vendored
2
.github/workflows/phpunit.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: dom, curl, libxml, mbstring, zip, pdo, mysql, pdo_mysql, bcmath, soap, intl, gd, exif, iconv
|
||||
|
||||
4
.github/workflows/playground-tests-fix.yml
vendored
4
.github/workflows/playground-tests-fix.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
|
||||
- name: Upload Cypress artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: cypress-playground-results
|
||||
path: |
|
||||
|
||||
12
.github/workflows/playground-tests.yml
vendored
12
.github/workflows/playground-tests.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
@@ -142,7 +142,7 @@ jobs:
|
||||
|
||||
- name: Upload Cypress artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: cypress-single-site-results
|
||||
path: |
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
@@ -239,7 +239,7 @@ jobs:
|
||||
|
||||
- name: Upload Cypress artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: cypress-multisite-results
|
||||
path: |
|
||||
@@ -261,7 +261,7 @@ jobs:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: WordPress Performance Tests
|
||||
uses: swissspidy/wp-performance-action@v2.0.3
|
||||
uses: swissspidy/wp-performance-action@b7e3ffcf0fc4a48b62492e021e0ebeb51430ff11 # v2.0.3
|
||||
with:
|
||||
plugins: |
|
||||
./
|
||||
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -14,10 +14,10 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
|
||||
with:
|
||||
php-version: '7.4'
|
||||
extensions: mbstring, intl, zip
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
|
||||
with:
|
||||
files: wp-plugin-starter-template-for-ai-coding-${{ env.VERSION }}.zip
|
||||
name: v${{ env.VERSION }} - WordPress Plugin Starter Template
|
||||
|
||||
2
.github/workflows/sonarcloud.yml
vendored
2
.github/workflows/sonarcloud.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
|
||||
- name: SonarCloud Scan
|
||||
if: steps.check_token.outputs.skip != 'true'
|
||||
uses: SonarSource/sonarqube-scan-action@master
|
||||
uses: SonarSource/sonarqube-scan-action@9598b8a83feef37de07f549027fab50ecffe6a6e # master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONARCLOUD_GITHUB }}
|
||||
|
||||
8
.github/workflows/sync-wiki.yml
vendored
8
.github/workflows/sync-wiki.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
@@ -50,4 +50,8 @@ jobs:
|
||||
git commit -m "Sync wiki from source repository"
|
||||
|
||||
# Push changes
|
||||
git push https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.wiki.git
|
||||
git push https://${WIKI_ACTOR}:${WIKI_TOKEN}@github.com/${WIKI_REPO}.wiki.git
|
||||
env:
|
||||
WIKI_ACTOR: ${{ github.actor }}
|
||||
WIKI_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
WIKI_REPO: ${{ github.repository }}
|
||||
|
||||
15
.github/workflows/tests.yml
vendored
15
.github/workflows/tests.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
clean: 'true'
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mbstring, intl, zip
|
||||
@@ -34,11 +34,8 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: composer install --prefer-dist --no-progress
|
||||
|
||||
# - name: Debug test file content
|
||||
# run: echo "--- Debugging tests/test-admin.php lines 75-95 ---" && sed -n '75,95p' tests/test-admin.php && echo "--- End Debugging ---"
|
||||
|
||||
# - name: Run tests
|
||||
# run: ./vendor/bin/phpunit
|
||||
- name: Run tests
|
||||
run: ./vendor/bin/phpunit
|
||||
|
||||
code-style:
|
||||
name: Code Style
|
||||
@@ -46,12 +43,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
clean: 'true'
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
|
||||
with:
|
||||
php-version: '7.4'
|
||||
extensions: mbstring, intl, zip
|
||||
|
||||
6
.github/workflows/wordpress-tests.yml
vendored
6
.github/workflows/wordpress-tests.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
|
||||
- name: Upload Cypress artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: cypress-results
|
||||
path: |
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -63,3 +63,6 @@ temp/
|
||||
coverage/
|
||||
.phpunit.result.cache
|
||||
.agents/loop-state/
|
||||
|
||||
# Local tool configs
|
||||
.superset/
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"MD004": {
|
||||
"style": "asterisk"
|
||||
},
|
||||
"MD012": false,
|
||||
"MD022": false,
|
||||
"MD031": false,
|
||||
|
||||
@@ -67,7 +67,7 @@ if ($condition) {
|
||||
### Documentation
|
||||
|
||||
* All classes, methods, and functions should be documented using PHPDoc
|
||||
* Include a description, parameters, return values, and exceptions
|
||||
* Include descriptions of parameters, return values, and any exceptions thrown
|
||||
|
||||
```php
|
||||
/**
|
||||
@@ -271,7 +271,7 @@ To ensure your code passes the quality checks from these tools, follow these gui
|
||||
3. **Using AI Assistants with Code Quality Tools**
|
||||
* When you receive feedback from code quality tools, you can use AI assistants to help address the issues
|
||||
* Copy the output from the code quality tool and paste it into your AI assistant chat
|
||||
* Ask the AI to help you understand and resolve the issues
|
||||
* Request the AI's assistance to interpret and resolve the reported issues
|
||||
* Example prompt:
|
||||
|
||||
```text
|
||||
|
||||
@@ -6,11 +6,11 @@ Thank you for considering contributing to this project! This document provides g
|
||||
|
||||
By participating in this project, you agree to abide by our code of conduct:
|
||||
|
||||
- Be respectful and inclusive
|
||||
- Be patient and welcoming
|
||||
- Be considerate
|
||||
- Be collaborative
|
||||
- Be open-minded
|
||||
* Be respectful and inclusive
|
||||
* Be patient and welcoming
|
||||
* Be considerate
|
||||
* Be collaborative
|
||||
* Be open-minded
|
||||
|
||||
## How to Contribute
|
||||
|
||||
@@ -26,12 +26,12 @@ If you find a bug, please report it by creating an issue on GitHub:
|
||||
|
||||
Please include:
|
||||
|
||||
- A clear, descriptive title
|
||||
- Steps to reproduce the bug
|
||||
- Expected behavior
|
||||
- Actual behavior
|
||||
- Screenshots (if applicable)
|
||||
- Your environment (WordPress version, PHP version, browser, etc.)
|
||||
* A clear, descriptive title
|
||||
* Steps to reproduce the bug
|
||||
* Expected behavior
|
||||
* Actual behavior
|
||||
* Screenshots (if applicable)
|
||||
* Your environment (WordPress version, PHP version, browser, etc.)
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
@@ -45,10 +45,10 @@ If you have an idea for an enhancement:
|
||||
|
||||
Please include:
|
||||
|
||||
- A clear, descriptive title
|
||||
- A detailed description of the enhancement
|
||||
- Why this enhancement would be useful
|
||||
- Any relevant examples or mockups
|
||||
* A clear, descriptive title
|
||||
* A detailed description of the enhancement
|
||||
* Why this enhancement would be useful
|
||||
* Any relevant examples or mockups
|
||||
|
||||
### Pull Requests
|
||||
|
||||
@@ -72,33 +72,33 @@ If you want to contribute code:
|
||||
|
||||
#### Pull Request Guidelines
|
||||
|
||||
- Follow the coding standards (see [Coding Standards](Coding-Standards))
|
||||
- Write tests for your changes
|
||||
- Update documentation as needed
|
||||
- Keep pull requests focused on a single change
|
||||
- Write a clear, descriptive title and description
|
||||
- Reference any related issues
|
||||
- Ensure your code passes the automated code quality checks (see below)
|
||||
* Follow the coding standards (see [Coding Standards](Coding-Standards))
|
||||
* Write tests for your changes
|
||||
* Update documentation as needed
|
||||
* Keep pull requests focused on a single change
|
||||
* Write a clear, descriptive title and description
|
||||
* Reference any related issues
|
||||
* Ensure your code passes the automated code quality checks (see below)
|
||||
|
||||
#### Code Quality Tools
|
||||
|
||||
This project uses several automated code quality tools to ensure high standards. These tools are free for public repositories and will automatically analyze your code when you create a pull request:
|
||||
|
||||
1. **CodeRabbit**: AI-powered code review tool
|
||||
- [Website](https://www.coderabbit.ai/)
|
||||
- Provides automated feedback on pull requests
|
||||
* [Website](https://www.coderabbit.ai/)
|
||||
* Provides automated feedback on pull requests
|
||||
|
||||
2. **CodeFactor**: Continuous code quality monitoring
|
||||
- [Website](https://www.codefactor.io/)
|
||||
- Provides a grade for your codebase
|
||||
* [Website](https://www.codefactor.io/)
|
||||
* Provides a grade for your codebase
|
||||
|
||||
3. **Codacy**: Code quality and static analysis
|
||||
- [Website](https://www.codacy.com/)
|
||||
- Identifies issues related to code style, security, and performance
|
||||
* [Website](https://www.codacy.com/)
|
||||
* Identifies issues related to code style, security, and performance
|
||||
|
||||
4. **SonarCloud**: Code quality and security analysis
|
||||
- [Website](https://sonarcloud.io/)
|
||||
- Provides detailed analysis of code quality and security
|
||||
* [Website](https://sonarcloud.io/)
|
||||
* Provides detailed analysis of code quality and security
|
||||
|
||||
#### Using AI Assistants with Code Quality Tools
|
||||
|
||||
@@ -106,7 +106,7 @@ When you receive feedback from these code quality tools, you can use AI assistan
|
||||
|
||||
1. Copy the output from the code quality tool
|
||||
2. Paste it into your AI assistant chat
|
||||
3. Ask the AI to help you understand and resolve the issues
|
||||
3. Request the AI's assistance to interpret and resolve the reported issues
|
||||
4. Apply the suggested fixes
|
||||
5. Commit the changes and verify that the issues are resolved
|
||||
|
||||
@@ -143,7 +143,7 @@ To ensure your code meets the quality standards, run these commands before submi
|
||||
* Check JavaScript coding standards: `npm run lint:js`
|
||||
* Check CSS coding standards: `npm run lint:css`
|
||||
|
||||
These checks will help identify and fix issues before they are caught by the automated code quality tools in the pull request process.
|
||||
These checks will assist in identifying and resolving issues before they are caught by the automated code quality tools in the pull request process.
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
@@ -24,9 +24,10 @@ The easiest way to test our plugin with WordPress Playground is to use the onlin
|
||||
[playground-single]: https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/wpallstars/wp-plugin-starter-template-for-ai-coding/main/playground/blueprint.json&_t=2
|
||||
[playground-multisite]: https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/wpallstars/wp-plugin-starter-template-for-ai-coding/main/playground/multisite-blueprint.json&_t=2
|
||||
|
||||
These links automatically set up WordPress with multisite enabled and WP_DEBUG enabled.
|
||||
Both links automatically set up WordPress with WP_DEBUG enabled and the Plugin Toggle and
|
||||
Kadence Blocks plugins pre-installed and activated.
|
||||
|
||||
Both the Plugin Toggle and Kadence Blocks plugins are pre-activated.
|
||||
The multisite link additionally enables WordPress multisite and network-activates both plugins.
|
||||
|
||||
## WP-CLI Commands for WordPress Playground
|
||||
|
||||
@@ -101,14 +102,16 @@ In a WordPress multisite environment, there are two ways to activate plugins:
|
||||
1. **Network Activation**: Activates a plugin for all sites in the network
|
||||
* In the WordPress admin, go to Network Admin > Plugins
|
||||
* Click "Network Activate" under the plugin
|
||||
* Or use WP-CLI: `wp plugin install plugin-name --activate-network`
|
||||
* Or use WP-CLI:
|
||||
* To activate an already installed plugin: `wp plugin activate plugin-name --network`
|
||||
* To install and activate in one step: `wp plugin install plugin-name --activate-network`
|
||||
|
||||
2. **Per-Site Activation**: Activates a plugin for a specific site
|
||||
* In the WordPress admin, go to the specific site's admin area
|
||||
* Go to Plugins and activate the plugin for that site only
|
||||
* Or use WP-CLI: `wp plugin activate plugin-name --url=site-url`
|
||||
|
||||
Our multisite blueprint uses network activation for the Plugin Toggle plugin as an example.
|
||||
Our multisite blueprint uses network activation for both the Plugin Toggle and Kadence Blocks plugins.
|
||||
|
||||
## Running Tests with WordPress Playground
|
||||
|
||||
|
||||
@@ -376,7 +376,7 @@ When you receive feedback from these code quality tools, you can use AI assistan
|
||||
|
||||
1. Copy the output from the code quality tool
|
||||
2. Paste it into your AI assistant chat
|
||||
3. Ask the AI to help you understand and resolve the issues
|
||||
3. Request the AI's assistance to interpret and resolve the reported issues
|
||||
4. Apply the suggested fixes
|
||||
5. Commit the changes and verify that the issues are resolved
|
||||
|
||||
|
||||
@@ -6,140 +6,140 @@
|
||||
|
||||
/* General Admin Styles */
|
||||
.wpst-admin-page {
|
||||
max-width: 1200px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
|
||||
max-width: 1200px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
.wpst-admin-header {
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.wpst-admin-header h1 {
|
||||
margin-top: 0;
|
||||
color: #23282d;
|
||||
margin-top: 0;
|
||||
color: #23282d;
|
||||
}
|
||||
|
||||
/* Admin Form Styles */
|
||||
.wpst-form-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.wpst-form-table th {
|
||||
text-align: left;
|
||||
padding: 15px 10px 15px 0;
|
||||
width: 200px;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
padding: 15px 10px 15px 0;
|
||||
width: 200px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.wpst-form-table td {
|
||||
padding: 15px 0;
|
||||
vertical-align: middle;
|
||||
padding: 15px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.wpst-form-table input[type="text"],
|
||||
.wpst-form-table input[type="number"],
|
||||
.wpst-form-table select,
|
||||
.wpst-form-table textarea {
|
||||
width: 400px;
|
||||
max-width: 100%;
|
||||
width: 400px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.wpst-form-table textarea {
|
||||
min-height: 100px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.wpst-form-description {
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
margin-top: 5px;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* Admin Notices */
|
||||
.wpst-notice {
|
||||
padding: 10px 15px;
|
||||
margin: 15px 0;
|
||||
border-radius: 3px;
|
||||
border-left: 4px solid #00a0d2;
|
||||
background: #f7fcff;
|
||||
padding: 10px 15px;
|
||||
margin: 15px 0;
|
||||
border-radius: 3px;
|
||||
border-left: 4px solid #00a0d2;
|
||||
background: #f7fcff;
|
||||
}
|
||||
|
||||
.wpst-notice.success {
|
||||
border-left-color: #46b450;
|
||||
background: #ecf7ed;
|
||||
border-left-color: #46b450;
|
||||
background: #ecf7ed;
|
||||
}
|
||||
|
||||
.wpst-notice.error {
|
||||
border-left-color: #dc3232;
|
||||
background: #fbeaea;
|
||||
border-left-color: #dc3232;
|
||||
background: #fbeaea;
|
||||
}
|
||||
|
||||
.wpst-notice.warning {
|
||||
border-left-color: #ffb900;
|
||||
background: #fff8e5;
|
||||
border-left-color: #ffb900;
|
||||
background: #fff8e5;
|
||||
}
|
||||
|
||||
/* Admin Cards */
|
||||
.wpst-card-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -10px;
|
||||
}
|
||||
|
||||
.wpst-card {
|
||||
flex: 1 0 300px;
|
||||
margin: 10px;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
|
||||
flex: 1 0 300px;
|
||||
margin: 10px;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
.wpst-card-header {
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.wpst-card-title {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wpst-card-content {
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.wpst-card-footer {
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
text-align: right;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Responsive Styles */
|
||||
@media screen and (width <= 782px) {
|
||||
.wpst-form-table th {
|
||||
width: 100%;
|
||||
display: block;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
/* 782px is the WordPress mobile admin breakpoint. */
|
||||
@media screen and (max-width: 782px) {
|
||||
.wpst-form-table th {
|
||||
width: 100%;
|
||||
display: block;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.wpst-form-table td {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
.wpst-form-table td {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.wpst-form-table input[type="text"],
|
||||
.wpst-form-table input[type="number"],
|
||||
.wpst-form-table select,
|
||||
.wpst-form-table textarea {
|
||||
width: 100%;
|
||||
}
|
||||
.wpst-form-table input[type="text"],
|
||||
.wpst-form-table input[type="number"],
|
||||
.wpst-form-table select,
|
||||
.wpst-form-table textarea {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,138 +6,138 @@
|
||||
|
||||
/* Modal Styles */
|
||||
.wpst-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 100000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgb(0 0 0 / 40%);
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 100000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgb(0 0 0 / 40%);
|
||||
}
|
||||
|
||||
.wpst-modal-content {
|
||||
position: relative;
|
||||
background-color: #fefefe;
|
||||
margin: 10% auto;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 4px 8px rgb(0 0 0 / 10%);
|
||||
width: 500px;
|
||||
max-width: 90%;
|
||||
position: relative;
|
||||
background-color: #fefefe;
|
||||
margin: 10% auto;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 4px 8px rgb(0 0 0 / 10%);
|
||||
width: 500px;
|
||||
max-width: 90%;
|
||||
}
|
||||
|
||||
.wpst-modal-header {
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.wpst-modal-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wpst-modal-close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 15px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 15px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wpst-modal-close:hover,
|
||||
.wpst-modal-close:focus {
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.wpst-modal-body {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.wpst-modal-footer {
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
text-align: right;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Source Selection Styles */
|
||||
.wpst-source-options {
|
||||
margin: 15px 0;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.wpst-source-option {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wpst-source-option:hover {
|
||||
background-color: #f9f9f9;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.wpst-source-option.selected {
|
||||
border-color: #0073aa;
|
||||
background-color: #f0f6fc;
|
||||
border-color: #0073aa;
|
||||
background-color: #f0f6fc;
|
||||
}
|
||||
|
||||
.wpst-source-option input[type="radio"] {
|
||||
margin-right: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.wpst-source-option-label {
|
||||
font-weight: 600;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wpst-source-option-description {
|
||||
margin-top: 5px;
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
margin-top: 5px;
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Loading Indicator */
|
||||
.wpst-loading {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid rgb(0 0 0 / 10%);
|
||||
border-radius: 50%;
|
||||
border-top-color: #0073aa;
|
||||
animation: wpst-spin 1s ease-in-out infinite;
|
||||
margin-right: 10px;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid rgb(0 0 0 / 10%);
|
||||
border-radius: 50%;
|
||||
border-top-color: #0073aa;
|
||||
animation: wpst-spin 1s ease-in-out infinite;
|
||||
margin-right: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@keyframes wpst-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Message Styles */
|
||||
.wpst-modal-message {
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
border-radius: 3px;
|
||||
display: none;
|
||||
padding: 10px;
|
||||
margin: 10px 0;
|
||||
border-radius: 3px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wpst-modal-message.success {
|
||||
background-color: #ecf7ed;
|
||||
border: 1px solid #46b450;
|
||||
color: #2a6f31;
|
||||
background-color: #ecf7ed;
|
||||
border: 1px solid #46b450;
|
||||
color: #2a6f31;
|
||||
}
|
||||
|
||||
.wpst-modal-message.error {
|
||||
background-color: #fbeaea;
|
||||
border: 1px solid #dc3232;
|
||||
color: #8a1f1f;
|
||||
background-color: #fbeaea;
|
||||
border: 1px solid #dc3232;
|
||||
color: #8a1f1f;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
data: {
|
||||
action: 'wpst_save_settings',
|
||||
nonce: wpstData.nonce,
|
||||
formData: formData
|
||||
formData: formData,
|
||||
},
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
@@ -93,8 +93,8 @@
|
||||
complete: function () {
|
||||
// Re-enable submit button and remove loading state.
|
||||
$submitButton.prop( 'disabled', false ).removeClass( 'loading' );
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -105,10 +105,16 @@
|
||||
* @param {string} message Notice message
|
||||
*/
|
||||
showNotice: function (type, message) {
|
||||
const $notice = $( '<div class="wpst-notice ' + type + '"><p>' + message + '</p></div>' );
|
||||
const allowedTypes = [ 'success', 'error', 'warning' ];
|
||||
const safeType = allowedTypes.includes( type ) ? type : 'error';
|
||||
const $p = $( '<p>' );
|
||||
const $notice = $( '<div>' ).addClass( 'wpst-notice ' + safeType ).append( $p );
|
||||
|
||||
// Set message as plain text to prevent XSS.
|
||||
$p.text( message );
|
||||
|
||||
// Add notice to the page.
|
||||
$( '.wpst-notices' ).html( $notice );
|
||||
$( '.wpst-notices' ).empty().append( $notice );
|
||||
|
||||
// Automatically remove notice after 5 seconds.
|
||||
setTimeout(
|
||||
@@ -117,19 +123,19 @@
|
||||
300,
|
||||
function () {
|
||||
$( this ).remove();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Initialize when document is ready.
|
||||
$( document ).ready(
|
||||
function () {
|
||||
WPSTAdmin.init();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
})( jQuery );
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
if ($( e.target ).hasClass( 'wpst-modal' )) {
|
||||
WPSTUpdateSourceSelector.closeModal();
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Select source option.
|
||||
@@ -116,7 +116,7 @@
|
||||
data: {
|
||||
action: 'wpst_set_update_source', // AJAX action hook.
|
||||
nonce: wpstModalData.nonce, // Security nonce.
|
||||
source: this.selectedSource
|
||||
source: this.selectedSource,
|
||||
},
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
@@ -127,7 +127,7 @@
|
||||
function () {
|
||||
WPSTUpdateSourceSelector.closeModal();
|
||||
},
|
||||
1500
|
||||
1500,
|
||||
);
|
||||
} else {
|
||||
WPSTUpdateSourceSelector.showMessage( 'error', response.data.message );
|
||||
@@ -139,40 +139,44 @@
|
||||
complete: function () {
|
||||
// Reset button state.
|
||||
$saveButton.prop( 'disabled', false ).text( wpstModalData.i18n.confirm );
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a message in the modal
|
||||
*
|
||||
* @param {string} type Message type (success, error)
|
||||
* @param {string} type Message type (success, error)
|
||||
* @param {string} message Message text
|
||||
*/
|
||||
showMessage: function (type, message) {
|
||||
const $message = this.$modal.find( '.wpst-modal-message' );
|
||||
|
||||
// Set message content and type.
|
||||
$message.html( message ).removeClass( 'success error' ).addClass( type ).show();
|
||||
// Validate type against allow-list to prevent class injection vulnerabilities.
|
||||
const allowedTypes = [ 'success', 'error' ];
|
||||
const safeType = allowedTypes.includes( type ) ? type : 'error';
|
||||
|
||||
// Set message as plain text to prevent XSS, then apply validated type class.
|
||||
$message.text( message ).removeClass( 'success error' ).addClass( safeType ).show();
|
||||
|
||||
// Hide message after a delay for success messages.
|
||||
if (type === 'success') {
|
||||
if (safeType === 'success') {
|
||||
setTimeout(
|
||||
function () {
|
||||
$message.fadeOut( 300 );
|
||||
},
|
||||
3000
|
||||
3000,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Initialize when document is ready.
|
||||
$( document ).ready(
|
||||
function () {
|
||||
WPSTUpdateSourceSelector.init();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
})( jQuery );
|
||||
|
||||
@@ -12,11 +12,22 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
?>
|
||||
|
||||
<!-- Update Source Modal -->
|
||||
<div id="wpst-update-source-modal" class="wpst-modal">
|
||||
<div
|
||||
id="wpst-update-source-modal"
|
||||
class="wpst-modal"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="wpst-update-source-modal-title"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div class="wpst-modal-content">
|
||||
<div class="wpst-modal-header">
|
||||
<h2 class="wpst-modal-title"><?php esc_html_e( 'Select Update Source', 'wp-plugin-starter-template' ); ?></h2>
|
||||
<span class="wpst-modal-close">×</span>
|
||||
<h2 id="wpst-update-source-modal-title" class="wpst-modal-title"><?php esc_html_e( 'Select Update Source', 'wp-plugin-starter-template' ); ?></h2>
|
||||
<button
|
||||
type="button"
|
||||
class="wpst-modal-close"
|
||||
aria-label="<?php esc_attr_e( 'Close dialog', 'wp-plugin-starter-template' ); ?>"
|
||||
>×</button>
|
||||
</div>
|
||||
|
||||
<div class="wpst-modal-body">
|
||||
|
||||
@@ -17,15 +17,19 @@ WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
|
||||
WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/}
|
||||
|
||||
download() {
|
||||
if command -v curl > /dev/null; then
|
||||
curl -s "$1" > "$2";
|
||||
elif command -v wget > /dev/null; then
|
||||
wget -nv -O "$2" "$1"
|
||||
fi
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$1" -o "$2"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -qO "$2" "$1"
|
||||
else
|
||||
echo "Error: Neither curl nor wget is installed" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then
|
||||
WP_BRANCH=${WP_VERSION%\-*}
|
||||
WP_TESTS_TAG="branches/$WP_BRANCH"
|
||||
elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
|
||||
WP_TESTS_TAG="branches/$WP_VERSION"
|
||||
elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
||||
@@ -40,27 +44,38 @@ elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
|
||||
else
|
||||
# http serves a single offer, whereas https serves multiple. we only want one
|
||||
download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
|
||||
grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
|
||||
LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
|
||||
LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//' | head -1)
|
||||
if [[ -z "$LATEST_VERSION" ]]; then
|
||||
echo "Latest WordPress version could not be found"
|
||||
exit 1
|
||||
fi
|
||||
WP_TESTS_TAG="tags/$LATEST_VERSION"
|
||||
fi
|
||||
|
||||
# Derive a git ref from WP_TESTS_TAG by stripping the SVN-style prefix.
|
||||
# WP_TESTS_TAG uses "tags/X.Y.Z", "branches/X.Y", or "trunk".
|
||||
# git clone --branch requires the bare ref name ("X.Y.Z", "X.Y", or "trunk").
|
||||
if [[ "$WP_TESTS_TAG" == tags/* ]]; then
|
||||
GIT_REF="${WP_TESTS_TAG#tags/}"
|
||||
elif [[ "$WP_TESTS_TAG" == branches/* ]]; then
|
||||
GIT_REF="${WP_TESTS_TAG#branches/}"
|
||||
else
|
||||
GIT_REF="$WP_TESTS_TAG"
|
||||
fi
|
||||
|
||||
set -ex
|
||||
|
||||
install_wp() {
|
||||
|
||||
if [ -d "$WP_CORE_DIR" ]; then
|
||||
return;
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p "$WP_CORE_DIR"
|
||||
|
||||
if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
|
||||
mkdir -p "$WP_CORE_DIR"
|
||||
download https://wordpress.org/nightly-builds/wordpress-latest.zip "$WP_CORE_DIR/wordpress-nightly.zip"
|
||||
download https://wordpress.org/nightly-builds/wordpress-latest.zip "$WP_CORE_DIR/wordpress-nightly.zip"
|
||||
unzip -q "$WP_CORE_DIR/wordpress-nightly.zip" -d "$WP_CORE_DIR"
|
||||
rm "$WP_CORE_DIR/wordpress-nightly.zip"
|
||||
else
|
||||
@@ -71,6 +86,7 @@ install_wp() {
|
||||
if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
|
||||
LATEST_VERSION=${WP_VERSION%??}
|
||||
else
|
||||
# shellcheck disable=SC2001
|
||||
VERSION_ESCAPED=$(echo "$WP_VERSION" | sed 's/\./\\\\./g')
|
||||
LATEST_VERSION=$(grep -o '"version":"'"$VERSION_ESCAPED"'[^"]*' "$WP_CORE_DIR/wp-latest.json" | sed 's/"version":"//' | head -1)
|
||||
fi
|
||||
@@ -82,7 +98,7 @@ install_wp() {
|
||||
else
|
||||
local ARCHIVE_NAME="wordpress-$WP_VERSION"
|
||||
fi
|
||||
download https://wordpress.org/"${ARCHIVE_NAME}".tar.gz "$WP_CORE_DIR/wordpress.tar.gz"
|
||||
download https://wordpress.org/"${ARCHIVE_NAME}".tar.gz "$WP_CORE_DIR/wordpress.tar.gz"
|
||||
tar --strip-components=1 -zxmf "$WP_CORE_DIR/wordpress.tar.gz" -C "$WP_CORE_DIR"
|
||||
rm "$WP_CORE_DIR/wordpress.tar.gz"
|
||||
fi
|
||||
@@ -101,12 +117,22 @@ install_test_suite() {
|
||||
# set up testing suite if it doesn't yet exist
|
||||
if [ ! -d "$WP_TESTS_DIR" ]; then
|
||||
mkdir -p "$WP_TESTS_DIR"
|
||||
git clone --quiet --depth=1 https://github.com/WordPress/wordpress-develop.git /tmp/wordpress-develop
|
||||
rm -rf /tmp/wordpress-develop
|
||||
if ! git clone --quiet --depth=1 --branch "$GIT_REF" https://github.com/WordPress/wordpress-develop.git /tmp/wordpress-develop; then
|
||||
echo "Error: Failed to clone wordpress-develop at branch/tag $GIT_REF" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -d /tmp/wordpress-develop/tests/phpunit/includes ]; then
|
||||
cp -r /tmp/wordpress-develop/tests/phpunit/includes "$WP_TESTS_DIR/"
|
||||
if ! cp -r /tmp/wordpress-develop/tests/phpunit/includes "$WP_TESTS_DIR/"; then
|
||||
echo "Error: Failed to copy phpunit includes to $WP_TESTS_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -d /tmp/wordpress-develop/tests/phpunit/data ]; then
|
||||
cp -r /tmp/wordpress-develop/tests/phpunit/data "$WP_TESTS_DIR/"
|
||||
if ! cp -r /tmp/wordpress-develop/tests/phpunit/data "$WP_TESTS_DIR/"; then
|
||||
echo "Error: Failed to copy phpunit data to $WP_TESTS_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -116,15 +142,15 @@ install_test_suite() {
|
||||
else
|
||||
download https://raw.githubusercontent.com/WordPress/wordpress-develop/master/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
fi
|
||||
WP_CORE_DIR=$(echo "$WP_CORE_DIR" | sed "s:/\+$::")
|
||||
sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
WP_CORE_DIR="${WP_CORE_DIR%/}"
|
||||
sed "$ioption" "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
sed "$ioption" "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
sed "$ioption" "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
sed "$ioption" "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
sed "$ioption" "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
|
||||
if [ "$MULTISITE" = "true" ]; then
|
||||
sed $ioption "s:// define( 'WP_TESTS_MULTISITE', true );:define( 'WP_TESTS_MULTISITE', true );:" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
sed "$ioption" "s:// define( 'WP_TESTS_MULTISITE', true );:define( 'WP_TESTS_MULTISITE', true );:" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -132,27 +158,27 @@ install_test_suite() {
|
||||
|
||||
install_db() {
|
||||
|
||||
if [ ${SKIP_DB_CREATE} = "true" ]; then
|
||||
if [ "${SKIP_DB_CREATE}" = "true" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local PARTS
|
||||
IFS=':' read -ra PARTS <<< "$DB_HOST"
|
||||
local DB_HOSTNAME=${PARTS[0]};
|
||||
local DB_SOCK_OR_PORT=${PARTS[1]};
|
||||
IFS=':' read -ra PARTS <<<"$DB_HOST"
|
||||
local DB_HOSTNAME=${PARTS[0]}
|
||||
local DB_SOCK_OR_PORT=${PARTS[1]}
|
||||
local EXTRA=""
|
||||
|
||||
if [ -n "$DB_HOSTNAME" ] ; then
|
||||
if [ -n "$DB_HOSTNAME" ]; then
|
||||
if [[ $DB_SOCK_OR_PORT =~ ^[0-9]+$ ]]; then
|
||||
EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
|
||||
elif [ -n "$DB_SOCK_OR_PORT" ] ; then
|
||||
elif [ -n "$DB_SOCK_OR_PORT" ]; then
|
||||
EXTRA=" --socket=$DB_SOCK_OR_PORT"
|
||||
elif [ -n "$DB_HOSTNAME" ] ; then
|
||||
elif [ -n "$DB_HOSTNAME" ]; then
|
||||
EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
|
||||
fi
|
||||
fi
|
||||
|
||||
mysqladmin create "$DB_NAME" --user="$DB_USER" --password="$DB_PASS"$EXTRA || true
|
||||
mysqladmin create "$DB_NAME" --user="$DB_USER" --password="$DB_PASS""$EXTRA" || true
|
||||
}
|
||||
|
||||
install_wp
|
||||
|
||||
@@ -28,7 +28,6 @@ set -e
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
PLUGIN_SLUG="wp-plugin-starter-template"
|
||||
PLUGIN_TEXT_DOMAIN="wp-plugin-starter-template"
|
||||
|
||||
# LocalWP paths (macOS)
|
||||
LOCAL_SITES_DIR="$HOME/Local Sites"
|
||||
@@ -51,363 +50,375 @@ NC='\033[0m' # No Color
|
||||
|
||||
# Helper functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "${CYAN}[STEP]${NC} $1"
|
||||
echo -e "${CYAN}[STEP]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if LocalWP is installed
|
||||
check_localwp() {
|
||||
if [ ! -d "$LOCAL_APP" ]; then
|
||||
log_error "LocalWP is not installed at $LOCAL_APP"
|
||||
log_info "Download from: https://localwp.com/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$LOCAL_WP_CLI" ]; then
|
||||
log_error "WP-CLI not found in LocalWP installation"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local version=$("$LOCAL_WP_CLI" --version 2>/dev/null || echo "unknown")
|
||||
log_info "LocalWP WP-CLI version: $version"
|
||||
if [ ! -d "$LOCAL_APP" ]; then
|
||||
log_error "LocalWP is not installed at $LOCAL_APP"
|
||||
log_info "Download from: https://localwp.com/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$LOCAL_WP_CLI" ]; then
|
||||
log_error "WP-CLI not found in LocalWP installation"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local version
|
||||
version=$("$LOCAL_WP_CLI" --version 2>/dev/null || echo "unknown")
|
||||
log_info "LocalWP WP-CLI version: $version"
|
||||
}
|
||||
|
||||
# Get site path
|
||||
get_site_path() {
|
||||
local site_name="$1"
|
||||
echo "$LOCAL_SITES_DIR/$site_name"
|
||||
local site_name="$1"
|
||||
echo "$LOCAL_SITES_DIR/$site_name"
|
||||
}
|
||||
|
||||
# Get WordPress path within site
|
||||
get_wp_path() {
|
||||
local site_name="$1"
|
||||
local site_path=$(get_site_path "$site_name")
|
||||
|
||||
# LocalWP uses app/public for WordPress files
|
||||
echo "$site_path/app/public"
|
||||
local site_name="$1"
|
||||
local site_path
|
||||
site_path=$(get_site_path "$site_name")
|
||||
|
||||
# LocalWP uses app/public for WordPress files
|
||||
echo "$site_path/app/public"
|
||||
}
|
||||
|
||||
# Check if site exists
|
||||
site_exists() {
|
||||
local site_name="$1"
|
||||
local site_path=$(get_site_path "$site_name")
|
||||
[ -d "$site_path" ]
|
||||
local site_name="$1"
|
||||
local site_path
|
||||
site_path=$(get_site_path "$site_name")
|
||||
[ -d "$site_path" ]
|
||||
}
|
||||
|
||||
# Get plugin destination path
|
||||
get_plugin_path() {
|
||||
local site_name="$1"
|
||||
local wp_path=$(get_wp_path "$site_name")
|
||||
echo "$wp_path/wp-content/plugins/$PLUGIN_SLUG"
|
||||
local site_name="$1"
|
||||
local wp_path
|
||||
wp_path=$(get_wp_path "$site_name")
|
||||
echo "$wp_path/wp-content/plugins/$PLUGIN_SLUG"
|
||||
}
|
||||
|
||||
# Sync plugin files to LocalWP site
|
||||
sync_plugin() {
|
||||
local site_name="$1"
|
||||
local plugin_dest=$(get_plugin_path "$site_name")
|
||||
|
||||
if ! site_exists "$site_name"; then
|
||||
log_error "Site '$site_name' does not exist"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Syncing plugin to $site_name..."
|
||||
|
||||
# Create plugin directory if it doesn't exist
|
||||
mkdir -p "$plugin_dest"
|
||||
|
||||
# Sync files using rsync (excludes dev files)
|
||||
rsync -av --delete \
|
||||
--exclude 'node_modules' \
|
||||
--exclude 'vendor' \
|
||||
--exclude '.git' \
|
||||
--exclude 'dist' \
|
||||
--exclude 'tests' \
|
||||
--exclude 'cypress' \
|
||||
--exclude '.github' \
|
||||
--exclude '.agents' \
|
||||
--exclude '.wiki' \
|
||||
--exclude 'reference-plugins' \
|
||||
--exclude '*.zip' \
|
||||
--exclude '.playground.*' \
|
||||
--exclude 'composer.lock' \
|
||||
--exclude 'package-lock.json' \
|
||||
"$PROJECT_DIR/" "$plugin_dest/"
|
||||
|
||||
log_success "Plugin synced to: $plugin_dest"
|
||||
local site_name="$1"
|
||||
local plugin_dest
|
||||
plugin_dest=$(get_plugin_path "$site_name")
|
||||
|
||||
if ! site_exists "$site_name"; then
|
||||
log_error "Site '$site_name' does not exist"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Syncing plugin to $site_name..."
|
||||
|
||||
# Create plugin directory if it doesn't exist
|
||||
mkdir -p "$plugin_dest"
|
||||
|
||||
# Sync files using rsync (excludes dev files)
|
||||
rsync -av --delete \
|
||||
--exclude 'node_modules' \
|
||||
--exclude 'vendor' \
|
||||
--exclude '.git' \
|
||||
--exclude 'dist' \
|
||||
--exclude 'tests' \
|
||||
--exclude 'cypress' \
|
||||
--exclude '.github' \
|
||||
--exclude '.agents' \
|
||||
--exclude '.wiki' \
|
||||
--exclude 'reference-plugins' \
|
||||
--exclude '*.zip' \
|
||||
--exclude '.playground.*' \
|
||||
--exclude 'composer.lock' \
|
||||
--exclude 'package-lock.json' \
|
||||
"$PROJECT_DIR/" "$plugin_dest/"
|
||||
|
||||
log_success "Plugin synced to: $plugin_dest"
|
||||
}
|
||||
|
||||
# Create a new LocalWP site
|
||||
create_site() {
|
||||
local multisite=false
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--multisite)
|
||||
multisite=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local site_name="$SINGLE_SITE_NAME"
|
||||
local domain="$SINGLE_SITE_DOMAIN"
|
||||
local mode="single site"
|
||||
|
||||
if [ "$multisite" = true ]; then
|
||||
site_name="$MULTISITE_NAME"
|
||||
domain="$MULTISITE_DOMAIN"
|
||||
mode="multisite"
|
||||
fi
|
||||
|
||||
check_localwp
|
||||
|
||||
local site_path=$(get_site_path "$site_name")
|
||||
|
||||
if site_exists "$site_name"; then
|
||||
log_warning "Site '$site_name' already exists at: $site_path"
|
||||
log_info "Use 'npm run localwp:reset' to reset it, or 'npm run localwp:sync' to update files"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " LocalWP Site Setup ($mode)"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "This script will guide you through creating a"
|
||||
echo "LocalWP site for testing the plugin."
|
||||
echo ""
|
||||
echo "Site Details:"
|
||||
echo " Name: $site_name"
|
||||
echo " Domain: $domain"
|
||||
echo " Path: $site_path"
|
||||
echo ""
|
||||
|
||||
log_step "Creating LocalWP Site"
|
||||
echo ""
|
||||
log_info "LocalWP doesn't have a CLI for site creation."
|
||||
log_info "Please create the site manually in LocalWP:"
|
||||
echo ""
|
||||
echo "1. Open LocalWP application"
|
||||
echo "2. Click the '+' button to create a new site"
|
||||
echo "3. Use these settings:"
|
||||
echo " - Site name: ${CYAN}$site_name${NC}"
|
||||
echo " - Local site domain: ${CYAN}$domain${NC}"
|
||||
echo " - PHP version: 8.0 or higher"
|
||||
echo " - Web server: nginx (preferred)"
|
||||
echo " - MySQL version: 8.0+"
|
||||
|
||||
if [ "$multisite" = true ]; then
|
||||
echo ""
|
||||
echo "4. After site creation, convert to multisite:"
|
||||
echo " - Open Site Shell in LocalWP"
|
||||
echo " - Run: wp core multisite-convert --subdomains=0"
|
||||
echo " - Update wp-config.php if needed"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_info "After creating the site, run: npm run localwp:sync"
|
||||
echo ""
|
||||
|
||||
# Wait for user to create site
|
||||
read -p "Press Enter after you've created the site in LocalWP..."
|
||||
|
||||
if site_exists "$site_name"; then
|
||||
log_success "Site detected at: $site_path"
|
||||
sync_plugin "$site_name"
|
||||
|
||||
# Install recommended plugins
|
||||
install_recommended_plugins "$site_name"
|
||||
|
||||
show_site_info "$site_name" "$domain" "$multisite"
|
||||
else
|
||||
log_warning "Site not found at expected location"
|
||||
log_info "Expected path: $site_path"
|
||||
log_info "You can run 'npm run localwp:sync' later to sync files"
|
||||
fi
|
||||
local multisite=false
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--multisite)
|
||||
multisite=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local site_name="$SINGLE_SITE_NAME"
|
||||
local domain="$SINGLE_SITE_DOMAIN"
|
||||
local mode="single site"
|
||||
|
||||
if [ "$multisite" = true ]; then
|
||||
site_name="$MULTISITE_NAME"
|
||||
domain="$MULTISITE_DOMAIN"
|
||||
mode="multisite"
|
||||
fi
|
||||
|
||||
check_localwp
|
||||
|
||||
local site_path
|
||||
site_path=$(get_site_path "$site_name")
|
||||
|
||||
if site_exists "$site_name"; then
|
||||
log_warning "Site '$site_name' already exists at: $site_path"
|
||||
log_info "Use 'npm run localwp:reset' to reset it, or 'npm run localwp:sync' to update files"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " LocalWP Site Setup ($mode)"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "This script will guide you through creating a"
|
||||
echo "LocalWP site for testing the plugin."
|
||||
echo ""
|
||||
echo "Site Details:"
|
||||
echo " Name: $site_name"
|
||||
echo " Domain: $domain"
|
||||
echo " Path: $site_path"
|
||||
echo ""
|
||||
|
||||
log_step "Creating LocalWP Site"
|
||||
echo ""
|
||||
log_info "LocalWP doesn't have a CLI for site creation."
|
||||
log_info "Please create the site manually in LocalWP:"
|
||||
echo ""
|
||||
echo "1. Open LocalWP application"
|
||||
echo "2. Click the '+' button to create a new site"
|
||||
echo "3. Use these settings:"
|
||||
echo " - Site name: ${CYAN}$site_name${NC}"
|
||||
echo " - Local site domain: ${CYAN}$domain${NC}"
|
||||
echo " - PHP version: 8.0 or higher"
|
||||
echo " - Web server: nginx (preferred)"
|
||||
echo " - MySQL version: 8.0+"
|
||||
|
||||
if [ "$multisite" = true ]; then
|
||||
echo ""
|
||||
echo "4. After site creation, convert to multisite:"
|
||||
echo " - Open Site Shell in LocalWP"
|
||||
echo " - Run: wp core multisite-convert --subdomains=0"
|
||||
echo " - Update wp-config.php if needed"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_info "After creating the site, run: npm run localwp:sync"
|
||||
echo ""
|
||||
|
||||
# Wait for user to create site
|
||||
read -r -p "Press Enter after you've created the site in LocalWP..."
|
||||
|
||||
if site_exists "$site_name"; then
|
||||
log_success "Site detected at: $site_path"
|
||||
sync_plugin "$site_name"
|
||||
|
||||
# Install recommended plugins
|
||||
install_recommended_plugins "$site_name"
|
||||
|
||||
show_site_info "$site_name" "$domain" "$multisite"
|
||||
else
|
||||
log_warning "Site not found at expected location"
|
||||
log_info "Expected path: $site_path"
|
||||
log_info "You can run 'npm run localwp:sync' later to sync files"
|
||||
fi
|
||||
}
|
||||
|
||||
# Install recommended plugins (matching Playground blueprint)
|
||||
install_recommended_plugins() {
|
||||
local site_name="$1"
|
||||
local wp_path=$(get_wp_path "$site_name")
|
||||
|
||||
log_info "Note: Install these plugins to match Playground environment:"
|
||||
echo " - Plugin Toggle (plugin-toggle)"
|
||||
echo " - Kadence Blocks (kadence-blocks)"
|
||||
echo ""
|
||||
log_info "You can install them via LocalWP's WP Admin or Site Shell"
|
||||
local site_name="$1"
|
||||
local wp_path
|
||||
wp_path=$(get_wp_path "$site_name")
|
||||
|
||||
log_info "Note: Install these plugins to match Playground environment:"
|
||||
echo " - Plugin Toggle (plugin-toggle)"
|
||||
echo " - Kadence Blocks (kadence-blocks)"
|
||||
echo ""
|
||||
log_info "You can install them via LocalWP's WP Admin or Site Shell"
|
||||
}
|
||||
|
||||
# Show site information
|
||||
show_site_info() {
|
||||
local site_name="$1"
|
||||
local domain="$2"
|
||||
local multisite="$3"
|
||||
|
||||
local site_path=$(get_site_path "$site_name")
|
||||
local plugin_path=$(get_plugin_path "$site_name")
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " LocalWP Site Ready"
|
||||
echo "============================================"
|
||||
echo " Site: $site_name"
|
||||
echo " URL: http://$domain"
|
||||
echo " Admin: http://$domain/wp-admin/"
|
||||
echo " Plugin Path: $plugin_path"
|
||||
echo "============================================"
|
||||
|
||||
if [ "$multisite" = true ]; then
|
||||
echo " Network Admin: http://$domain/wp-admin/network/"
|
||||
echo "============================================"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_info "Remember to:"
|
||||
echo " 1. Start the site in LocalWP"
|
||||
echo " 2. Activate the plugin in WordPress admin"
|
||||
echo " 3. Run 'npm run localwp:sync' after making changes"
|
||||
echo ""
|
||||
local site_name="$1"
|
||||
local domain="$2"
|
||||
local multisite="$3"
|
||||
|
||||
local site_path
|
||||
site_path=$(get_site_path "$site_name")
|
||||
local plugin_path
|
||||
plugin_path=$(get_plugin_path "$site_name")
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " LocalWP Site Ready"
|
||||
echo "============================================"
|
||||
echo " Site: $site_name"
|
||||
echo " URL: http://$domain"
|
||||
echo " Admin: http://$domain/wp-admin/"
|
||||
echo " Plugin Path: $plugin_path"
|
||||
echo "============================================"
|
||||
|
||||
if [ "$multisite" = true ]; then
|
||||
echo " Network Admin: http://$domain/wp-admin/network/"
|
||||
echo "============================================"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_info "Remember to:"
|
||||
echo " 1. Start the site in LocalWP"
|
||||
echo " 2. Activate the plugin in WordPress admin"
|
||||
echo " 3. Run 'npm run localwp:sync' after making changes"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Reset site to clean state
|
||||
reset_site() {
|
||||
local site_name="${1:-$SINGLE_SITE_NAME}"
|
||||
|
||||
if ! site_exists "$site_name"; then
|
||||
log_error "Site '$site_name' does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_warning "This will delete the plugin files and resync them."
|
||||
read -p "Continue? (y/n) " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
local plugin_path=$(get_plugin_path "$site_name")
|
||||
|
||||
log_info "Removing plugin files..."
|
||||
rm -rf "$plugin_path"
|
||||
|
||||
log_info "Resyncing plugin..."
|
||||
sync_plugin "$site_name"
|
||||
|
||||
log_success "Site reset complete"
|
||||
else
|
||||
log_info "Reset cancelled"
|
||||
fi
|
||||
local site_name="${1:-$SINGLE_SITE_NAME}"
|
||||
|
||||
if ! site_exists "$site_name"; then
|
||||
log_error "Site '$site_name' does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_warning "This will delete the plugin files and resync them."
|
||||
read -p "Continue? (y/n) " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
local plugin_path
|
||||
plugin_path=$(get_plugin_path "$site_name")
|
||||
|
||||
log_info "Removing plugin files..."
|
||||
rm -rf "$plugin_path"
|
||||
|
||||
log_info "Resyncing plugin..."
|
||||
sync_plugin "$site_name"
|
||||
|
||||
log_success "Site reset complete"
|
||||
else
|
||||
log_info "Reset cancelled"
|
||||
fi
|
||||
}
|
||||
|
||||
# Sync all existing sites
|
||||
sync_all() {
|
||||
local synced=0
|
||||
|
||||
for site_name in "$SINGLE_SITE_NAME" "$MULTISITE_NAME"; do
|
||||
if site_exists "$site_name"; then
|
||||
sync_plugin "$site_name"
|
||||
synced=$((synced + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $synced -eq 0 ]; then
|
||||
log_warning "No LocalWP sites found for this plugin"
|
||||
log_info "Run 'npm run localwp:create' to create one"
|
||||
else
|
||||
log_success "Synced $synced site(s)"
|
||||
fi
|
||||
local synced=0
|
||||
|
||||
for site_name in "$SINGLE_SITE_NAME" "$MULTISITE_NAME"; do
|
||||
if site_exists "$site_name"; then
|
||||
sync_plugin "$site_name"
|
||||
synced=$((synced + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $synced -eq 0 ]; then
|
||||
log_warning "No LocalWP sites found for this plugin"
|
||||
log_info "Run 'npm run localwp:create' to create one"
|
||||
else
|
||||
log_success "Synced $synced site(s)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Show info about all sites
|
||||
show_info() {
|
||||
echo ""
|
||||
echo "LocalWP Sites for $PLUGIN_SLUG"
|
||||
echo "==============================="
|
||||
|
||||
for site_name in "$SINGLE_SITE_NAME" "$MULTISITE_NAME"; do
|
||||
local site_path=$(get_site_path "$site_name")
|
||||
|
||||
if site_exists "$site_name"; then
|
||||
echo ""
|
||||
echo " ${GREEN}✓${NC} $site_name"
|
||||
echo " Path: $site_path"
|
||||
|
||||
local plugin_path=$(get_plugin_path "$site_name")
|
||||
if [ -d "$plugin_path" ]; then
|
||||
echo " Plugin: ${GREEN}Installed${NC}"
|
||||
else
|
||||
echo " Plugin: ${YELLOW}Not synced${NC}"
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo " ${YELLOW}○${NC} $site_name (not created)"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " npm run localwp:create Create single site"
|
||||
echo " npm run localwp:create:multisite Create multisite"
|
||||
echo " npm run localwp:sync Sync plugin files"
|
||||
echo " npm run localwp:reset Reset plugin files"
|
||||
echo ""
|
||||
echo ""
|
||||
echo "LocalWP Sites for $PLUGIN_SLUG"
|
||||
echo "==============================="
|
||||
|
||||
for site_name in "$SINGLE_SITE_NAME" "$MULTISITE_NAME"; do
|
||||
local site_path
|
||||
site_path=$(get_site_path "$site_name")
|
||||
|
||||
if site_exists "$site_name"; then
|
||||
echo ""
|
||||
echo " ${GREEN}✓${NC} $site_name"
|
||||
echo " Path: $site_path"
|
||||
|
||||
local plugin_path
|
||||
plugin_path=$(get_plugin_path "$site_name")
|
||||
if [ -d "$plugin_path" ]; then
|
||||
echo " Plugin: ${GREEN}Installed${NC}"
|
||||
else
|
||||
echo " Plugin: ${YELLOW}Not synced${NC}"
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo " ${YELLOW}○${NC} $site_name (not created)"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " npm run localwp:create Create single site"
|
||||
echo " npm run localwp:create:multisite Create multisite"
|
||||
echo " npm run localwp:sync Sync plugin files"
|
||||
echo " npm run localwp:reset Reset plugin files"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main command handler
|
||||
case "${1:-}" in
|
||||
create)
|
||||
shift
|
||||
create_site "$@"
|
||||
;;
|
||||
sync)
|
||||
sync_all
|
||||
;;
|
||||
reset)
|
||||
shift
|
||||
reset_site "$@"
|
||||
;;
|
||||
info)
|
||||
show_info
|
||||
;;
|
||||
*)
|
||||
echo "LocalWP Integration Script"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " $0 create [--multisite] Create a new LocalWP site"
|
||||
echo " $0 sync Sync plugin files to all sites"
|
||||
echo " $0 reset [site-name] Reset site plugin to clean state"
|
||||
echo " $0 info Show info about LocalWP sites"
|
||||
echo ""
|
||||
echo "npm scripts:"
|
||||
echo " npm run localwp:create Create single site"
|
||||
echo " npm run localwp:create:multisite Create multisite"
|
||||
echo " npm run localwp:sync Sync plugin files"
|
||||
echo " npm run localwp:reset Reset plugin files"
|
||||
echo ""
|
||||
echo "URL Patterns:"
|
||||
echo " Single site: http://${PLUGIN_SLUG}-single.local"
|
||||
echo " Multisite: http://${PLUGIN_SLUG}-multisite.local"
|
||||
echo ""
|
||||
exit 1
|
||||
;;
|
||||
create)
|
||||
shift
|
||||
create_site "$@"
|
||||
;;
|
||||
sync)
|
||||
sync_all
|
||||
;;
|
||||
reset)
|
||||
shift
|
||||
reset_site "$@"
|
||||
;;
|
||||
info)
|
||||
show_info
|
||||
;;
|
||||
*)
|
||||
echo "LocalWP Integration Script"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " $0 create [--multisite] Create a new LocalWP site"
|
||||
echo " $0 sync Sync plugin files to all sites"
|
||||
echo " $0 reset [site-name] Reset site plugin to clean state"
|
||||
echo " $0 info Show info about LocalWP sites"
|
||||
echo ""
|
||||
echo "npm scripts:"
|
||||
echo " npm run localwp:create Create single site"
|
||||
echo " npm run localwp:create:multisite Create multisite"
|
||||
echo " npm run localwp:sync Sync plugin files"
|
||||
echo " npm run localwp:reset Reset plugin files"
|
||||
echo ""
|
||||
echo "URL Patterns:"
|
||||
echo " Single site: http://${PLUGIN_SLUG}-single.local"
|
||||
echo " Multisite: http://${PLUGIN_SLUG}-multisite.local"
|
||||
echo ""
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -1,126 +1,139 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Make this script executable
|
||||
chmod +x "$0"
|
||||
|
||||
# Check if environment type is provided
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 [single|multisite|playground-single|playground-multisite]"
|
||||
exit 1
|
||||
echo "Usage: $0 [single|multisite|playground-single|playground-multisite]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ENV_TYPE=$1
|
||||
|
||||
# Function to check if a command exists
|
||||
command_exists() {
|
||||
command -v "$1" &> /dev/null
|
||||
command -v "$1" &>/dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
# PID of the background Python HTTP server (set when started).
|
||||
PYTHON_PID=""
|
||||
|
||||
# Function to clean up resources on exit.
|
||||
cleanup() {
|
||||
if [ -n "$PYTHON_PID" ]; then
|
||||
echo "Stopping Python HTTP server (PID: $PYTHON_PID)..."
|
||||
kill "$PYTHON_PID" 2>/dev/null || true
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Trap EXIT, INT, and TERM so the server is always stopped on script exit.
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Function to install wp-env if needed
|
||||
install_wp_env() {
|
||||
if ! command_exists wp-env; then
|
||||
echo "wp-env is not installed. Installing..."
|
||||
npm install -g @wordpress/env
|
||||
fi
|
||||
if ! command_exists wp-env; then
|
||||
echo "wp-env is not installed. Installing..."
|
||||
npm install -g @wordpress/env
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to install wp-playground if needed
|
||||
install_wp_playground() {
|
||||
# Check if we have a local installation
|
||||
if [ ! -d "node_modules/@wp-playground" ]; then
|
||||
echo "WordPress Playground is not installed locally. Installing..."
|
||||
npm install --save-dev @wp-playground/client @wp-playground/blueprints
|
||||
fi
|
||||
# Check if we have a local installation
|
||||
if [ ! -d "node_modules/@wp-playground" ]; then
|
||||
echo "WordPress Playground is not installed locally. Installing..."
|
||||
npm install --save-dev @wp-playground/client @wp-playground/blueprints
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$ENV_TYPE" == "single" ]; then
|
||||
echo "Setting up single site environment..."
|
||||
if [ "$ENV_TYPE" = "single" ]; then
|
||||
echo "Setting up single site environment..."
|
||||
|
||||
# Install wp-env if needed
|
||||
install_wp_env
|
||||
# Install wp-env if needed
|
||||
install_wp_env
|
||||
|
||||
# Start the environment
|
||||
wp-env start
|
||||
# Start the environment
|
||||
wp-env start
|
||||
|
||||
# Wait for WordPress to be ready with a timeout
|
||||
MAX_ATTEMPTS=30
|
||||
ATTEMPT=0
|
||||
echo "Waiting for WordPress to be ready..."
|
||||
until wp-env run cli wp core is-installed || [ $ATTEMPT -ge $MAX_ATTEMPTS ]; do
|
||||
ATTEMPT=$((ATTEMPT+1))
|
||||
echo "Attempt $ATTEMPT/$MAX_ATTEMPTS..."
|
||||
sleep 2
|
||||
done
|
||||
# Wait for WordPress to be ready with a timeout
|
||||
MAX_ATTEMPTS=30
|
||||
ATTEMPT=0
|
||||
echo "Waiting for WordPress to be ready..."
|
||||
until wp-env run cli wp core is-installed || [ $ATTEMPT -ge $MAX_ATTEMPTS ]; do
|
||||
ATTEMPT=$((ATTEMPT + 1))
|
||||
echo "Attempt $ATTEMPT/$MAX_ATTEMPTS..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then
|
||||
echo "Timed out waiting for WordPress to be ready."
|
||||
exit 1
|
||||
fi
|
||||
if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then
|
||||
echo "Timed out waiting for WordPress to be ready."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Activate our plugin
|
||||
if ! wp-env run cli wp plugin activate wp-plugin-starter-template-for-ai-coding; then
|
||||
echo "Failed to activate plugin. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
# Activate our plugin
|
||||
if ! wp-env run cli wp plugin activate wp-plugin-starter-template-for-ai-coding; then
|
||||
echo "Failed to activate plugin. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "WordPress Single Site environment is ready!"
|
||||
echo "Site: http://localhost:8888"
|
||||
echo "Admin login: admin / password"
|
||||
echo "WordPress Single Site environment is ready!"
|
||||
echo "Site: http://localhost:8888"
|
||||
echo "Admin login: admin / password"
|
||||
|
||||
elif [ "$ENV_TYPE" == "multisite" ]; then
|
||||
echo "Setting up multisite environment..."
|
||||
elif [ "$ENV_TYPE" = "multisite" ]; then
|
||||
echo "Setting up multisite environment..."
|
||||
|
||||
# Install wp-env if needed
|
||||
install_wp_env
|
||||
# Install wp-env if needed
|
||||
install_wp_env
|
||||
|
||||
# Start the environment with multisite configuration
|
||||
wp-env start --config=.wp-env.multisite.json
|
||||
# Start the environment with multisite configuration
|
||||
wp-env start --config=.wp-env.multisite.json
|
||||
|
||||
# Wait for WordPress to be ready with a timeout
|
||||
MAX_ATTEMPTS=30
|
||||
ATTEMPT=0
|
||||
echo "Waiting for WordPress to be ready..."
|
||||
until wp-env run cli wp core is-installed || [ $ATTEMPT -ge $MAX_ATTEMPTS ]; do
|
||||
ATTEMPT=$((ATTEMPT+1))
|
||||
echo "Attempt $ATTEMPT/$MAX_ATTEMPTS..."
|
||||
sleep 2
|
||||
done
|
||||
# Wait for WordPress to be ready with a timeout
|
||||
MAX_ATTEMPTS=30
|
||||
ATTEMPT=0
|
||||
echo "Waiting for WordPress to be ready..."
|
||||
until wp-env run cli wp core is-installed || [ $ATTEMPT -ge $MAX_ATTEMPTS ]; do
|
||||
ATTEMPT=$((ATTEMPT + 1))
|
||||
echo "Attempt $ATTEMPT/$MAX_ATTEMPTS..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then
|
||||
echo "Timed out waiting for WordPress to be ready."
|
||||
exit 1
|
||||
fi
|
||||
if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then
|
||||
echo "Timed out waiting for WordPress to be ready."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a test site
|
||||
if ! wp-env run cli wp site create --slug=testsite --title="Test Site" --email=admin@example.com; then
|
||||
echo "Failed to create test site. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
# Create a test site
|
||||
if ! wp-env run cli wp site create --slug=testsite --title="Test Site" --email=admin@example.com; then
|
||||
echo "Failed to create test site. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Network activate our plugin
|
||||
if ! wp-env run cli wp plugin activate wp-plugin-starter-template-for-ai-coding --network; then
|
||||
echo "Failed to activate plugin. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
# Network activate our plugin
|
||||
if ! wp-env run cli wp plugin activate wp-plugin-starter-template-for-ai-coding --network; then
|
||||
echo "Failed to activate plugin. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "WordPress Multisite environment is ready!"
|
||||
echo "Main site: http://localhost:8888"
|
||||
echo "Test site: http://localhost:8888/testsite"
|
||||
echo "Admin login: admin / password"
|
||||
echo "WordPress Multisite environment is ready!"
|
||||
echo "Main site: http://localhost:8888"
|
||||
echo "Test site: http://localhost:8888/testsite"
|
||||
echo "Admin login: admin / password"
|
||||
|
||||
elif [ "$ENV_TYPE" == "playground-single" ]; then
|
||||
echo "Setting up WordPress Playground single site environment..."
|
||||
elif [ "$ENV_TYPE" = "playground-single" ]; then
|
||||
echo "Setting up WordPress Playground single site environment..."
|
||||
|
||||
# Install wp-playground if needed
|
||||
install_wp_playground
|
||||
# Install wp-playground if needed
|
||||
install_wp_playground
|
||||
|
||||
# Create plugin zip
|
||||
echo "Creating plugin zip..."
|
||||
mkdir -p dist
|
||||
zip -r dist/plugin.zip . -x "node_modules/*" "dist/*" ".git/*"
|
||||
# Create plugin zip
|
||||
echo "Creating plugin zip..."
|
||||
mkdir -p dist
|
||||
zip -r dist/plugin.zip . -x "node_modules/*" "dist/*" ".git/*"
|
||||
|
||||
# Update blueprint to use local plugin
|
||||
cat > playground/blueprint.json << EOF
|
||||
# Update blueprint to use local plugin
|
||||
cat >playground/blueprint.json <<EOF
|
||||
{
|
||||
"landingPage": "/wp-admin/",
|
||||
"preferredVersions": {
|
||||
@@ -148,46 +161,49 @@ elif [ "$ENV_TYPE" == "playground-single" ]; then
|
||||
}
|
||||
EOF
|
||||
|
||||
# Start WordPress Playground
|
||||
echo "Starting WordPress Playground..."
|
||||
if command_exists python3; then
|
||||
python3 -m http.server 8888 --directory playground &
|
||||
echo "Opening WordPress Playground in your browser..."
|
||||
if command_exists open; then
|
||||
open http://localhost:8888/index.html
|
||||
elif command_exists xdg-open; then
|
||||
xdg-open http://localhost:8888/index.html
|
||||
elif command_exists start; then
|
||||
start http://localhost:8888/index.html
|
||||
else
|
||||
echo "Please open http://localhost:8888/index.html in your browser"
|
||||
fi
|
||||
else
|
||||
echo "Python3 is not installed. Please open playground/index.html in your browser."
|
||||
fi
|
||||
# Start WordPress Playground
|
||||
echo "Starting WordPress Playground..."
|
||||
if command_exists python3; then
|
||||
python3 -m http.server 8888 --directory playground &
|
||||
PYTHON_PID=$!
|
||||
echo "Started Python HTTP server with PID: $PYTHON_PID"
|
||||
echo "Opening WordPress Playground in your browser..."
|
||||
if command_exists open; then
|
||||
open http://localhost:8888/index.html
|
||||
elif command_exists xdg-open; then
|
||||
xdg-open http://localhost:8888/index.html
|
||||
elif command_exists start; then
|
||||
start http://localhost:8888/index.html
|
||||
else
|
||||
echo "Please open http://localhost:8888/index.html in your browser"
|
||||
fi
|
||||
else
|
||||
echo "Python3 is not installed. Please open playground/index.html in your browser."
|
||||
fi
|
||||
|
||||
# Wait for WordPress Playground to be ready
|
||||
echo "Waiting for WordPress Playground to be ready..."
|
||||
sleep 5
|
||||
# Wait for WordPress Playground to be ready
|
||||
echo "Waiting for WordPress Playground to be ready..."
|
||||
sleep 5
|
||||
|
||||
echo "WordPress Playground Single Site environment is ready!"
|
||||
echo "Site: http://localhost:8888"
|
||||
echo "Admin login: admin / password"
|
||||
echo "Press Ctrl+C to stop the server when done."
|
||||
echo "WordPress Playground Single Site environment is ready!"
|
||||
echo "Site: http://localhost:8888"
|
||||
echo "Admin login: admin / password"
|
||||
echo "Press Ctrl+C to stop the server when done."
|
||||
|
||||
elif [ "$ENV_TYPE" == "playground-multisite" ]; then
|
||||
echo "Setting up WordPress Playground multisite environment..."
|
||||
elif [ "$ENV_TYPE" = "playground-multisite" ]; then
|
||||
echo "Setting up WordPress Playground multisite environment..."
|
||||
|
||||
# Install wp-playground if needed
|
||||
install_wp_playground
|
||||
# Install wp-playground if needed
|
||||
install_wp_playground
|
||||
|
||||
# Create plugin zip
|
||||
echo "Creating plugin zip..."
|
||||
mkdir -p dist
|
||||
zip -r dist/plugin.zip . -x "node_modules/*" "dist/*" ".git/*"
|
||||
# Create plugin zip
|
||||
echo "Creating plugin zip..."
|
||||
mkdir -p dist
|
||||
zip -r dist/plugin.zip . -x "node_modules/*" "dist/*" ".git/*"
|
||||
|
||||
# Update blueprint to use local plugin
|
||||
cat > playground/multisite-blueprint.json << EOF
|
||||
# Update blueprint to use local plugin
|
||||
# shellcheck disable=SC2154
|
||||
cat >playground/multisite-blueprint.json <<EOF
|
||||
{
|
||||
"landingPage": "/wp-admin/network/",
|
||||
"preferredVersions": {
|
||||
@@ -255,35 +271,37 @@ elif [ "$ENV_TYPE" == "playground-multisite" ]; then
|
||||
}
|
||||
EOF
|
||||
|
||||
# Start WordPress Playground
|
||||
echo "Starting WordPress Playground..."
|
||||
if command_exists python3; then
|
||||
python3 -m http.server 8888 --directory playground &
|
||||
echo "Opening WordPress Playground in your browser..."
|
||||
if command_exists open; then
|
||||
open http://localhost:8888/multisite.html
|
||||
elif command_exists xdg-open; then
|
||||
xdg-open http://localhost:8888/multisite.html
|
||||
elif command_exists start; then
|
||||
start http://localhost:8888/multisite.html
|
||||
else
|
||||
echo "Please open http://localhost:8888/multisite.html in your browser"
|
||||
fi
|
||||
else
|
||||
echo "Python3 is not installed. Please open playground/multisite.html in your browser."
|
||||
fi
|
||||
# Start WordPress Playground
|
||||
echo "Starting WordPress Playground..."
|
||||
if command_exists python3; then
|
||||
python3 -m http.server 8888 --directory playground &
|
||||
PYTHON_PID=$!
|
||||
echo "Started Python HTTP server with PID: $PYTHON_PID"
|
||||
echo "Opening WordPress Playground in your browser..."
|
||||
if command_exists open; then
|
||||
open http://localhost:8888/multisite.html
|
||||
elif command_exists xdg-open; then
|
||||
xdg-open http://localhost:8888/multisite.html
|
||||
elif command_exists start; then
|
||||
start http://localhost:8888/multisite.html
|
||||
else
|
||||
echo "Please open http://localhost:8888/multisite.html in your browser"
|
||||
fi
|
||||
else
|
||||
echo "Python3 is not installed. Please open playground/multisite.html in your browser."
|
||||
fi
|
||||
|
||||
# Wait for WordPress Playground to be ready
|
||||
echo "Waiting for WordPress Playground to be ready..."
|
||||
sleep 5
|
||||
# Wait for WordPress Playground to be ready
|
||||
echo "Waiting for WordPress Playground to be ready..."
|
||||
sleep 5
|
||||
|
||||
echo "WordPress Playground Multisite environment is ready!"
|
||||
echo "Main site: http://localhost:8888"
|
||||
echo "Test site: http://localhost:8888/testsite"
|
||||
echo "Admin login: admin / password"
|
||||
echo "Press Ctrl+C to stop the server when done."
|
||||
echo "WordPress Playground Multisite environment is ready!"
|
||||
echo "Main site: http://localhost:8888"
|
||||
echo "Test site: http://localhost:8888/testsite"
|
||||
echo "Admin login: admin / password"
|
||||
echo "Press Ctrl+C to stop the server when done."
|
||||
|
||||
else
|
||||
echo "Invalid environment type. Use 'single', 'multisite', 'playground-single', or 'playground-multisite'."
|
||||
exit 1
|
||||
echo "Invalid environment type. Use 'single', 'multisite', 'playground-single', or 'playground-multisite'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
91
build.sh
91
build.sh
@@ -1,13 +1,14 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# WordPress Plugin Build Script
|
||||
# This script creates a clean build of the plugin for distribution
|
||||
|
||||
# Check if version is provided
|
||||
if [ -z "$1" ]; then
|
||||
echo "❌ Error: Version number is required"
|
||||
echo "Usage: ./build.sh <version>"
|
||||
exit 1
|
||||
echo "❌ Error: Version number is required"
|
||||
echo "Usage: ./build.sh <version>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION=$1
|
||||
@@ -22,15 +23,15 @@ mkdir -p "$BUILD_DIR"
|
||||
|
||||
# Run code quality checks
|
||||
echo "Running code quality checks..."
|
||||
if command -v composer &> /dev/null; then
|
||||
echo "Running PHPCS..."
|
||||
composer run phpcs || { echo "⚠️ PHPCS found issues. Consider running 'composer run phpcbf' to fix them."; }
|
||||
if command -v composer &>/dev/null; then
|
||||
echo "Running PHPCS..."
|
||||
composer run phpcs || { echo "⚠️ PHPCS found issues. Consider running 'composer run phpcbf' to fix them."; }
|
||||
|
||||
# Uncomment the following line to automatically fix coding standards issues
|
||||
# echo "Running PHPCBF..."
|
||||
# composer run phpcbf
|
||||
# Uncomment the following line to automatically fix coding standards issues
|
||||
# echo "Running PHPCBF..."
|
||||
# composer run phpcbf
|
||||
else
|
||||
echo "⚠️ Composer not found, skipping code quality checks"
|
||||
echo "⚠️ Composer not found, skipping code quality checks"
|
||||
fi
|
||||
|
||||
# Install composer dependencies
|
||||
@@ -39,72 +40,72 @@ composer install --no-dev --optimize-autoloader
|
||||
|
||||
# Copy plugin files to build directory
|
||||
echo "Copying plugin files..."
|
||||
cp -R *.php "$BUILD_DIR/"
|
||||
cp -R ./*.php "$BUILD_DIR/"
|
||||
cp -R README.md LICENSE CHANGELOG.md readme.txt composer.json "$BUILD_DIR/"
|
||||
|
||||
# Copy directories
|
||||
echo "Copying directories..."
|
||||
mkdir -p "$BUILD_DIR/admin" "$BUILD_DIR/includes" "$BUILD_DIR/languages" "$BUILD_DIR/assets"
|
||||
cp -R admin/* "$BUILD_DIR/admin/"
|
||||
cp -R includes/* "$BUILD_DIR/includes/"
|
||||
cp -R languages/* "$BUILD_DIR/languages/"
|
||||
cp -R ./admin/* "$BUILD_DIR/admin/"
|
||||
cp -R ./includes/* "$BUILD_DIR/includes/"
|
||||
cp -R ./languages/* "$BUILD_DIR/languages/"
|
||||
|
||||
# Create assets directory structure
|
||||
mkdir -p "$BUILD_DIR/assets/banner" "$BUILD_DIR/assets/icon" "$BUILD_DIR/assets/screenshots"
|
||||
|
||||
# Copy assets if they exist
|
||||
if [ -d "assets/banner" ]; then
|
||||
cp -R assets/banner/* "$BUILD_DIR/assets/banner/"
|
||||
cp -R assets/banner/* "$BUILD_DIR/assets/banner/"
|
||||
fi
|
||||
|
||||
if [ -d "assets/icon" ]; then
|
||||
cp -R assets/icon/* "$BUILD_DIR/assets/icon/"
|
||||
cp -R assets/icon/* "$BUILD_DIR/assets/icon/"
|
||||
fi
|
||||
|
||||
if [ -d "assets/screenshots" ]; then
|
||||
cp -R assets/screenshots/* "$BUILD_DIR/assets/screenshots/"
|
||||
cp -R assets/screenshots/* "$BUILD_DIR/assets/screenshots/"
|
||||
fi
|
||||
|
||||
# Copy vendor directory if it exists
|
||||
if [ -d "vendor" ]; then
|
||||
cp -R vendor "$BUILD_DIR/"
|
||||
cp -R vendor "$BUILD_DIR/"
|
||||
fi
|
||||
|
||||
# Create ZIP file
|
||||
# Create ZIP file.
|
||||
echo "Creating ZIP file..."
|
||||
cd build
|
||||
zip -r "../$ZIP_FILE" "$PLUGIN_SLUG" -x "*.DS_Store" -x "*.git*" -x "*.github*"
|
||||
cd ..
|
||||
(
|
||||
cd build || exit 1
|
||||
zip -r "../$ZIP_FILE" "$PLUGIN_SLUG" -x "*.DS_Store" -x "*.git*" -x "*.github*"
|
||||
)
|
||||
|
||||
# Check if ZIP file was created successfully
|
||||
if [ -f "$ZIP_FILE" ]; then
|
||||
echo "✅ Build successful: $ZIP_FILE created"
|
||||
echo "File path: $(pwd)/$ZIP_FILE"
|
||||
echo "✅ Build successful: $ZIP_FILE created"
|
||||
echo "File path: $(pwd)/$ZIP_FILE"
|
||||
|
||||
# Deploy to local WordPress installation if environment variable is set
|
||||
if [ -n "$WP_LOCAL_PLUGIN_DIR" ]; then
|
||||
echo "\nDeploying to local WordPress installation..."
|
||||
echo "Deploying to local WordPress installation..."
|
||||
# Deploy to local WordPress installation if environment variable is set
|
||||
if [ -n "${WP_LOCAL_PLUGIN_DIR:-}" ]; then
|
||||
printf '\nDeploying to local WordPress installation...\n'
|
||||
|
||||
# Remove existing plugin directory
|
||||
rm -rf "$WP_LOCAL_PLUGIN_DIR/$PLUGIN_SLUG"
|
||||
# Remove existing plugin directory.
|
||||
rm -rf "${WP_LOCAL_PLUGIN_DIR:?}/$PLUGIN_SLUG"
|
||||
|
||||
# Copy files to local WordPress installation
|
||||
rsync -av --exclude=".git" --exclude=".github" --exclude=".DS_Store" \
|
||||
"$BUILD_DIR/" "$WP_LOCAL_PLUGIN_DIR/$PLUGIN_SLUG"
|
||||
# Copy files to local WordPress installation
|
||||
rsync -av --exclude=".git" --exclude=".github" --exclude=".DS_Store" \
|
||||
"$BUILD_DIR/" "$WP_LOCAL_PLUGIN_DIR/$PLUGIN_SLUG"
|
||||
|
||||
# Clear WordPress transients if WP-CLI is available
|
||||
if command -v wp &> /dev/null; then
|
||||
echo "Clearing WordPress transients..."
|
||||
wp transient delete --all --path="$WP_LOCAL_PLUGIN_DIR/../.."
|
||||
else
|
||||
echo "⚠️ WP-CLI not found, skipping transient clearing"
|
||||
fi
|
||||
# Clear WordPress transients if WP-CLI is available
|
||||
if command -v wp &>/dev/null; then
|
||||
echo "Clearing WordPress transients..."
|
||||
wp transient delete --all --path="$WP_LOCAL_PLUGIN_DIR/../.."
|
||||
else
|
||||
echo "⚠️ WP-CLI not found, skipping transient clearing"
|
||||
fi
|
||||
|
||||
echo "✅ Local deployment successful!"
|
||||
echo "Plugin deployed to: $WP_LOCAL_PLUGIN_DIR/$PLUGIN_SLUG"
|
||||
fi
|
||||
echo "✅ Local deployment successful!"
|
||||
echo "Plugin deployed to: $WP_LOCAL_PLUGIN_DIR/$PLUGIN_SLUG"
|
||||
fi
|
||||
else
|
||||
echo "❌ Build failed: ZIP file was not created"
|
||||
exit 1
|
||||
echo "❌ Build failed: ZIP file was not created"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -12,6 +12,6 @@ module.exports = defineConfig({
|
||||
},
|
||||
// Add configuration for WordPress Playground
|
||||
experimentalWebKitSupport: true,
|
||||
chromeWebSecurity: false
|
||||
}
|
||||
chromeWebSecurity: false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
/* eslint-env mocha, jquery, cypress */
|
||||
describe('WordPress Playground Single Site Tests', () => {
|
||||
describe('WordPress Playground Single Site Tests', {
|
||||
retries: {
|
||||
runMode: 2,
|
||||
openMode: 0,
|
||||
},
|
||||
}, () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/', { timeout: 30000 });
|
||||
});
|
||||
@@ -18,14 +23,22 @@ describe('WordPress Playground Single Site Tests', () => {
|
||||
cy.visit('/wp-admin/plugins.php', { timeout: 30000 });
|
||||
|
||||
cy.get('body', { timeout: 15000 }).then(($body) => {
|
||||
if ($body.text().includes('Plugin Toggle')) {
|
||||
const hasPluginToggle = $body.text().includes('Plugin Toggle');
|
||||
const hasKadenceBlocks = $body.text().includes('Kadence Blocks');
|
||||
|
||||
expect(
|
||||
hasPluginToggle || hasKadenceBlocks,
|
||||
'At least one blueprint plugin should be present in the plugins table',
|
||||
).to.be.true;
|
||||
|
||||
if (hasPluginToggle) {
|
||||
cy.contains('tr', 'Plugin Toggle').should('exist');
|
||||
cy.contains('tr', 'Plugin Toggle').find('.deactivate').should('exist');
|
||||
} else {
|
||||
cy.log('Plugin Toggle not found, skipping check');
|
||||
}
|
||||
|
||||
if ($body.text().includes('Kadence Blocks')) {
|
||||
if (hasKadenceBlocks) {
|
||||
cy.contains('tr', 'Kadence Blocks').find('.deactivate').should('exist');
|
||||
} else {
|
||||
cy.log('Kadence Blocks plugin not found, skipping check');
|
||||
|
||||
@@ -1,30 +1,75 @@
|
||||
describe('WordPress Single Site Tests', () => {
|
||||
it('Can access the site', () => {
|
||||
cy.visit('/');
|
||||
cy.get('body').should('exist');
|
||||
});
|
||||
/* eslint-env mocha, jquery, cypress */
|
||||
describe( 'WordPress Single Site Tests', () => {
|
||||
it( 'Can access the site', () => {
|
||||
cy.visit( '/' );
|
||||
cy.get( 'body' ).should( 'exist' );
|
||||
} );
|
||||
|
||||
it('Can login to the admin area', () => {
|
||||
cy.loginAsAdmin();
|
||||
cy.get('#wpadminbar').should('exist');
|
||||
cy.get('#dashboard-widgets').should('exist');
|
||||
});
|
||||
it( 'Can login to the admin area', () => {
|
||||
cy.loginAsAdmin();
|
||||
cy.get( '#wpadminbar' ).should( 'exist' );
|
||||
cy.get( '#dashboard-widgets' ).should( 'exist' );
|
||||
} );
|
||||
|
||||
it('Plugin is activated', () => {
|
||||
// Use our custom command to check and activate the plugin if needed
|
||||
cy.activatePlugin('wp-plugin-starter-template-for-ai-coding');
|
||||
it( 'Plugin is activated', () => {
|
||||
// Use our custom command to check and activate the plugin if needed.
|
||||
cy.activatePlugin( 'wp-plugin-starter-template-for-ai-coding' );
|
||||
|
||||
// Verify it's active
|
||||
cy.get('tr[data-slug="wp-plugin-starter-template-for-ai-coding"] .deactivate').should('exist');
|
||||
});
|
||||
// Verify it's active.
|
||||
cy.get( 'tr[data-slug="wp-plugin-starter-template-for-ai-coding"] .deactivate' ).should( 'exist' );
|
||||
} );
|
||||
|
||||
it('Plugin settings page loads correctly', () => {
|
||||
cy.loginAsAdmin();
|
||||
it( 'Plugin row is visible on the plugins page', () => {
|
||||
cy.loginAsAdmin();
|
||||
cy.visit( '/wp-admin/plugins.php' );
|
||||
|
||||
// Navigate to the plugin settings page (if it exists)
|
||||
cy.visit('/wp-admin/options-general.php?page=wp-plugin-starter-template');
|
||||
// Verify the plugin row exists with the correct slug.
|
||||
cy.get( 'tr[data-slug="wp-plugin-starter-template-for-ai-coding"]' ).should( 'exist' );
|
||||
|
||||
// This is a basic check - adjust based on your actual plugin's settings page
|
||||
cy.get('h1').should('contain', 'WP Plugin Starter Template');
|
||||
});
|
||||
});
|
||||
// Verify the plugin name is displayed.
|
||||
cy.get( 'tr[data-slug="wp-plugin-starter-template-for-ai-coding"] .plugin-title strong' )
|
||||
.should( 'contain', 'WordPress Plugin Starter Template' );
|
||||
} );
|
||||
|
||||
it( 'Update source selector link is present in the plugin row', () => {
|
||||
cy.loginAsAdmin();
|
||||
cy.visit( '/wp-admin/plugins.php' );
|
||||
|
||||
// The update source selector link should be rendered in the plugin row.
|
||||
cy.get( 'tr[data-slug="wp-plugin-starter-template-for-ai-coding"]' )
|
||||
.find( '.wpst-update-source-selector' )
|
||||
.should( 'exist' );
|
||||
} );
|
||||
|
||||
it( 'Update source modal opens and displays source options', () => {
|
||||
cy.loginAsAdmin();
|
||||
cy.visit( '/wp-admin/plugins.php' );
|
||||
|
||||
// Click the update source selector link to open the modal.
|
||||
cy.get( '.wpst-update-source-selector' ).first().click();
|
||||
|
||||
// Modal should be visible.
|
||||
cy.get( '#wpst-update-source-modal' ).should( 'be.visible' );
|
||||
|
||||
// Modal should contain the three update source options.
|
||||
cy.get( '#wpst-update-source-modal input[name="update_source"][value="wordpress.org"]' ).should( 'exist' );
|
||||
cy.get( '#wpst-update-source-modal input[name="update_source"][value="github"]' ).should( 'exist' );
|
||||
cy.get( '#wpst-update-source-modal input[name="update_source"][value="gitea"]' ).should( 'exist' );
|
||||
|
||||
// Save button should be present.
|
||||
cy.get( '#wpst-save-source' ).should( 'exist' );
|
||||
} );
|
||||
|
||||
it( 'Update source modal can be closed', () => {
|
||||
cy.loginAsAdmin();
|
||||
cy.visit( '/wp-admin/plugins.php' );
|
||||
|
||||
// Open the modal.
|
||||
cy.get( '.wpst-update-source-selector' ).first().click();
|
||||
cy.get( '#wpst-update-source-modal' ).should( 'be.visible' );
|
||||
|
||||
// Close the modal via the close button.
|
||||
cy.get( '#wpst-update-source-modal .wpst-modal-close' ).click();
|
||||
cy.get( '#wpst-update-source-modal' ).should( 'not.be.visible' );
|
||||
} );
|
||||
} );
|
||||
|
||||
@@ -46,8 +46,8 @@ class Admin {
|
||||
*/
|
||||
public function enqueue_admin_assets(): void {
|
||||
|
||||
// @phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
// @phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
// @phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
// @phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
// For production, use filter_input.
|
||||
$page = '';
|
||||
if ( defined( 'PHPUNIT_RUNNING' ) && PHPUNIT_RUNNING ) {
|
||||
@@ -64,15 +64,17 @@ class Admin {
|
||||
if ( ! $page || 'wp_plugin_starter_template_settings' !== $page ) {
|
||||
return;
|
||||
}
|
||||
// @phpcs:enable
|
||||
// @phpcs:enable
|
||||
|
||||
// Get the plugin version.
|
||||
$plugin_version = $this->core->get_plugin_version();
|
||||
|
||||
$plugin_url = $this->get_plugin_base_url();
|
||||
|
||||
// Enqueue styles.
|
||||
\wp_enqueue_style(
|
||||
'wpst-admin-styles',
|
||||
plugin_dir_url( dirname( __DIR__ ) ) . 'admin/css/admin-styles.css',
|
||||
$plugin_url . 'admin/css/admin-styles.css',
|
||||
array(), // Dependencies.
|
||||
$plugin_version // Version.
|
||||
);
|
||||
@@ -80,7 +82,7 @@ class Admin {
|
||||
// Enqueue admin scripts.
|
||||
\wp_enqueue_script(
|
||||
'wpst-admin-script',
|
||||
plugin_dir_url( dirname( __DIR__ ) ) . 'admin/js/admin-scripts.js',
|
||||
$plugin_url . 'admin/js/admin-scripts.js',
|
||||
array( 'jquery' ),
|
||||
$plugin_version, // Version.
|
||||
true
|
||||
@@ -99,4 +101,21 @@ class Admin {
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin base URL.
|
||||
*
|
||||
* @return string Plugin base URL with trailing slash.
|
||||
*/
|
||||
private function get_plugin_base_url(): string {
|
||||
if ( defined( 'WP_PLUGIN_STARTER_TEMPLATE_URL' ) ) {
|
||||
return WP_PLUGIN_STARTER_TEMPLATE_URL;
|
||||
}
|
||||
|
||||
if ( defined( 'WPST_PLUGIN_URL' ) ) {
|
||||
return WPST_PLUGIN_URL;
|
||||
}
|
||||
|
||||
return \plugin_dir_url( dirname( __DIR__, 2 ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
* Extend this file or create additional classes in this directory
|
||||
* to implement multisite features for your plugin.
|
||||
*
|
||||
* @package WP_Plugin_Starter_Template_For_AI_Coding
|
||||
* @package WPALLSTARS\PluginStarterTemplate
|
||||
*/
|
||||
|
||||
namespace WP_Plugin_Starter_Template_For_AI_Coding\Multisite;
|
||||
namespace WPALLSTARS\PluginStarterTemplate\Multisite;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
|
||||
1180
package-lock.json
generated
1180
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -28,7 +28,8 @@
|
||||
"test:phpunit": "composer test",
|
||||
"test:phpunit:multisite": "WP_MULTISITE=1 composer test",
|
||||
"build": "./build.sh",
|
||||
"lint:js": "eslint cypress/",
|
||||
"lint:js": "eslint cypress/ cypress.config.js",
|
||||
"lint:css": "stylelint \"**/*.css\" --allow-empty-input",
|
||||
"lint:php": "composer run-script phpcs",
|
||||
"lint:php:simple": "composer run-script phpcs:simple",
|
||||
"lint:phpstan": "composer run-script phpstan",
|
||||
@@ -36,7 +37,8 @@
|
||||
"fix:php": "composer run-script phpcbf",
|
||||
"fix:php:simple": "composer run-script phpcbf:simple",
|
||||
"test:php": "composer run-script test",
|
||||
"lint": "composer run-script lint",
|
||||
"lint:php-all": "composer run-script lint",
|
||||
"lint": "npm run lint:php-all && npm run lint:js && npm run lint:css",
|
||||
"fix": "composer run-script fix",
|
||||
"quality": "npm run lint && npm run test:php"
|
||||
},
|
||||
@@ -60,10 +62,12 @@
|
||||
"devDependencies": {
|
||||
"@wordpress/env": "^8.12.0",
|
||||
"@wp-playground/blueprints": "^3.0.22",
|
||||
"@wp-playground/client": "^3.0.22",
|
||||
"@wp-playground/cli": "^3.0.22",
|
||||
"@wp-playground/client": "^3.0.22",
|
||||
"cypress": "^13.17.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-cypress": "^2.15.1"
|
||||
"eslint-plugin-cypress": "^6.2.0",
|
||||
"stylelint": "^16.0.0",
|
||||
"stylelint-config-standard": "^36.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<exclude-pattern>*/build/*</exclude-pattern>
|
||||
<exclude-pattern>*/dist/*</exclude-pattern>
|
||||
|
||||
<!-- Command line arguments -->
|
||||
<!-- Command line arguments: combined short flags (-s shows sniff codes, -p shows progress) -->
|
||||
<arg value="sp"/>
|
||||
<arg name="extensions" value="php"/>
|
||||
<arg name="basepath" value="."/>
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
<exclude name="CamelCaseMethodName" />
|
||||
<exclude name="CamelCaseParameterName" />
|
||||
<exclude name="CamelCaseVariableName" />
|
||||
<!-- WordPress plugins use filter_input() for production and $_GET for testing; Superglobals rule is not applicable. -->
|
||||
<exclude name="Superglobals" />
|
||||
</rule>
|
||||
<rule ref="rulesets/design.xml" />
|
||||
<rule ref="rulesets/naming.xml">
|
||||
|
||||
@@ -5,13 +5,6 @@ parameters:
|
||||
- admin
|
||||
- wp-plugin-starter-template.php
|
||||
excludePaths:
|
||||
analyse:
|
||||
- vendor
|
||||
- node_modules
|
||||
- tests
|
||||
- bin
|
||||
- build
|
||||
- dist
|
||||
analyseAndScan:
|
||||
- vendor
|
||||
- node_modules
|
||||
|
||||
@@ -21,6 +21,6 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/wpallstars/wp-plugin-starter-template-for-ai-coding/main/playground/blueprint.json&_t=2" title="WordPress Playground Single Site Environment"></iframe>
|
||||
<iframe src="https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/wpallstars/wp-plugin-starter-template-for-ai-coding/main/playground/blueprint.json" title="WordPress Playground Single Site Environment"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"landingPage": "/wp-admin/",
|
||||
"login": true,
|
||||
"features": {
|
||||
"networking": true
|
||||
"networking": false
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
|
||||
@@ -150,7 +150,7 @@ When you receive feedback from these code quality tools, you can use AI assistan
|
||||
|
||||
1. Copy the output from the code quality tool
|
||||
2. Paste it into your AI assistant chat
|
||||
3. Ask the AI to help you understand and resolve the issues
|
||||
3. Request the AI's assistance to interpret and resolve the reported issues
|
||||
4. Apply the suggested fixes
|
||||
5. Commit the changes and verify that the issues are resolved
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ if ( getenv( 'WP_PHPUNIT__DIR' ) ) {
|
||||
// Include plugin files needed for tests.
|
||||
require_once WPST_PLUGIN_DIR . 'includes/class-core.php';
|
||||
require_once WPST_PLUGIN_DIR . 'includes/class-plugin.php';
|
||||
if ( file_exists( WPST_PLUGIN_DIR . 'admin/lib/admin.php' ) ) {
|
||||
require_once WPST_PLUGIN_DIR . 'admin/lib/admin.php';
|
||||
if ( file_exists( WPST_PLUGIN_DIR . 'includes/Admin/class-admin.php' ) ) {
|
||||
require_once WPST_PLUGIN_DIR . 'includes/Admin/class-admin.php';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,17 +101,12 @@ class AdminTest extends \WP_Mock\Tools\TestCase {
|
||||
'return' => 'wp_plugin_starter_template_settings',
|
||||
]);
|
||||
|
||||
// Mock WordPress functions used in the method
|
||||
WP_Mock::userFunction('plugin_dir_url', [
|
||||
'return' => 'http://example.com/wp-content/plugins/wp-plugin-starter-template/includes/Admin/',
|
||||
]);
|
||||
|
||||
// Mock wp_enqueue_style
|
||||
WP_Mock::userFunction('wp_enqueue_style', [
|
||||
'times' => 1,
|
||||
'args' => [
|
||||
'wpst-admin-styles',
|
||||
'http://example.com/wp-content/plugins/wp-plugin-starter-template/includes/Admin/../../admin/css/admin-styles.css',
|
||||
'http://example.org/wp-content/plugins/wp-plugin-starter-template/admin/css/admin-styles.css',
|
||||
[],
|
||||
'1.0.0',
|
||||
],
|
||||
@@ -122,7 +117,7 @@ class AdminTest extends \WP_Mock\Tools\TestCase {
|
||||
'times' => 1,
|
||||
'args' => [
|
||||
'wpst-admin-script',
|
||||
'http://example.com/wp-content/plugins/wp-plugin-starter-template/includes/Admin/../../admin/js/admin-scripts.js',
|
||||
'http://example.org/wp-content/plugins/wp-plugin-starter-template/admin/js/admin-scripts.js',
|
||||
['jquery'],
|
||||
'1.0.0',
|
||||
true,
|
||||
|
||||
@@ -55,13 +55,19 @@ spl_autoload_register(
|
||||
// Get the relative class name.
|
||||
$relative_class = substr( $className, $len );
|
||||
|
||||
// Convert namespace to path.
|
||||
$file = WP_PLUGIN_STARTER_TEMPLATE_PATH . 'includes/' . str_replace( '\\', '/', $relative_class ) . '.php';
|
||||
// Build class file path using WordPress-style class file names.
|
||||
$relative_path = str_replace( '\\', '/', $relative_class );
|
||||
$path_parts = explode( '/', $relative_path );
|
||||
$class_name = array_pop( $path_parts );
|
||||
$directory = '';
|
||||
|
||||
// Convert class name format to file name format.
|
||||
$file = str_replace( 'class-', '', $file );
|
||||
$file = preg_replace( '/([a-z])([A-Z])/', '$1-$2', $file );
|
||||
$file = strtolower( $file );
|
||||
if ( ! empty( $path_parts ) ) {
|
||||
$directory = implode( '/', $path_parts ) . '/';
|
||||
}
|
||||
|
||||
$class_file = preg_replace( '/([a-z])([A-Z])/', '$1-$2', $class_name );
|
||||
$class_file = 'class-' . strtolower( $class_file ) . '.php';
|
||||
$file = WP_PLUGIN_STARTER_TEMPLATE_PATH . 'includes/' . $directory . $class_file;
|
||||
|
||||
// If the file exists, require it.
|
||||
if ( file_exists( $file ) ) {
|
||||
|
||||
Reference in New Issue
Block a user