diff --git a/.ai-workflows/code-review.md b/.ai-workflows/code-review.md index fcd2944..7aa0567 100644 --- a/.ai-workflows/code-review.md +++ b/.ai-workflows/code-review.md @@ -85,13 +85,21 @@ This project uses several automated code review tools to maintain high code qual * **Benefits**: Provides a grade for your codebase, identifies issues, and tracks code quality over time * **Usage**: Codacy automatically analyzes your codebase and provides feedback on pull requests -### 4. SonarCloud +### 4. PHPStan -[SonarCloud](https://sonarcloud.io/) is a cloud-based code quality and security service that performs static code analysis to detect bugs, vulnerabilities, and code smells. +[PHPStan](https://phpstan.org/) is a static analysis tool that finds errors in your code without running it. -* **Integration**: Add the SonarCloud GitHub App to your repository -* **Benefits**: Provides detailed analysis of code quality, security vulnerabilities, and technical debt -* **Usage**: SonarCloud automatically analyzes your codebase and provides feedback on pull requests +* **Integration**: Included in the project's composer.json and GitHub Actions workflow +* **Benefits**: Detects undefined variables, methods, and properties; type-related issues; and logical errors +* **Usage**: Run `composer phpstan` or `npm run lint:phpstan` locally, or let GitHub Actions run it automatically + +### 5. PHP Mess Detector + +[PHP Mess Detector](https://phpmd.org/) is a tool that looks for potential problems in your code such as possible bugs, suboptimal code, overcomplicated expressions, and unused parameters, variables, and methods. + +* **Integration**: Included in the project's composer.json and GitHub Actions workflow +* **Benefits**: Identifies code smells, complexity issues, unused code, naming problems, and more +* **Usage**: Run `composer phpmd` or `npm run lint:phpmd` locally, or let GitHub Actions run it automatically ### Using AI Assistants with Code Review Tools diff --git a/.codacy.yml b/.codacy.yml index 3ce1041..129e0d0 100644 --- a/.codacy.yml +++ b/.codacy.yml @@ -3,6 +3,52 @@ engines: markdownlint: enabled: true config_file: .markdownlint.json + phpmd: + enabled: true + phpcs: + enabled: true + stylelint: + enabled: false + shellcheck: + enabled: false + # Disable tools that are causing issues + eslint: + enabled: false + eslint-8: + enabled: false + eslint-9: + enabled: false + trivy: + enabled: false + semgrep: + enabled: false + checkov: + enabled: false + pmd: + enabled: false + pmd-7: + enabled: false + lizard: + enabled: false + jshint: + enabled: false + csslint: + enabled: false + jacksonlinter: + enabled: false + spectral: + enabled: false + +duplication: + enabled: true + exclude_patterns: + - "tests/**" + - "vendor/**" + - "node_modules/**" + +metrics: + enabled: true + exclude_paths: - "vendor/**" - "node_modules/**" @@ -11,3 +57,5 @@ exclude_paths: - "bin/**" - ".github/**" - "tests/**" + - "*.lock" + - "*.json" diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..4a42e06 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,30 @@ +{ + "env": { + "browser": true, + "jquery": true, + "es6": true + }, + "extends": "eslint:recommended", + "globals": { + "wp": "readonly", + "wpstData": "readonly", + "wpstModalData": "readonly", + "Cypress": "readonly", + "cy": "readonly", + "describe": "readonly", + "it": "readonly", + "before": "readonly", + "module": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": { + "indent": ["error", 2], + "linebreak-style": ["error", "unix"], + "quotes": ["error", "single"], + "semi": ["error", "always"] + }, + "ignorePatterns": ["vendor/**", "node_modules/**", "build/**", "dist/**", "bin/**"] +} diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 47a610d..e595b55 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -1,4 +1,4 @@ -name: Code Quality - Run automated code quality checks +name: Code Quality on: push: @@ -19,21 +19,71 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.1' extensions: mbstring, intl, zip - tools: composer:v2, phpcs + tools: composer:v2 - 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 run phpcs + run: composer phpcs continue-on-error: true - name: Run PHPCBF (report only) run: | echo "Running PHPCBF in dry-run mode to show what would be fixed" - composer run phpcbf -- --dry-run + composer phpcbf -- --dry-run + continue-on-error: true + + phpstan: + name: PHPStan Static Analysis + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + extensions: mbstring, intl, zip + tools: composer:v2, phpstan + + - 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 + + phpmd: + name: PHP Mess Detector + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + extensions: mbstring, intl, zip + tools: composer:v2, phpmd + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: Run PHPMD + run: composer phpmd continue-on-error: true sonarcloud: @@ -59,7 +109,7 @@ jobs: restore-keys: ${{ runner.os }}-sonar - name: SonarCloud Scan - uses: SonarSource/sonarcloud-github-action@v2.0.2 + uses: SonarSource/sonarqube-scan-action@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -88,13 +138,15 @@ jobs: verbose: true output: results.sarif format: sarif - # Adjust the below patterns based on your project structure + # Limit the number of issues to prevent GitHub Code Scanning rejection gh-code-scanning-compat: true - max-allowed-issues: 2147483647 + max-allowed-issues: 20 + # Limit tools to prevent timeouts and stay under GitHub's 20 runs limit + tool: phpcs,phpmd,markdownlint continue-on-error: true - name: Upload SARIF results file - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: results.sarif continue-on-error: true diff --git a/.markdownlint.json b/.markdownlint.json index 11a35ea..97dfdb1 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,4 +1,5 @@ { + "default": true, "MD004": { "style": "asterisk" }, diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000..93f69e7 --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,16 @@ +{ + "extends": "stylelint-config-standard", + "rules": { + "alpha-value-notation": "percentage", + "color-function-notation": "modern", + "font-weight-notation": "numeric", + "media-feature-range-notation": "context" + }, + "ignoreFiles": [ + "vendor/**", + "node_modules/**", + "build/**", + "dist/**", + "bin/**" + ] +} diff --git a/README.md b/README.md index 1daef11..69001dd 100644 --- a/README.md +++ b/README.md @@ -252,10 +252,43 @@ This project uses several automated code quality tools to ensure high standards. 3. **Codacy**: Code quality and static analysis * [Website](https://www.codacy.com/) * Identifies issues related to code style, security, and performance + * Requires a `CODACY_PROJECT_TOKEN` secret in your GitHub repository settings + * To set up Codacy: + 1. Go to [Codacy](https://www.codacy.com/) and sign in with your GitHub account + 2. Add your repository to Codacy + 3. Go to your project settings > Integrations > Project API + 4. Generate a project API token + 5. Add the token as a secret named `CODACY_PROJECT_TOKEN` in your GitHub repository settings + 6. Note: Codacy tokens are project-specific, so they need to be added at the repository level. However, you can use GitHub Actions to securely pass these tokens between repositories if needed. 4. **SonarCloud**: Code quality and security analysis * [Website](https://sonarcloud.io/) * Provides detailed analysis of code quality and security + * Requires a `SONAR_TOKEN` secret in your GitHub repository settings + * To set up SonarCloud: + 1. Go to [SonarCloud](https://sonarcloud.io/) and sign in with your GitHub account + 2. Create a new organization or use an existing one + 3. Add your repository to SonarCloud + 4. Generate a token in SonarCloud (Account > Security > Tokens) + 5. Add the token as a secret named `SONAR_TOKEN` in your GitHub repository or organization settings (see "GitHub Secrets Management" section below) + +5. **PHP_CodeSniffer (PHPCS)**: PHP code style checker + * Enforces WordPress Coding Standards + * Automatically runs in GitHub Actions workflow + * Run locally with `composer phpcs` + +6. **PHP Code Beautifier and Fixer (PHPCBF)**: Automatically fixes coding standard violations + * Run locally with `composer phpcbf` + +7. **PHPStan**: PHP static analysis tool + * Detects bugs and errors without running the code + * Run locally with `composer phpstan` + +8. **PHP Mess Detector (PHPMD)**: Analyzes code for potential problems + * Identifies complex code, unused parameters, etc. + * Run locally with `composer phpmd` + +For detailed setup instructions, see the [Code Quality Setup Guide](docs/code-quality-setup.md). ### Using AI Assistants with Code Quality Tools @@ -269,6 +302,138 @@ When you receive feedback from these code quality tools, you can use AI assistan For more information on coding standards and how to pass code quality checks, see the [Coding Standards Guide](.wiki/Coding-Standards.md). +### GitHub Secrets Management + +GitHub offers three levels of secrets management, each with different scopes and use cases: + +1. **Organization Secrets** (recommended for teams and organizations): + * Available at: GitHub Organization > Settings > Secrets and variables > Actions + * Scope: Can be shared across multiple repositories within the organization + * Benefits: Centralized management, reduced duplication, easier rotation + * Recommended for: `SONAR_TOKEN` and other tokens that apply to multiple repositories + * Note: You can restrict which repositories can access organization secrets + * Note: Codacy tokens (`CODACY_PROJECT_TOKEN`) are project-specific and should be set at the repository level + +2. **Repository Secrets**: + * Available at: Repository > Settings > Secrets and variables > Actions + * Scope: Limited to a single repository + * Benefits: Repository-specific, higher isolation + * Recommended for: `CODACY_PROJECT_TOKEN` and other repository-specific credentials or tokens that shouldn't be shared + +3. **Environment Secrets**: + * Available at: Repository > Settings > Environments > (select environment) > Environment secrets + * Scope: Limited to specific deployment environments (e.g., production, staging) + * Benefits: Environment-specific, can have approval requirements + * Recommended for: Deployment credentials that vary between environments + +For code quality tools like SonarCloud, organization secrets are recommended if you have multiple repositories that use these tools. This approach reduces management overhead and ensures consistent configuration across projects. For Codacy, since tokens are project-specific, they should be set at the repository level. + +### Local Environment Setup for Code Quality Tools + +To run code quality tools locally before committing to GitHub: + +1. **Install dependencies**: + + ```bash + composer install + ``` + +2. **Run PHP CodeSniffer**: + + ```bash + composer phpcs + ``` + +3. **Fix coding standards automatically**: + + ```bash + composer phpcbf + ``` + +4. **Run PHPStan static analysis**: + + ```bash + composer phpstan + ``` + +5. **Run PHP Mess Detector**: + + ```bash + composer phpmd + ``` + +6. **Run all linters at once**: + + ```bash + composer lint + ``` + +7. **Set up environment variables for SonarCloud and Codacy**: + + * **For macOS/Linux**: + ```bash + export SONAR_TOKEN=your_sonar_token + export CODACY_PROJECT_TOKEN=your_codacy_token + ``` + + * **For Windows (Command Prompt)**: + + ```cmd + set SONAR_TOKEN=your_sonar_token + set CODACY_PROJECT_TOKEN=your_codacy_token + ``` + + * **For Windows (PowerShell)**: + + ```powershell + $env:SONAR_TOKEN="your_sonar_token" + $env:CODACY_PROJECT_TOKEN="your_codacy_token" + ``` + +8. **Create a .env file** (alternative approach): + + ```env + # .env (already included in .gitignore to prevent committing secrets) + SONAR_TOKEN=your_sonar_token + CODACY_PROJECT_TOKEN=your_codacy_token + ``` + + Then load these variables: + + ```bash + # Using a tool like dotenv + source .env + ``` + +9. **Run SonarCloud locally**: + + ```bash + # Install SonarScanner + npm install -g sonarqube-scanner + + # Run analysis + sonar-scanner \ + -Dsonar.projectKey=your_project_key \ + -Dsonar.organization=your_organization \ + -Dsonar.sources=. \ + -Dsonar.host.url=https://sonarcloud.io \ + -Dsonar.login=$SONAR_TOKEN + ``` + +10. **Run Codacy locally**: + + ```bash + # Install Codacy CLI + npm install -g codacy-coverage + + # Run analysis + codacy-analysis-cli analyze --directory . --project-token $CODACY_PROJECT_TOKEN + ``` + +For more detailed instructions, see the [Code Quality Setup Guide](docs/code-quality-setup.md). + +By running these tools locally, you can identify and fix issues before pushing your code to GitHub, ensuring smoother CI/CD workflows. + ## Developers ### AI-Powered Development diff --git a/admin/css/admin-styles.css b/admin/css/admin-styles.css index 6b096e7..040509b 100644 --- a/admin/css/admin-styles.css +++ b/admin/css/admin-styles.css @@ -11,7 +11,7 @@ padding: 20px; background: #fff; border-radius: 5px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgb(0 0 0 / 10%); } .wpst-admin-header { @@ -98,7 +98,7 @@ padding: 20px; background: #fff; border-radius: 3px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgb(0 0 0 / 10%); } .wpst-card-header { @@ -124,7 +124,7 @@ } /* Responsive Styles */ -@media screen and (max-width: 782px) { +@media screen and (width <= 782px) { .wpst-form-table th { width: 100%; display: block; diff --git a/admin/css/update-source-selector.css b/admin/css/update-source-selector.css index 013fd23..3f8b91e 100644 --- a/admin/css/update-source-selector.css +++ b/admin/css/update-source-selector.css @@ -14,7 +14,7 @@ width: 100%; height: 100%; overflow: auto; - background-color: rgba(0, 0, 0, 0.4); + background-color: rgb(0 0 0 / 40%); } .wpst-modal-content { @@ -23,7 +23,7 @@ margin: 10% auto; padding: 20px; border-radius: 5px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + box-shadow: 0 4px 8px rgb(0 0 0 / 10%); width: 500px; max-width: 90%; } @@ -45,7 +45,7 @@ top: 10px; right: 15px; font-size: 20px; - font-weight: bold; + font-weight: 700; color: #666; cursor: pointer; } @@ -108,7 +108,7 @@ display: inline-block; width: 20px; height: 20px; - border: 2px solid rgba(0, 0, 0, 0.1); + border: 2px solid rgb(0 0 0 / 10%); border-radius: 50%; border-top-color: #0073aa; animation: wpst-spin 1s ease-in-out infinite; diff --git a/admin/js/admin-scripts.js b/admin/js/admin-scripts.js index 5afe43d..09d8711 100644 --- a/admin/js/admin-scripts.js +++ b/admin/js/admin-scripts.js @@ -5,131 +5,131 @@ */ (function ($) { - 'use strict'; + 'use strict'; - /** + /** * Admin functionality */ - const WPSTAdmin = { - /** + const WPSTAdmin = { + /** * Initialize */ - init: function () { - // Initialize components. - this.initComponents(); + init: function () { + // Initialize components. + this.initComponents(); - // Bind events. - this.bindEvents(); - }, + // Bind events. + this.bindEvents(); + }, - /** + /** * Initialize components */ - initComponents: function () { - // Initialize any components here. - }, + initComponents: function () { + // Initialize any components here. + }, - /** + /** * Bind events */ - bindEvents: function () { - // Example: Toggle sections. - $( '.wpst-toggle-section' ).on( 'click', this.toggleSection ); + bindEvents: function () { + // Example: Toggle sections. + $( '.wpst-toggle-section' ).on( 'click', this.toggleSection ); - // Example: Form submission. - $( '#wpst-settings-form' ).on( 'submit', this.handleFormSubmit ); - }, + // Example: Form submission. + $( '#wpst-settings-form' ).on( 'submit', this.handleFormSubmit ); + }, - /** + /** * Toggle section visibility * * @param {Event} e Click event */ - toggleSection: function (e) { - e.preventDefault(); + toggleSection: function (e) { + e.preventDefault(); - const $this = $( this ); - const target = $this.data( 'target' ); + const $this = $( this ); + const target = $this.data( 'target' ); - $( target ).slideToggle( 200 ); - $this.toggleClass( 'open' ); - }, + $( target ).slideToggle( 200 ); + $this.toggleClass( 'open' ); + }, - /** + /** * Handle form submission * * @param {Event} e Submit event */ - handleFormSubmit: function (e) { - e.preventDefault(); + handleFormSubmit: function (e) { + e.preventDefault(); - const $form = $( this ); - const $submitButton = $form.find( 'input[type="submit"]' ); - const formData = $form.serialize(); + const $form = $( this ); + const $submitButton = $form.find( 'input[type="submit"]' ); + const formData = $form.serialize(); - // Disable submit button and show loading state. - $submitButton.prop( 'disabled', true ).addClass( 'loading' ); + // Disable submit button and show loading state. + $submitButton.prop( 'disabled', true ).addClass( 'loading' ); - // Send AJAX request. - $.ajax( - { - url: wpstData.ajaxUrl, - type: 'POST', - data: { - action: 'wpst_save_settings', - nonce: wpstData.nonce, - formData: formData - }, - success: function (response) { - if (response.success) { - WPSTAdmin.showNotice( 'success', response.data.message ); - } else { - WPSTAdmin.showNotice( 'error', response.data.message ); - } - }, - error: function () { - WPSTAdmin.showNotice( 'error', 'An error occurred. Please try again.' ); - }, - complete: function () { - // Re-enable submit button and remove loading state. - $submitButton.prop( 'disabled', false ).removeClass( 'loading' ); - } - } - ); - }, + // Send AJAX request. + $.ajax( + { + url: wpstData.ajaxUrl, + type: 'POST', + data: { + action: 'wpst_save_settings', + nonce: wpstData.nonce, + formData: formData + }, + success: function (response) { + if (response.success) { + WPSTAdmin.showNotice( 'success', response.data.message ); + } else { + WPSTAdmin.showNotice( 'error', response.data.message ); + } + }, + error: function () { + WPSTAdmin.showNotice( 'error', 'An error occurred. Please try again.' ); + }, + complete: function () { + // Re-enable submit button and remove loading state. + $submitButton.prop( 'disabled', false ).removeClass( 'loading' ); + } + } + ); + }, - /** + /** * Show admin notice * * @param {string} type Notice type (success, error, warning) * @param {string} message Notice message */ - showNotice: function (type, message) { - const $notice = $( '

' + message + '

' ); + showNotice: function (type, message) { + const $notice = $( '

' + message + '

' ); - // Add notice to the page. - $( '.wpst-notices' ).html( $notice ); + // Add notice to the page. + $( '.wpst-notices' ).html( $notice ); - // Automatically remove notice after 5 seconds. - setTimeout( - function () { - $notice.fadeOut( - 300, - function () { - $( this ).remove(); - } - ); - }, - 5000 - ); - } - }; + // Automatically remove notice after 5 seconds. + setTimeout( + function () { + $notice.fadeOut( + 300, + function () { + $( this ).remove(); + } + ); + }, + 5000 + ); + } + }; - // Initialize when document is ready. - $( document ).ready( - function () { - WPSTAdmin.init(); - } - ); + // Initialize when document is ready. + $( document ).ready( + function () { + WPSTAdmin.init(); + } + ); })( jQuery ); diff --git a/admin/js/update-source-selector.js b/admin/js/update-source-selector.js index d782527..5f21f36 100644 --- a/admin/js/update-source-selector.js +++ b/admin/js/update-source-selector.js @@ -5,174 +5,174 @@ */ (function ($) { - 'use strict'; + 'use strict'; - /** + /** * Update Source Selector functionality */ - const WPSTUpdateSourceSelector = { - /** + const WPSTUpdateSourceSelector = { + /** * Modal element */ - $modal: null, + $modal: null, - /** + /** * Selected source */ - selectedSource: '', + selectedSource: '', - /** + /** * Initialize */ - init: function () { - // Cache DOM elements. - this.$modal = $( '#wpst-update-source-modal' ); + init: function () { + // Cache DOM elements. + this.$modal = $( '#wpst-update-source-modal' ); - // Bind events. - this.bindEvents(); - }, + // Bind events. + this.bindEvents(); + }, - /** + /** * Bind events */ - bindEvents: function () { - // Open modal when clicking on the update source link. - $( document ).on( 'click', '.wpst-update-source-selector', this.openModal.bind( this ) ); + bindEvents: function () { + // Open modal when clicking on the update source link. + $( document ).on( 'click', '.wpst-update-source-selector', this.openModal.bind( this ) ); - // Close modal when clicking on the close button or outside the modal. - this.$modal.on( 'click', '.wpst-modal-close', this.closeModal.bind( this ) ); - $( document ).on( - 'click', - '.wpst-modal', - function (e) { - if ($( e.target ).hasClass( 'wpst-modal' )) { - WPSTUpdateSourceSelector.closeModal(); - } - } - ); + // Close modal when clicking on the close button or outside the modal. + this.$modal.on( 'click', '.wpst-modal-close', this.closeModal.bind( this ) ); + $( document ).on( + 'click', + '.wpst-modal', + function (e) { + if ($( e.target ).hasClass( 'wpst-modal' )) { + WPSTUpdateSourceSelector.closeModal(); + } + } + ); - // Select source option. - this.$modal.on( 'click', '.wpst-source-option', this.selectSource.bind( this ) ); + // Select source option. + this.$modal.on( 'click', '.wpst-source-option', this.selectSource.bind( this ) ); - // Save source selection. - this.$modal.on( 'click', '#wpst-save-source', this.saveSource.bind( this ) ); - }, + // Save source selection. + this.$modal.on( 'click', '#wpst-save-source', this.saveSource.bind( this ) ); + }, - /** + /** * Open the modal * * @param {Event} e Click event */ - openModal: function (e) { - e.preventDefault(); - this.$modal.show(); - }, + openModal: function (e) { + e.preventDefault(); + this.$modal.show(); + }, - /** + /** * Close the modal */ - closeModal: function () { - this.$modal.hide(); - }, + closeModal: function () { + this.$modal.hide(); + }, - /** + /** * Select a source option * * @param {Event} e Click event */ - selectSource: function (e) { - const $option = $( e.currentTarget ); + selectSource: function (e) { + const $option = $( e.currentTarget ); - // Update selected state. - this.$modal.find( '.wpst-source-option' ).removeClass( 'selected' ); - $option.addClass( 'selected' ); + // Update selected state. + this.$modal.find( '.wpst-source-option' ).removeClass( 'selected' ); + $option.addClass( 'selected' ); - // Update radio button. - $option.find( 'input[type="radio"]' ).prop( 'checked', true ); + // Update radio button. + $option.find( 'input[type="radio"]' ).prop( 'checked', true ); - // Store selected source. - this.selectedSource = $option.find( 'input[type="radio"]' ).val(); - }, + // Store selected source. + this.selectedSource = $option.find( 'input[type="radio"]' ).val(); + }, - /** + /** * Save the selected source */ - saveSource: function () { - // Validate selection. - if ( ! this.selectedSource) { - this.showMessage( 'error', 'Please select an update source.' ); - return; - } + saveSource: function () { + // Validate selection. + if ( ! this.selectedSource) { + this.showMessage( 'error', 'Please select an update source.' ); + return; + } - // Show loading state. - const $saveButton = $( '#wpst-save-source' ); - $saveButton.prop( 'disabled', true ).html( ' Saving...' ); + // Show loading state. + const $saveButton = $( '#wpst-save-source' ); + $saveButton.prop( 'disabled', true ).html( ' Saving...' ); - // Send AJAX request. - $.ajax( - { - url: wpstModalData.ajaxUrl, // WordPress AJAX URL. - type: 'POST', - data: { - action: 'wpst_set_update_source', // AJAX action hook. - nonce: wpstModalData.nonce, // Security nonce. - source: this.selectedSource - }, - success: function (response) { - if (response.success) { - WPSTUpdateSourceSelector.showMessage( 'success', response.data.message ); + // Send AJAX request. + $.ajax( + { + url: wpstModalData.ajaxUrl, // WordPress AJAX URL. + type: 'POST', + data: { + action: 'wpst_set_update_source', // AJAX action hook. + nonce: wpstModalData.nonce, // Security nonce. + source: this.selectedSource + }, + success: function (response) { + if (response.success) { + WPSTUpdateSourceSelector.showMessage( 'success', response.data.message ); - // Close modal after a short delay. - setTimeout( - function () { - WPSTUpdateSourceSelector.closeModal(); - }, - 1500 - ); - } else { - WPSTUpdateSourceSelector.showMessage( 'error', response.data.message ); - } - }, - error: function () { - WPSTUpdateSourceSelector.showMessage( 'error', 'An error occurred. Please try again.' ); - }, - complete: function () { - // Reset button state. - $saveButton.prop( 'disabled', false ).text( wpstModalData.i18n.confirm ); - } - } - ); - }, + // Close modal after a short delay. + setTimeout( + function () { + WPSTUpdateSourceSelector.closeModal(); + }, + 1500 + ); + } else { + WPSTUpdateSourceSelector.showMessage( 'error', response.data.message ); + } + }, + error: function () { + WPSTUpdateSourceSelector.showMessage( 'error', 'An error occurred. Please try again.' ); + }, + 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} message Message text */ - showMessage: function (type, message) { - const $message = this.$modal.find( '.wpst-modal-message' ); + 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(); + // Set message content and type. + $message.html( message ).removeClass( 'success error' ).addClass( type ).show(); - // Hide message after a delay for success messages. - if (type === 'success') { - setTimeout( - function () { - $message.fadeOut( 300 ); - }, - 3000 - ); - } - } - }; + // Hide message after a delay for success messages. + if (type === 'success') { + setTimeout( + function () { + $message.fadeOut( 300 ); + }, + 3000 + ); + } + } + }; - // Initialize when document is ready. - $( document ).ready( - function () { - WPSTUpdateSourceSelector.init(); - } - ); + // Initialize when document is ready. + $( document ).ready( + function () { + WPSTUpdateSourceSelector.init(); + } + ); })( jQuery ); diff --git a/admin/templates/modal.php b/admin/templates/modal.php index 3d75889..ad59744 100644 --- a/admin/templates/modal.php +++ b/admin/templates/modal.php @@ -7,51 +7,51 @@ // Ensure this file is loaded within WordPress. if ( ! defined( 'ABSPATH' ) ) { - die; + die; } ?>
-
-
-

- × -
- -
-

- -
- -
- - - - - - - -
-
- - -
+
+
+

+ × +
+ +
+

+ +
+ +
+ + + + + + + +
+
+ + +
diff --git a/assets/css/admin.css b/assets/css/admin.css index 126215c..3a3a87d 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -6,7 +6,7 @@ padding: 20px; background: #fff; border: 1px solid #ccd0d4; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); + box-shadow: 0 1px 1px rgb(0 0 0 / 4%); margin-top: 20px; } diff --git a/assets/js/admin.js b/assets/js/admin.js index 4e13984..84a6f4e 100644 --- a/assets/js/admin.js +++ b/assets/js/admin.js @@ -3,10 +3,10 @@ */ (function($) { - 'use strict'; + 'use strict'; - $(document).ready(function() { - // Plugin admin functionality will go here - }); + $(document).ready(function() { + // Plugin admin functionality will go here + }); })(jQuery); diff --git a/composer.json b/composer.json index 8abd88a..1da64ad 100644 --- a/composer.json +++ b/composer.json @@ -15,11 +15,20 @@ "php": ">=7.4" }, "require-dev": { - "phpunit/phpunit": "^9.5", + "phpunit/phpunit": "^9.5.0", "10up/wp_mock": "^1.0", "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "wp-coding-standards/wpcs": "^3.0", - "phpcompatibility/phpcompatibility-wp": "^2.1" + "phpcompatibility/phpcompatibility-wp": "^2.1", + "phpstan/phpstan": "^1.10.0", + "szepeviktor/phpstan-wordpress": "^1.3", + "phpmd/phpmd": "^2.13.0", + "symfony/dependency-injection": "^5.4", + "symfony/config": "^5.4", + "symfony/filesystem": "^5.4", + "symfony/deprecation-contracts": "^2.5", + "doctrine/instantiator": "^1.5.0", + "psr/log": "^1.1" }, "autoload": { "psr-4": { @@ -37,12 +46,14 @@ } }, "scripts": { - "phpcs": "phpcs --standard=phpcs.xml", - "phpcs:simple": "phpcs --standard=phpcs-simple.xml", - "phpcbf": "phpcbf --standard=phpcs.xml", - "phpcbf:simple": "phpcbf --standard=phpcs-simple.xml", - "test": "phpunit", - "lint": ["@phpcs"], + "phpcs": "vendor/bin/phpcs --standard=phpcs.xml", + "phpcs:simple": "vendor/bin/phpcs --standard=phpcs-simple.xml", + "phpcbf": "vendor/bin/phpcbf --standard=phpcs.xml", + "phpcbf:simple": "vendor/bin/phpcbf --standard=phpcs-simple.xml", + "phpstan": "vendor/bin/phpstan analyse --level=5 .", + "phpmd": "vendor/bin/phpmd . text cleancode,codesize,controversial,design,naming,unusedcode --exclude vendor,node_modules,tests,bin,build,dist", + "test": "vendor/bin/phpunit", + "lint": ["@phpcs", "@phpstan", "@phpmd"], "fix": ["@phpcbf"] } } diff --git a/composer.lock b/composer.lock index 8315817..c808ca5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d6c5be2ba3ffdfe4efb6c9662fd167aa", + "content-hash": "0fd3ab35fc0dfbc05c8057409f758104", "packages": [], "packages-dev": [ { @@ -109,6 +109,151 @@ }, "time": "2024-12-11T10:19:54+00:00" }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-05-06T16:37:16+00:00" + }, { "name": "dealerdirect/phpcodesniffer-composer-installer", "version": "v1.0.0", @@ -509,6 +654,69 @@ }, "time": "2024-12-30T11:07:19+00:00" }, + { + "name": "pdepend/pdepend", + "version": "2.16.2", + "source": { + "type": "git", + "url": "https://github.com/pdepend/pdepend.git", + "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58", + "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58", + "shasum": "" + }, + "require": { + "php": ">=5.3.7", + "symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0", + "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0", + "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0", + "symfony/polyfill-mbstring": "^1.19" + }, + "require-dev": { + "easy-doc/easy-doc": "0.0.0|^1.2.3", + "gregwar/rst": "^1.0", + "squizlabs/php_codesniffer": "^2.0.0" + }, + "bin": [ + "src/bin/pdepend" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "PDepend\\": "src/main/php/PDepend" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Official version of pdepend to be handled with Composer", + "keywords": [ + "PHP Depend", + "PHP_Depend", + "dev", + "pdepend" + ], + "support": { + "issues": "https://github.com/pdepend/pdepend/issues", + "source": "https://github.com/pdepend/pdepend/tree/2.16.2" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend", + "type": "tidelift" + } + ], + "time": "2023-12-17T18:09:59+00:00" + }, { "name": "phar-io/manifest", "version": "2.0.4", @@ -627,6 +835,57 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "php-stubs/wordpress-stubs", + "version": "v6.8.0", + "source": { + "type": "git", + "url": "https://github.com/php-stubs/wordpress-stubs.git", + "reference": "1824db4d1d00d32c0119175d2369d9425dbc4953" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/1824db4d1d00d32c0119175d2369d9425dbc4953", + "reference": "1824db4d1d00d32c0119175d2369d9425dbc4953", + "shasum": "" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "5.6.1" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "nikic/php-parser": "^4.13", + "php": "^7.4 || ^8.0", + "php-stubs/generator": "^0.8.3", + "phpdocumentor/reflection-docblock": "^5.4.1", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^9.5", + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.1.1", + "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" + }, + "suggest": { + "paragonie/sodium_compat": "Pure PHP implementation of libsodium", + "symfony/polyfill-php80": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "WordPress function and class declaration stubs for static analysis.", + "homepage": "https://github.com/php-stubs/wordpress-stubs", + "keywords": [ + "PHPStan", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/php-stubs/wordpress-stubs/issues", + "source": "https://github.com/php-stubs/wordpress-stubs/tree/v6.8.0" + }, + "time": "2025-04-17T15:13:53+00:00" + }, { "name": "phpcompatibility/php-compatibility", "version": "9.3.5", @@ -833,22 +1092,22 @@ }, { "name": "phpcsstandards/phpcsextra", - "version": "1.2.1", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489" + "reference": "46d08eb86eec622b96c466adec3063adfed280dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", - "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/46d08eb86eec622b96c466adec3063adfed280dd", + "reference": "46d08eb86eec622b96c466adec3063adfed280dd", "shasum": "" }, "require": { "php": ">=5.4", "phpcsstandards/phpcsutils": "^1.0.9", - "squizlabs/php_codesniffer": "^3.8.0" + "squizlabs/php_codesniffer": "^3.12.1" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0", @@ -905,9 +1164,13 @@ { "url": "https://opencollective.com/php_codesniffer", "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" } ], - "time": "2023-12-08T16:49:07+00:00" + "time": "2025-04-20T23:35:32+00:00" }, { "name": "phpcsstandards/phpcsutils", @@ -997,6 +1260,147 @@ ], "time": "2024-05-20T13:34:27+00:00" }, + { + "name": "phpmd/phpmd", + "version": "2.15.0", + "source": { + "type": "git", + "url": "https://github.com/phpmd/phpmd.git", + "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0", + "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0", + "shasum": "" + }, + "require": { + "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0", + "ext-xml": "*", + "pdepend/pdepend": "^2.16.1", + "php": ">=5.3.9" + }, + "require-dev": { + "easy-doc/easy-doc": "0.0.0 || ^1.3.2", + "ext-json": "*", + "ext-simplexml": "*", + "gregwar/rst": "^1.0", + "mikey179/vfsstream": "^1.6.8", + "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2" + }, + "bin": [ + "src/bin/phpmd" + ], + "type": "library", + "autoload": { + "psr-0": { + "PHPMD\\": "src/main/php" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Manuel Pichler", + "email": "github@manuel-pichler.de", + "homepage": "https://github.com/manuelpichler", + "role": "Project Founder" + }, + { + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "homepage": "https://github.com/ravage84", + "role": "Project Maintainer" + }, + { + "name": "Other contributors", + "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", + "role": "Contributors" + } + ], + "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", + "homepage": "https://phpmd.org/", + "keywords": [ + "dev", + "mess detection", + "mess detector", + "pdepend", + "phpmd", + "pmd" + ], + "support": { + "irc": "irc://irc.freenode.org/phpmd", + "issues": "https://github.com/phpmd/phpmd/issues", + "source": "https://github.com/phpmd/phpmd/tree/2.15.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd", + "type": "tidelift" + } + ], + "time": "2023-12-11T08:22:20+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.12.24", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "338b92068f58d9f8035b76aed6cf2b9e5624c025" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/338b92068f58d9f8035b76aed6cf2b9e5624c025", + "reference": "338b92068f58d9f8035b76aed6cf2b9e5624c025", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-04-16T13:01:53+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.32", @@ -1419,6 +1823,104 @@ ], "time": "2024-12-05T13:48:26+00:00" }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, { "name": "sebastian/cli-parser", "version": "1.0.2", @@ -2466,6 +2968,845 @@ ], "time": "2025-04-13T04:10:18+00:00" }, + { + "name": "symfony/config", + "version": "v5.4.46", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "977c88a02d7d3f16904a81907531b19666a08e78" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/977c88a02d7d3f16904a81907531b19666a08e78", + "reference": "977c88a02d7d3f16904a81907531b19666a08e78", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" + }, + "conflict": { + "symfony/finder": "<4.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/yaml": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v5.4.46" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-30T07:58:02+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v5.4.48", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "e5ca16dee39ef7d63e552ff0bf0a2526a1142c92" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e5ca16dee39ef7d63e552ff0bf0a2526a1142c92", + "reference": "e5ca16dee39ef7d63e552ff0bf0a2526a1142c92", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1.1", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<5.3", + "symfony/finder": "<4.4", + "symfony/proxy-manager-bridge": "<4.4", + "symfony/yaml": "<4.4.26" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/config": "^5.3|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4.26|^5.0|^6.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.48" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-20T10:51:57+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "2.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.4.45", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "57c8294ed37d4a055b77057827c67f9558c95c54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/57c8294ed37d4a055b77057827c67f9558c95c54", + "reference": "57c8294ed37d4a055b77057827c67f9558c95c54", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/process": "^5.4|^6.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.4.45" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-22T13:05:35+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "2.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:11:13+00:00" + }, + { + "name": "szepeviktor/phpstan-wordpress", + "version": "v1.3.5", + "source": { + "type": "git", + "url": "https://github.com/szepeviktor/phpstan-wordpress.git", + "reference": "7f8cfe992faa96b6a33bbd75c7bace98864161e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/7f8cfe992faa96b6a33bbd75c7bace98864161e7", + "reference": "7f8cfe992faa96b6a33bbd75c7bace98864161e7", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "php-stubs/wordpress-stubs": "^4.7 || ^5.0 || ^6.0", + "phpstan/phpstan": "^1.10.31", + "symfony/polyfill-php73": "^1.12.0" + }, + "require-dev": { + "composer/composer": "^2.1.14", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpstan/phpstan-strict-rules": "^1.2", + "phpunit/phpunit": "^8.0 || ^9.0", + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.0", + "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" + }, + "suggest": { + "swissspidy/phpstan-no-private": "Detect usage of internal core functions, classes and methods" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "SzepeViktor\\PHPStan\\WordPress\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "WordPress extensions for PHPStan", + "keywords": [ + "PHPStan", + "code analyse", + "code analysis", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/szepeviktor/phpstan-wordpress/issues", + "source": "https://github.com/szepeviktor/phpstan-wordpress/tree/v1.3.5" + }, + "time": "2024-06-28T22:27:19+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.3", diff --git a/docs/code-quality-setup.md b/docs/code-quality-setup.md new file mode 100644 index 0000000..167d185 --- /dev/null +++ b/docs/code-quality-setup.md @@ -0,0 +1,107 @@ +# Code Quality Tools Setup + +This document explains how to set up and use the code quality tools for this project. + +## Prerequisites + +* PHP 7.4 or higher +* Composer + +## Installation + +1. Clone the repository: + + ```bash + git clone https://github.com/wpallstars/wp-plugin-starter-template-for-ai-coding.git + cd wp-plugin-starter-template-for-ai-coding + ``` + +2. Install dependencies: + + ```bash + composer install + ``` + +## Available Tools + +### PHP CodeSniffer (PHPCS) + +PHPCS checks your code against the WordPress Coding Standards. + +```bash +# Run PHPCS +composer phpcs + +# Run PHPCS with a simplified ruleset +composer phpcs:simple +``` + +### PHP Code Beautifier and Fixer (PHPCBF) + +PHPCBF automatically fixes coding standard violations. + +```bash +# Run PHPCBF to fix coding standard violations +composer phpcbf + +# Run PHPCBF with a simplified ruleset +composer phpcbf:simple +``` + +### PHPStan + +PHPStan performs static analysis to find bugs in your code. + +```bash +# Run PHPStan +composer phpstan +``` + +### PHP Mess Detector (PHPMD) + +PHPMD detects potential problems in your code. + +```bash +# Run PHPMD +composer phpmd +``` + +### Running All Linters + +```bash +# Run all linters (PHPCS, PHPStan, PHPMD) +composer lint +``` + +### Running All Fixers + +```bash +# Run all fixers (PHPCBF) +composer fix +``` + +## Environment Variables + +For SonarCloud and Codacy integration, you need to set up the following environment variables: + +### SonarCloud + +```bash +export SONAR_TOKEN=your_sonar_token +``` + +### Codacy + +```bash +export CODACY_PROJECT_TOKEN=your_codacy_token +``` + +## CI/CD Integration + +The project includes GitHub Actions workflows for running these tools automatically on each push and pull request. See the `.github/workflows/code-quality.yml` file for details. + +## Customization + +* PHPCS rules can be customized in `phpcs.xml` +* PHPStan configuration is in `phpstan.neon` +* SonarCloud configuration is in `sonar-project.properties` diff --git a/includes/Admin/class-admin.php b/includes/Admin/class-admin.php index a07a54e..060a421 100644 --- a/includes/Admin/class-admin.php +++ b/includes/Admin/class-admin.php @@ -14,86 +14,71 @@ use WPALLSTARS\PluginStarterTemplate\Core; */ class Admin { - /** - * Core plugin class instance. - * - * @var Core - */ - private $core; + /** + * Core plugin class instance. + * + * @var Core + */ + private $core; - /** - * Constructor. - * - * @param Core $core Core instance. - */ - public function __construct( Core $core ) { - $this->core = $core; - $this->initialize_hooks(); - } + /** + * Constructor. + * + * @param Core $core Core instance. + */ + public function __construct( Core $core ) { + $this->core = $core; + $this->initialize_hooks(); + } - /** - * Initializes WordPress hooks. - */ - private function initialize_hooks() { - \add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) ); - } + /** + * Initializes WordPress hooks. + */ + private function initialize_hooks(): void { + \add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) ); + } - /** - * Enqueues admin-specific scripts and styles. - * - * This method is hooked into 'admin_enqueue_scripts'. It checks if the current - * screen is relevant to the plugin before enqueueing assets. + /** + * Enqueues admin-specific scripts and styles. + * + * This method is hooked into 'admin_enqueue_scripts'. It checks if the current + * screen is relevant to the plugin before enqueueing assets. - * + * * @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found - * @param string $hook_suffix The hook suffix of the current admin page. - */ - public function enqueue_admin_assets( string $hook_suffix ): void { + */ + public function enqueue_admin_assets(): void { // @phpcs:disable WordPress.Security.NonceVerification.Recommended // @phpcs:disable WordPress.Security.NonceVerification.Missing - if ( ! isset( $_GET['page'] ) || 'wp_plugin_starter_template_settings' !== $_GET['page'] ) { - return; - } + $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); + if ( ! $page || 'wp_plugin_starter_template_settings' !== $page ) { + return; + } // @phpcs:enable - // Get the plugin version. - $plugin_version = $this->core->get_plugin_version(); + // Get the plugin version. + $pluginVersion = $this->core->get_plugin_version(); - // Enqueue styles. - \wp_enqueue_style( - 'wpst-admin-styles', - \plugin_dir_url( __FILE__ ) . '../../admin/css/admin-styles.css', - array(), // Dependencies. - $plugin_version // Version. - ); + // Enqueue styles. + \wp_enqueue_style( + 'wpst-admin-styles', + \plugin_dir_url( __FILE__ ) . '../../admin/css/admin-styles.css', + array(), // Dependencies. + $pluginVersion // Version. + ); - // Enqueue admin scripts. - \wp_enqueue_script( - 'wpst-admin-script', - \plugin_dir_url( __FILE__ ) . '../../admin/js/admin-scripts.js', - array( 'jquery' ), - $plugin_version, // Version. - true - ); + // Enqueue admin scripts. + \wp_enqueue_script( + 'wpst-admin-script', + \plugin_dir_url( __FILE__ ) . '../../admin/js/admin-scripts.js', + array( 'jquery' ), + $pluginVersion, // Version. + true + ); - // Prepare data for localization. - $data = array( - 'ajax_url' => \admin_url( 'admin-ajax.php' ), - // @TODO: Fix mocking for wp_create_nonce. Issue #1. - // 'nonce' => \wp_create_nonce( 'wpst_admin_nonce' ), - ); - - // Localize the script with the data. - // @TODO: Fix mocking for wp_localize_script. Issue #1. - // @phpcs:ignore Squiz.PHP.CommentedOutCode.Found - /* - \wp_localize_script( - 'wpst-admin-script', - 'wpst_admin_data', - $data - ); - */ - } + // TODO: Implement localization when mocking is fixed (Issue #1). + // This will include ajax_url and nonce for security. + } } diff --git a/includes/class-core.php b/includes/class-core.php index 56d352f..3b4cb75 100644 --- a/includes/class-core.php +++ b/includes/class-core.php @@ -12,39 +12,39 @@ namespace WPALLSTARS\PluginStarterTemplate; */ class Core { - /** - * Plugin version - * - * @var string - */ - private $version; + /** + * Plugin version + * + * @var string + */ + private $version; - /** - * Constructor - * - * @param string $version Plugin version. - */ - public function __construct( $version = '' ) { - // Initialize hooks. - $this->version = $version; - } + /** + * Constructor + * + * @param string $version Plugin version. + */ + public function __construct( $version = '' ) { + // Initialize hooks. + $this->version = $version; + } - /** - * Example method to filter content - * - * @param string $content The content to filter. - * @return string The filtered content. - */ - public function filter_content( $content ) { - return $content; - } + /** + * Example method to filter content + * + * @param string $content The content to filter. + * @return string The filtered content. + */ + public function filter_content( $content ) { + return $content; + } - /** - * Get the plugin version - * - * @return string The plugin version. - */ - public function get_plugin_version() { - return $this->version; - } + /** + * Get the plugin version + * + * @return string The plugin version. + */ + public function get_plugin_version() { + return $this->version; + } } diff --git a/includes/class-plugin.php b/includes/class-plugin.php index a358a60..a1ab938 100644 --- a/includes/class-plugin.php +++ b/includes/class-plugin.php @@ -14,51 +14,51 @@ use WPALLSTARS\PluginStarterTemplate\Admin\Admin; */ class Plugin { - /** - * Core instance - * - * @var Core - */ - private $core; + /** + * Core instance + * + * @var Core + */ + private $core; - /** - * Admin instance - * - * @var Admin - */ - private $admin; + /** + * Admin instance + * + * @var Admin + */ + private $admin; - /** - * Plugin file - * - * @var string - */ - private $plugin_file; + /** + * Plugin file path + * + * @var string + */ + private string $pluginFile; - /** - * Plugin version - * - * @var string - */ - private $version; + /** + * Plugin version + * + * @var string + */ + private $version; - /** - * Constructor - * - * @param string $plugin_file Main plugin file path. - * @param string $version Plugin version. - */ - public function __construct( $plugin_file, $version ) { - $this->plugin_file = $plugin_file; - $this->version = $version; - $this->core = new Core( $version ); - $this->admin = new Admin( $this->core ); - } + /** + * Constructor + * + * @param string $pluginFile Main plugin file path. + * @param string $version Plugin version. + */ + public function __construct( string $pluginFile, string $version ) { + $this->pluginFile = $pluginFile; + $this->version = $version; + $this->core = new Core( $version ); + $this->admin = new Admin( $this->core ); + } - /** - * Initialize the plugin - */ - public function init() { - // Initialization logic goes here. - } + /** + * Initialize the plugin + */ + public function init() { + // Initialization logic goes here. + } } diff --git a/package.json b/package.json index c02bd37..b82dc0e 100644 --- a/package.json +++ b/package.json @@ -13,11 +13,13 @@ "build": "./build.sh", "lint:php": "composer run-script phpcs", "lint:php:simple": "composer run-script phpcs:simple", + "lint:phpstan": "composer run-script phpstan", + "lint:phpmd": "composer run-script phpmd", "fix:php": "composer run-script phpcbf", "fix:php:simple": "composer run-script phpcbf:simple", "test:php": "composer run-script test", - "lint": "npm run lint:php", - "fix": "npm run fix:php", + "lint": "composer run-script lint", + "fix": "composer run-script fix", "quality": "npm run lint && npm run test:php" }, "repository": { diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..f04ad33 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,65 @@ + + + WordPress dev PHP_CodeSniffer ruleset. + + + . + + */vendor/* + */node_modules/* + */bin/* + */.github/* + */tests/* + libs/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..07a5cbe --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,25 @@ +parameters: + level: 5 + paths: + - includes + - admin + - wp-plugin-starter-template.php + excludePaths: + paths: + - vendor + - node_modules + - tests + - bin + - build + - dist + ignoreErrors: + - '#Function apply_filters invoked with [0-9]+ parameters, 2 required.#' + - '#Function [a-zA-Z0-9_]+ not found.#' + - '#Call to static method [a-zA-Z0-9_:()]+ on an unknown class [a-zA-Z0-9_]+.#' + - '#Function do_action invoked with [0-9]+ parameters, 1 required.#' + - '#Function add_action invoked with [0-9]+ parameters, 2 required.#' + - '#Function add_filter invoked with [0-9]+ parameters, 2 required.#' + reportUnmatchedIgnoredErrors: false + +includes: + - vendor/szepeviktor/phpstan-wordpress/extension.neon diff --git a/wp-plugin-starter-template.php b/wp-plugin-starter-template.php index 319f0d3..680cebf 100644 --- a/wp-plugin-starter-template.php +++ b/wp-plugin-starter-template.php @@ -28,7 +28,7 @@ // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { - die; + die; } // Load the main plugin class.