Compare commits
11 Commits
quality-de
...
595855ce10
| Author | SHA1 | Date | |
|---|---|---|---|
| 595855ce10 | |||
| 1d41af86c3 | |||
| a6db436a48 | |||
| 4a817ab231 | |||
| 1f96fe9965 | |||
| 5d148f8af9 | |||
| 0e906eb981 | |||
| 02a635f72c | |||
| 6625e8ca4a | |||
| 52632ec322 | |||
| 1c1980bb22 |
8
.github/workflows/code-quality.yml
vendored
8
.github/workflows/code-quality.yml
vendored
@@ -29,6 +29,11 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: composer install --prefer-dist --no-progress
|
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
|
- name: Run PHPCS
|
||||||
run: composer phpcs
|
run: composer phpcs
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@@ -56,6 +61,9 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: composer install --prefer-dist --no-progress
|
run: composer install --prefer-dist --no-progress
|
||||||
|
|
||||||
|
- name: Install PHPStan WordPress stubs
|
||||||
|
run: composer require --dev szepeviktor/phpstan-wordpress
|
||||||
|
|
||||||
- name: Run PHPStan
|
- name: Run PHPStan
|
||||||
run: composer phpstan
|
run: composer phpstan
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|||||||
7
.github/workflows/tests.yml
vendored
7
.github/workflows/tests.yml
vendored
@@ -34,8 +34,11 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: composer install --prefer-dist --no-progress
|
run: composer install --prefer-dist --no-progress
|
||||||
|
|
||||||
- name: Run tests
|
# - name: Debug test file content
|
||||||
run: ./vendor/bin/phpunit
|
# 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
|
||||||
|
|
||||||
code-style:
|
code-style:
|
||||||
name: Code Style
|
name: Code Style
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"MD004": {
|
||||||
|
"style": "asterisk"
|
||||||
|
},
|
||||||
"MD012": false,
|
"MD012": false,
|
||||||
"MD022": false,
|
"MD022": false,
|
||||||
"MD031": false,
|
"MD031": false,
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ if ($condition) {
|
|||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
* All classes, methods, and functions should be documented using PHPDoc
|
* All classes, methods, and functions should be documented using PHPDoc
|
||||||
* Include descriptions of parameters, return values, and any exceptions thrown
|
* Include a description of the parameters, return values, and possible exceptions
|
||||||
|
|
||||||
```php
|
```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**
|
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
|
* 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
|
* Copy the output from the code quality tool and paste it into your AI assistant chat
|
||||||
* Request the AI's assistance to interpret and resolve the reported issues
|
* Ask the AI to help you understand and resolve the issues
|
||||||
* Example prompt:
|
* Example prompt:
|
||||||
|
|
||||||
```text
|
```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:
|
By participating in this project, you agree to abide by our code of conduct:
|
||||||
|
|
||||||
- Be respectful and inclusive
|
* Be respectful and inclusive
|
||||||
- Be patient and welcoming
|
* Be patient and welcoming
|
||||||
- Be considerate
|
* Be considerate
|
||||||
- Be collaborative
|
* Be collaborative
|
||||||
- Be open-minded
|
* Be open-minded
|
||||||
|
|
||||||
## How to Contribute
|
## How to Contribute
|
||||||
|
|
||||||
@@ -26,12 +26,12 @@ If you find a bug, please report it by creating an issue on GitHub:
|
|||||||
|
|
||||||
Please include:
|
Please include:
|
||||||
|
|
||||||
- A clear, descriptive title
|
* A clear, descriptive title
|
||||||
- Steps to reproduce the bug
|
* Steps to reproduce the bug
|
||||||
- Expected behavior
|
* Expected behavior
|
||||||
- Actual behavior
|
* Actual behavior
|
||||||
- Screenshots (if applicable)
|
* Screenshots (if applicable)
|
||||||
- Your environment (WordPress version, PHP version, browser, etc.)
|
* Your environment (WordPress version, PHP version, browser, etc.)
|
||||||
|
|
||||||
### Suggesting Enhancements
|
### Suggesting Enhancements
|
||||||
|
|
||||||
@@ -45,10 +45,10 @@ If you have an idea for an enhancement:
|
|||||||
|
|
||||||
Please include:
|
Please include:
|
||||||
|
|
||||||
- A clear, descriptive title
|
* A clear, descriptive title
|
||||||
- A detailed description of the enhancement
|
* A detailed description of the enhancement
|
||||||
- Why this enhancement would be useful
|
* Why this enhancement would be useful
|
||||||
- Any relevant examples or mockups
|
* Any relevant examples or mockups
|
||||||
|
|
||||||
### Pull Requests
|
### Pull Requests
|
||||||
|
|
||||||
@@ -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
|
1. Copy the output from the code quality tool
|
||||||
2. Paste it into your AI assistant chat
|
2. Paste it into your AI assistant chat
|
||||||
3. Request the AI's assistance to interpret and resolve the reported issues
|
3. Ask the AI to help you understand and resolve the issues
|
||||||
4. Apply the suggested fixes
|
4. Apply the suggested fixes
|
||||||
5. Commit the changes and verify that the issues are resolved
|
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 JavaScript coding standards: `npm run lint:js`
|
||||||
* Check CSS coding standards: `npm run lint:css`
|
* Check CSS coding standards: `npm run lint:css`
|
||||||
|
|
||||||
These checks will assist in identifying and resolving issues before they are caught by the automated code quality tools in the pull request process.
|
These checks will help identify and fix issues before they are caught by the automated code quality tools in the pull request process.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
1. Copy the output from the code quality tool
|
||||||
2. Paste it into your AI assistant chat
|
2. Paste it into your AI assistant chat
|
||||||
3. Request the AI's assistance to interpret and resolve the reported issues
|
3. Ask the AI to help you understand and resolve the issues
|
||||||
4. Apply the suggested fixes
|
4. Apply the suggested fixes
|
||||||
5. Commit the changes and verify that the issues are resolved
|
5. Commit the changes and verify that the issues are resolved
|
||||||
|
|
||||||
|
|||||||
@@ -6,140 +6,140 @@
|
|||||||
|
|
||||||
/* General Admin Styles */
|
/* General Admin Styles */
|
||||||
.wpst-admin-page {
|
.wpst-admin-page {
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
|
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-admin-header {
|
.wpst-admin-header {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-admin-header h1 {
|
.wpst-admin-header h1 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
color: #23282d;
|
color: #23282d;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Admin Form Styles */
|
/* Admin Form Styles */
|
||||||
.wpst-form-table {
|
.wpst-form-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-form-table th {
|
.wpst-form-table th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 15px 10px 15px 0;
|
padding: 15px 10px 15px 0;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-form-table td {
|
.wpst-form-table td {
|
||||||
padding: 15px 0;
|
padding: 15px 0;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-form-table input[type="text"],
|
.wpst-form-table input[type="text"],
|
||||||
.wpst-form-table input[type="number"],
|
.wpst-form-table input[type="number"],
|
||||||
.wpst-form-table select,
|
.wpst-form-table select,
|
||||||
.wpst-form-table textarea {
|
.wpst-form-table textarea {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-form-table textarea {
|
.wpst-form-table textarea {
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-form-description {
|
.wpst-form-description {
|
||||||
color: #666;
|
color: #666;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Admin Notices */
|
/* Admin Notices */
|
||||||
.wpst-notice {
|
.wpst-notice {
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
margin: 15px 0;
|
margin: 15px 0;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border-left: 4px solid #00a0d2;
|
border-left: 4px solid #00a0d2;
|
||||||
background: #f7fcff;
|
background: #f7fcff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-notice.success {
|
.wpst-notice.success {
|
||||||
border-left-color: #46b450;
|
border-left-color: #46b450;
|
||||||
background: #ecf7ed;
|
background: #ecf7ed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-notice.error {
|
.wpst-notice.error {
|
||||||
border-left-color: #dc3232;
|
border-left-color: #dc3232;
|
||||||
background: #fbeaea;
|
background: #fbeaea;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-notice.warning {
|
.wpst-notice.warning {
|
||||||
border-left-color: #ffb900;
|
border-left-color: #ffb900;
|
||||||
background: #fff8e5;
|
background: #fff8e5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Admin Cards */
|
/* Admin Cards */
|
||||||
.wpst-card-container {
|
.wpst-card-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin: 0 -10px;
|
margin: 0 -10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-card {
|
.wpst-card {
|
||||||
flex: 1 0 300px;
|
flex: 1 0 300px;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
|
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-card-header {
|
.wpst-card-header {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
padding-bottom: 15px;
|
padding-bottom: 15px;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-card-title {
|
.wpst-card-title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-card-content {
|
.wpst-card-content {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-card-footer {
|
.wpst-card-footer {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Responsive Styles */
|
/* Responsive Styles */
|
||||||
@media screen and (width <= 782px) {
|
@media screen and (width <= 782px) {
|
||||||
.wpst-form-table th {
|
.wpst-form-table th {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-form-table td {
|
.wpst-form-table td {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-form-table input[type="text"],
|
.wpst-form-table input[type="text"],
|
||||||
.wpst-form-table input[type="number"],
|
.wpst-form-table input[type="number"],
|
||||||
.wpst-form-table select,
|
.wpst-form-table select,
|
||||||
.wpst-form-table textarea {
|
.wpst-form-table textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,138 +6,138 @@
|
|||||||
|
|
||||||
/* Modal Styles */
|
/* Modal Styles */
|
||||||
.wpst-modal {
|
.wpst-modal {
|
||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 100000;
|
z-index: 100000;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
background-color: rgb(0 0 0 / 40%);
|
background-color: rgb(0 0 0 / 40%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-modal-content {
|
.wpst-modal-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: #fefefe;
|
background-color: #fefefe;
|
||||||
margin: 10% auto;
|
margin: 10% auto;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
box-shadow: 0 4px 8px rgb(0 0 0 / 10%);
|
box-shadow: 0 4px 8px rgb(0 0 0 / 10%);
|
||||||
width: 500px;
|
width: 500px;
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-modal-header {
|
.wpst-modal-header {
|
||||||
padding-bottom: 15px;
|
padding-bottom: 15px;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-modal-title {
|
.wpst-modal-title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-modal-close {
|
.wpst-modal-close {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
right: 15px;
|
right: 15px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #666;
|
color: #666;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-modal-close:hover,
|
.wpst-modal-close:hover,
|
||||||
.wpst-modal-close:focus {
|
.wpst-modal-close:focus {
|
||||||
color: #000;
|
color: #000;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-modal-body {
|
.wpst-modal-body {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-modal-footer {
|
.wpst-modal-footer {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Source Selection Styles */
|
/* Source Selection Styles */
|
||||||
.wpst-source-options {
|
.wpst-source-options {
|
||||||
margin: 15px 0;
|
margin: 15px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-source-option {
|
.wpst-source-option {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-source-option:hover {
|
.wpst-source-option:hover {
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-source-option.selected {
|
.wpst-source-option.selected {
|
||||||
border-color: #0073aa;
|
border-color: #0073aa;
|
||||||
background-color: #f0f6fc;
|
background-color: #f0f6fc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-source-option input[type="radio"] {
|
.wpst-source-option input[type="radio"] {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-source-option-label {
|
.wpst-source-option-label {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-source-option-description {
|
.wpst-source-option-description {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
color: #666;
|
color: #666;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loading Indicator */
|
/* Loading Indicator */
|
||||||
.wpst-loading {
|
.wpst-loading {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
border: 2px solid rgb(0 0 0 / 10%);
|
border: 2px solid rgb(0 0 0 / 10%);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border-top-color: #0073aa;
|
border-top-color: #0073aa;
|
||||||
animation: wpst-spin 1s ease-in-out infinite;
|
animation: wpst-spin 1s ease-in-out infinite;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes wpst-spin {
|
@keyframes wpst-spin {
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Message Styles */
|
/* Message Styles */
|
||||||
.wpst-modal-message {
|
.wpst-modal-message {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-modal-message.success {
|
.wpst-modal-message.success {
|
||||||
background-color: #ecf7ed;
|
background-color: #ecf7ed;
|
||||||
border: 1px solid #46b450;
|
border: 1px solid #46b450;
|
||||||
color: #2a6f31;
|
color: #2a6f31;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wpst-modal-message.error {
|
.wpst-modal-message.error {
|
||||||
background-color: #fbeaea;
|
background-color: #fbeaea;
|
||||||
border: 1px solid #dc3232;
|
border: 1px solid #dc3232;
|
||||||
color: #8a1f1f;
|
color: #8a1f1f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,10 +105,16 @@
|
|||||||
* @param {string} message Notice message
|
* @param {string} message Notice message
|
||||||
*/
|
*/
|
||||||
showNotice: function (type, 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.
|
// Add notice to the page.
|
||||||
$( '.wpst-notices' ).html( $notice );
|
$( '.wpst-notices' ).empty().append( $notice );
|
||||||
|
|
||||||
// Automatically remove notice after 5 seconds.
|
// Automatically remove notice after 5 seconds.
|
||||||
setTimeout(
|
setTimeout(
|
||||||
|
|||||||
@@ -153,8 +153,8 @@
|
|||||||
showMessage: function (type, message) {
|
showMessage: function (type, message) {
|
||||||
const $message = this.$modal.find( '.wpst-modal-message' );
|
const $message = this.$modal.find( '.wpst-modal-message' );
|
||||||
|
|
||||||
// Set message content and type.
|
// Set message as plain text to prevent XSS, then apply type class.
|
||||||
$message.html( message ).removeClass( 'success error' ).addClass( type ).show();
|
$message.text( message ).removeClass( 'success error' ).addClass( type ).show();
|
||||||
|
|
||||||
// Hide message after a delay for success messages.
|
// Hide message after a delay for success messages.
|
||||||
if (type === 'success') {
|
if (type === 'success') {
|
||||||
|
|||||||
@@ -12,11 +12,22 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
?>
|
?>
|
||||||
|
|
||||||
<!-- Update Source Modal -->
|
<!-- 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-content">
|
||||||
<div class="wpst-modal-header">
|
<div class="wpst-modal-header">
|
||||||
<h2 class="wpst-modal-title"><?php esc_html_e( 'Select Update Source', 'wp-plugin-starter-template' ); ?></h2>
|
<h2 id="wpst-update-source-modal-title" class="wpst-modal-title"><?php esc_html_e( 'Select Update Source', 'wp-plugin-starter-template' ); ?></h2>
|
||||||
<span class="wpst-modal-close">×</span>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="wpst-modal-close"
|
||||||
|
aria-label="<?php esc_attr_e( 'Close dialog', 'wp-plugin-starter-template' ); ?>"
|
||||||
|
>×</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wpst-modal-body">
|
<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/}
|
WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/}
|
||||||
|
|
||||||
download() {
|
download() {
|
||||||
if command -v curl > /dev/null; then
|
if command -v curl >/dev/null 2>&1; then
|
||||||
curl -s "$1" > "$2";
|
curl -fsSL "$1" -o "$2"
|
||||||
elif command -v wget > /dev/null; then
|
elif command -v wget >/dev/null 2>&1; then
|
||||||
wget -nv -O "$2" "$1"
|
wget -qO "$2" "$1"
|
||||||
fi
|
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
|
if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then
|
||||||
WP_BRANCH=${WP_VERSION%\-*}
|
WP_BRANCH=${WP_VERSION%\-*}
|
||||||
|
WP_TESTS_TAG="branches/$WP_BRANCH"
|
||||||
elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
|
elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
|
||||||
WP_TESTS_TAG="branches/$WP_VERSION"
|
WP_TESTS_TAG="branches/$WP_VERSION"
|
||||||
elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
||||||
@@ -40,27 +44,38 @@ elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
|
|||||||
else
|
else
|
||||||
# http serves a single offer, whereas https serves multiple. we only want one
|
# 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
|
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":"//' | head -1)
|
||||||
LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
|
|
||||||
if [[ -z "$LATEST_VERSION" ]]; then
|
if [[ -z "$LATEST_VERSION" ]]; then
|
||||||
echo "Latest WordPress version could not be found"
|
echo "Latest WordPress version could not be found"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
WP_TESTS_TAG="tags/$LATEST_VERSION"
|
WP_TESTS_TAG="tags/$LATEST_VERSION"
|
||||||
fi
|
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
|
set -ex
|
||||||
|
|
||||||
install_wp() {
|
install_wp() {
|
||||||
|
|
||||||
if [ -d "$WP_CORE_DIR" ]; then
|
if [ -d "$WP_CORE_DIR" ]; then
|
||||||
return;
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$WP_CORE_DIR"
|
mkdir -p "$WP_CORE_DIR"
|
||||||
|
|
||||||
if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
|
if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
|
||||||
mkdir -p "$WP_CORE_DIR"
|
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"
|
unzip -q "$WP_CORE_DIR/wordpress-nightly.zip" -d "$WP_CORE_DIR"
|
||||||
rm "$WP_CORE_DIR/wordpress-nightly.zip"
|
rm "$WP_CORE_DIR/wordpress-nightly.zip"
|
||||||
else
|
else
|
||||||
@@ -71,6 +86,7 @@ install_wp() {
|
|||||||
if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
|
if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
|
||||||
LATEST_VERSION=${WP_VERSION%??}
|
LATEST_VERSION=${WP_VERSION%??}
|
||||||
else
|
else
|
||||||
|
# shellcheck disable=SC2001
|
||||||
VERSION_ESCAPED=$(echo "$WP_VERSION" | sed 's/\./\\\\./g')
|
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)
|
LATEST_VERSION=$(grep -o '"version":"'"$VERSION_ESCAPED"'[^"]*' "$WP_CORE_DIR/wp-latest.json" | sed 's/"version":"//' | head -1)
|
||||||
fi
|
fi
|
||||||
@@ -82,7 +98,7 @@ install_wp() {
|
|||||||
else
|
else
|
||||||
local ARCHIVE_NAME="wordpress-$WP_VERSION"
|
local ARCHIVE_NAME="wordpress-$WP_VERSION"
|
||||||
fi
|
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"
|
tar --strip-components=1 -zxmf "$WP_CORE_DIR/wordpress.tar.gz" -C "$WP_CORE_DIR"
|
||||||
rm "$WP_CORE_DIR/wordpress.tar.gz"
|
rm "$WP_CORE_DIR/wordpress.tar.gz"
|
||||||
fi
|
fi
|
||||||
@@ -101,12 +117,21 @@ install_test_suite() {
|
|||||||
# set up testing suite if it doesn't yet exist
|
# set up testing suite if it doesn't yet exist
|
||||||
if [ ! -d "$WP_TESTS_DIR" ]; then
|
if [ ! -d "$WP_TESTS_DIR" ]; then
|
||||||
mkdir -p "$WP_TESTS_DIR"
|
mkdir -p "$WP_TESTS_DIR"
|
||||||
git clone --quiet --depth=1 https://github.com/WordPress/wordpress-develop.git /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
|
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
|
fi
|
||||||
if [ -d /tmp/wordpress-develop/tests/phpunit/data ]; then
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -116,15 +141,15 @@ install_test_suite() {
|
|||||||
else
|
else
|
||||||
download https://raw.githubusercontent.com/WordPress/wordpress-develop/master/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
|
download https://raw.githubusercontent.com/WordPress/wordpress-develop/master/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
|
||||||
fi
|
fi
|
||||||
WP_CORE_DIR=$(echo "$WP_CORE_DIR" | sed "s:/\+$::")
|
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: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/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/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/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||||
sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
|
sed "$ioption" "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||||
|
|
||||||
if [ "$MULTISITE" = "true" ]; then
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -132,27 +157,27 @@ install_test_suite() {
|
|||||||
|
|
||||||
install_db() {
|
install_db() {
|
||||||
|
|
||||||
if [ ${SKIP_DB_CREATE} = "true" ]; then
|
if [ "${SKIP_DB_CREATE}" = "true" ]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local PARTS
|
local PARTS
|
||||||
IFS=':' read -ra PARTS <<< "$DB_HOST"
|
IFS=':' read -ra PARTS <<<"$DB_HOST"
|
||||||
local DB_HOSTNAME=${PARTS[0]};
|
local DB_HOSTNAME=${PARTS[0]}
|
||||||
local DB_SOCK_OR_PORT=${PARTS[1]};
|
local DB_SOCK_OR_PORT=${PARTS[1]}
|
||||||
local EXTRA=""
|
local EXTRA=""
|
||||||
|
|
||||||
if [ -n "$DB_HOSTNAME" ] ; then
|
if [ -n "$DB_HOSTNAME" ]; then
|
||||||
if [[ $DB_SOCK_OR_PORT =~ ^[0-9]+$ ]]; then
|
if [[ $DB_SOCK_OR_PORT =~ ^[0-9]+$ ]]; then
|
||||||
EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
|
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"
|
EXTRA=" --socket=$DB_SOCK_OR_PORT"
|
||||||
elif [ -n "$DB_HOSTNAME" ] ; then
|
elif [ -n "$DB_HOSTNAME" ]; then
|
||||||
EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
|
EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
|
||||||
fi
|
fi
|
||||||
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
|
install_wp
|
||||||
|
|||||||
9
build.sh
9
build.sh
@@ -1,4 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
# WordPress Plugin Build Script
|
# WordPress Plugin Build Script
|
||||||
# This script creates a clean build of the plugin for distribution
|
# This script creates a clean build of the plugin for distribution
|
||||||
@@ -39,7 +40,7 @@ composer install --no-dev --optimize-autoloader
|
|||||||
|
|
||||||
# Copy plugin files to build directory
|
# Copy plugin files to build directory
|
||||||
echo "Copying plugin files..."
|
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/"
|
cp -R README.md LICENSE CHANGELOG.md readme.txt composer.json "$BUILD_DIR/"
|
||||||
|
|
||||||
# Copy directories
|
# Copy directories
|
||||||
@@ -70,7 +71,7 @@ if [ -d "vendor" ]; then
|
|||||||
cp -R vendor "$BUILD_DIR/"
|
cp -R vendor "$BUILD_DIR/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create ZIP file.
|
# Create ZIP file
|
||||||
echo "Creating ZIP file..."
|
echo "Creating ZIP file..."
|
||||||
cd build || exit 1
|
cd build || exit 1
|
||||||
zip -r "../$ZIP_FILE" "$PLUGIN_SLUG" -x "*.DS_Store" -x "*.git*" -x "*.github*"
|
zip -r "../$ZIP_FILE" "$PLUGIN_SLUG" -x "*.DS_Store" -x "*.git*" -x "*.github*"
|
||||||
@@ -83,10 +84,10 @@ if [ -f "$ZIP_FILE" ]; then
|
|||||||
|
|
||||||
# Deploy to local WordPress installation if environment variable is set
|
# Deploy to local WordPress installation if environment variable is set
|
||||||
if [ -n "$WP_LOCAL_PLUGIN_DIR" ]; then
|
if [ -n "$WP_LOCAL_PLUGIN_DIR" ]; then
|
||||||
echo "\nDeploying to local WordPress installation..."
|
printf '\nDeploying to local WordPress installation...\n'
|
||||||
echo "Deploying to local WordPress installation..."
|
echo "Deploying to local WordPress installation..."
|
||||||
|
|
||||||
# Remove existing plugin directory.
|
# Remove existing plugin directory
|
||||||
rm -rf "${WP_LOCAL_PLUGIN_DIR:?}/$PLUGIN_SLUG"
|
rm -rf "${WP_LOCAL_PLUGIN_DIR:?}/$PLUGIN_SLUG"
|
||||||
|
|
||||||
# Copy files to local WordPress installation
|
# Copy files to local WordPress installation
|
||||||
|
|||||||
@@ -18,6 +18,14 @@ describe('WordPress Playground Single Site Tests', () => {
|
|||||||
cy.visit('/wp-admin/plugins.php', { timeout: 30000 });
|
cy.visit('/wp-admin/plugins.php', { timeout: 30000 });
|
||||||
|
|
||||||
cy.get('body', { timeout: 15000 }).then(($body) => {
|
cy.get('body', { timeout: 15000 }).then(($body) => {
|
||||||
|
// Verify the starter template plugin exists and is activated.
|
||||||
|
if ($body.find('tr[data-slug="wp-plugin-starter-template-for-ai-coding"]').length) {
|
||||||
|
cy.get('tr[data-slug="wp-plugin-starter-template-for-ai-coding"]').should('exist');
|
||||||
|
cy.get('tr[data-slug="wp-plugin-starter-template-for-ai-coding"] .deactivate a').should('exist');
|
||||||
|
} else {
|
||||||
|
cy.log('Starter template plugin not found by slug, skipping check');
|
||||||
|
}
|
||||||
|
|
||||||
if ($body.text().includes('Plugin Toggle')) {
|
if ($body.text().includes('Plugin Toggle')) {
|
||||||
cy.contains('tr', 'Plugin Toggle').should('exist');
|
cy.contains('tr', 'Plugin Toggle').should('exist');
|
||||||
cy.contains('tr', 'Plugin Toggle').find('.deactivate').should('exist');
|
cy.contains('tr', 'Plugin Toggle').find('.deactivate').should('exist');
|
||||||
|
|||||||
@@ -1,30 +1,75 @@
|
|||||||
describe('WordPress Single Site Tests', () => {
|
/* eslint-env mocha, jquery, cypress */
|
||||||
it('Can access the site', () => {
|
describe( 'WordPress Single Site Tests', () => {
|
||||||
cy.visit('/');
|
it( 'Can access the site', () => {
|
||||||
cy.get('body').should('exist');
|
cy.visit( '/' );
|
||||||
});
|
cy.get( 'body' ).should( 'exist' );
|
||||||
|
} );
|
||||||
|
|
||||||
it('Can login to the admin area', () => {
|
it( 'Can login to the admin area', () => {
|
||||||
cy.loginAsAdmin();
|
cy.loginAsAdmin();
|
||||||
cy.get('#wpadminbar').should('exist');
|
cy.get( '#wpadminbar' ).should( 'exist' );
|
||||||
cy.get('#dashboard-widgets').should('exist');
|
cy.get( '#dashboard-widgets' ).should( 'exist' );
|
||||||
});
|
} );
|
||||||
|
|
||||||
it('Plugin is activated', () => {
|
it( 'Plugin is activated', () => {
|
||||||
// Use our custom command to check and activate the plugin if needed
|
// Use our custom command to check and activate the plugin if needed.
|
||||||
cy.activatePlugin('wp-plugin-starter-template-for-ai-coding');
|
cy.activatePlugin( 'wp-plugin-starter-template-for-ai-coding' );
|
||||||
|
|
||||||
// Verify it's active
|
// Verify it's active.
|
||||||
cy.get('tr[data-slug="wp-plugin-starter-template-for-ai-coding"] .deactivate').should('exist');
|
cy.get( 'tr[data-slug="wp-plugin-starter-template-for-ai-coding"] .deactivate' ).should( 'exist' );
|
||||||
});
|
} );
|
||||||
|
|
||||||
it('Plugin settings page loads correctly', () => {
|
it( 'Plugin row is visible on the plugins page', () => {
|
||||||
cy.loginAsAdmin();
|
cy.loginAsAdmin();
|
||||||
|
cy.visit( '/wp-admin/plugins.php' );
|
||||||
|
|
||||||
// Navigate to the plugin settings page (if it exists)
|
// Verify the plugin row exists with the correct slug.
|
||||||
cy.visit('/wp-admin/options-general.php?page=wp-plugin-starter-template');
|
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
|
// Verify the plugin name is displayed.
|
||||||
cy.get('h1').should('contain', 'WP Plugin Starter Template');
|
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 {
|
public function enqueue_admin_assets(): void {
|
||||||
|
|
||||||
// @phpcs:disable WordPress.Security.NonceVerification.Recommended
|
// @phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||||
// @phpcs:disable WordPress.Security.NonceVerification.Missing
|
// @phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||||
// For production, use filter_input.
|
// For production, use filter_input.
|
||||||
$page = '';
|
$page = '';
|
||||||
if ( defined( 'PHPUNIT_RUNNING' ) && PHPUNIT_RUNNING ) {
|
if ( defined( 'PHPUNIT_RUNNING' ) && PHPUNIT_RUNNING ) {
|
||||||
@@ -64,15 +64,17 @@ class Admin {
|
|||||||
if ( ! $page || 'wp_plugin_starter_template_settings' !== $page ) {
|
if ( ! $page || 'wp_plugin_starter_template_settings' !== $page ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// @phpcs:enable
|
// @phpcs:enable
|
||||||
|
|
||||||
// Get the plugin version.
|
// Get the plugin version.
|
||||||
$plugin_version = $this->core->get_plugin_version();
|
$plugin_version = $this->core->get_plugin_version();
|
||||||
|
|
||||||
|
$plugin_url = $this->get_plugin_base_url();
|
||||||
|
|
||||||
// Enqueue styles.
|
// Enqueue styles.
|
||||||
\wp_enqueue_style(
|
\wp_enqueue_style(
|
||||||
'wpst-admin-styles',
|
'wpst-admin-styles',
|
||||||
plugin_dir_url( dirname( __DIR__ ) ) . 'admin/css/admin-styles.css',
|
$plugin_url . 'admin/css/admin-styles.css',
|
||||||
array(), // Dependencies.
|
array(), // Dependencies.
|
||||||
$plugin_version // Version.
|
$plugin_version // Version.
|
||||||
);
|
);
|
||||||
@@ -80,7 +82,7 @@ class Admin {
|
|||||||
// Enqueue admin scripts.
|
// Enqueue admin scripts.
|
||||||
\wp_enqueue_script(
|
\wp_enqueue_script(
|
||||||
'wpst-admin-script',
|
'wpst-admin-script',
|
||||||
plugin_dir_url( dirname( __DIR__ ) ) . 'admin/js/admin-scripts.js',
|
$plugin_url . 'admin/js/admin-scripts.js',
|
||||||
array( 'jquery' ),
|
array( 'jquery' ),
|
||||||
$plugin_version, // Version.
|
$plugin_version, // Version.
|
||||||
true
|
true
|
||||||
@@ -99,4 +101,21 @@ class Admin {
|
|||||||
$data
|
$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
|
* Extend this file or create additional classes in this directory
|
||||||
* to implement multisite features for your plugin.
|
* 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.
|
// Exit if accessed directly.
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"test:phpunit:multisite": "WP_MULTISITE=1 composer test",
|
"test:phpunit:multisite": "WP_MULTISITE=1 composer test",
|
||||||
"build": "./build.sh",
|
"build": "./build.sh",
|
||||||
"lint:js": "eslint cypress/",
|
"lint:js": "eslint cypress/",
|
||||||
|
"lint:css": "stylelint \"**/*.css\" --allow-empty-input",
|
||||||
"lint:php": "composer run-script phpcs",
|
"lint:php": "composer run-script phpcs",
|
||||||
"lint:php:simple": "composer run-script phpcs:simple",
|
"lint:php:simple": "composer run-script phpcs:simple",
|
||||||
"lint:phpstan": "composer run-script phpstan",
|
"lint:phpstan": "composer run-script phpstan",
|
||||||
@@ -38,7 +39,7 @@
|
|||||||
"test:php": "composer run-script test",
|
"test:php": "composer run-script test",
|
||||||
"lint": "composer run-script lint",
|
"lint": "composer run-script lint",
|
||||||
"fix": "composer run-script fix",
|
"fix": "composer run-script fix",
|
||||||
"quality": "npm run lint && npm run test:php"
|
"quality": "npm run lint && npm run lint:css && npm run test:php"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -64,6 +65,8 @@
|
|||||||
"@wp-playground/cli": "^3.0.22",
|
"@wp-playground/cli": "^3.0.22",
|
||||||
"cypress": "^13.17.0",
|
"cypress": "^13.17.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-cypress": "^2.15.1"
|
"eslint-plugin-cypress": "^2.15.1",
|
||||||
|
"stylelint": "^16.0.0",
|
||||||
|
"stylelint-config-standard": "^36.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<exclude-pattern>*/build/*</exclude-pattern>
|
<exclude-pattern>*/build/*</exclude-pattern>
|
||||||
<exclude-pattern>*/dist/*</exclude-pattern>
|
<exclude-pattern>*/dist/*</exclude-pattern>
|
||||||
|
|
||||||
<!-- Command line arguments: combined short flags (-s shows sniff codes, -p shows progress) -->
|
<!-- Command line arguments -->
|
||||||
<arg value="sp"/>
|
<arg value="sp"/>
|
||||||
<arg name="extensions" value="php"/>
|
<arg name="extensions" value="php"/>
|
||||||
<arg name="basepath" value="."/>
|
<arg name="basepath" value="."/>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
<exclude name="CamelCaseMethodName" />
|
<exclude name="CamelCaseMethodName" />
|
||||||
<exclude name="CamelCaseParameterName" />
|
<exclude name="CamelCaseParameterName" />
|
||||||
<exclude name="CamelCaseVariableName" />
|
<exclude name="CamelCaseVariableName" />
|
||||||
|
<!-- WordPress plugins use filter_input() for production and $_GET for testing; Superglobals rule is not applicable. -->
|
||||||
|
<exclude name="Superglobals" />
|
||||||
</rule>
|
</rule>
|
||||||
<rule ref="rulesets/design.xml" />
|
<rule ref="rulesets/design.xml" />
|
||||||
<rule ref="rulesets/naming.xml">
|
<rule ref="rulesets/naming.xml">
|
||||||
|
|||||||
@@ -5,13 +5,6 @@ parameters:
|
|||||||
- admin
|
- admin
|
||||||
- wp-plugin-starter-template.php
|
- wp-plugin-starter-template.php
|
||||||
excludePaths:
|
excludePaths:
|
||||||
analyse:
|
|
||||||
- vendor
|
|
||||||
- node_modules
|
|
||||||
- tests
|
|
||||||
- bin
|
|
||||||
- build
|
|
||||||
- dist
|
|
||||||
analyseAndScan:
|
analyseAndScan:
|
||||||
- vendor
|
- vendor
|
||||||
- node_modules
|
- node_modules
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
"landingPage": "/wp-admin/",
|
"landingPage": "/wp-admin/",
|
||||||
"login": true,
|
"login": true,
|
||||||
"features": {
|
"features": {
|
||||||
"networking": true
|
"networking": false
|
||||||
},
|
},
|
||||||
"steps": [
|
"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
|
1. Copy the output from the code quality tool
|
||||||
2. Paste it into your AI assistant chat
|
2. Paste it into your AI assistant chat
|
||||||
3. Request the AI's assistance to interpret and resolve the reported issues
|
3. Ask the AI to help you understand and resolve the issues
|
||||||
4. Apply the suggested fixes
|
4. Apply the suggested fixes
|
||||||
5. Commit the changes and verify that the issues are resolved
|
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.
|
// Include plugin files needed for tests.
|
||||||
require_once WPST_PLUGIN_DIR . 'includes/class-core.php';
|
require_once WPST_PLUGIN_DIR . 'includes/class-core.php';
|
||||||
require_once WPST_PLUGIN_DIR . 'includes/class-plugin.php';
|
require_once WPST_PLUGIN_DIR . 'includes/class-plugin.php';
|
||||||
if ( file_exists( WPST_PLUGIN_DIR . 'admin/lib/admin.php' ) ) {
|
if ( file_exists( WPST_PLUGIN_DIR . 'includes/Admin/class-admin.php' ) ) {
|
||||||
require_once WPST_PLUGIN_DIR . 'admin/lib/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',
|
'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
|
// Mock wp_enqueue_style
|
||||||
WP_Mock::userFunction('wp_enqueue_style', [
|
WP_Mock::userFunction('wp_enqueue_style', [
|
||||||
'times' => 1,
|
'times' => 1,
|
||||||
'args' => [
|
'args' => [
|
||||||
'wpst-admin-styles',
|
'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',
|
'1.0.0',
|
||||||
],
|
],
|
||||||
@@ -122,7 +117,7 @@ class AdminTest extends \WP_Mock\Tools\TestCase {
|
|||||||
'times' => 1,
|
'times' => 1,
|
||||||
'args' => [
|
'args' => [
|
||||||
'wpst-admin-script',
|
'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'],
|
['jquery'],
|
||||||
'1.0.0',
|
'1.0.0',
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -55,13 +55,19 @@ spl_autoload_register(
|
|||||||
// Get the relative class name.
|
// Get the relative class name.
|
||||||
$relative_class = substr( $className, $len );
|
$relative_class = substr( $className, $len );
|
||||||
|
|
||||||
// Convert namespace to path.
|
// Build class file path using WordPress-style class file names.
|
||||||
$file = WP_PLUGIN_STARTER_TEMPLATE_PATH . 'includes/' . str_replace( '\\', '/', $relative_class ) . '.php';
|
$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.
|
if ( ! empty( $path_parts ) ) {
|
||||||
$file = str_replace( 'class-', '', $file );
|
$directory = implode( '/', $path_parts ) . '/';
|
||||||
$file = preg_replace( '/([a-z])([A-Z])/', '$1-$2', $file );
|
}
|
||||||
$file = strtolower( $file );
|
|
||||||
|
$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 the file exists, require it.
|
||||||
if ( file_exists( $file ) ) {
|
if ( file_exists( $file ) ) {
|
||||||
|
|||||||
Reference in New Issue
Block a user