├── .codeception.yml ├── .codeception ├── _config │ └── params.php ├── _data │ └── .gitignore └── _support │ ├── AcceptanceTester.php │ └── PluginNameTests │ └── TestCase.php ├── .env.example ├── .eslintignore ├── .eslintrc.js ├── .gitconfig ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── 1-Security-issue.md │ ├── 2-Support.md │ ├── 3-Bug-report.md │ ├── 4-Enhancement.md │ └── 5-Feature-request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── plugin-name.conf │ └── plugin-name.yml ├── .gitignore ├── .husky └── pre-push ├── .phpcs.xml ├── .scoper.inc.php ├── .stylelintrc ├── .tests ├── js │ ├── setupTests.js │ └── unit │ │ ├── main.test.js │ │ └── settings.test.js └── php │ ├── acceptance.suite.yml │ ├── acceptance │ └── SettingsCest.php │ ├── unit.suite.yml │ └── unit │ ├── Admin │ └── SettingsPageTest.php │ ├── Front │ └── FrontTest.php │ ├── PluginTest.php │ └── _bootstrap.php ├── .webpack.mix.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── SECURITY.md ├── assets └── .src │ ├── img │ └── yoda.jpg │ ├── js │ ├── admin │ │ └── settings │ │ │ ├── app.js │ │ │ └── settings.js │ └── front │ │ └── main │ │ ├── app.js │ │ └── main.js │ └── scss │ ├── admin │ └── settings.scss │ └── main.scss ├── composer.json ├── composer.lock ├── package-lock.json ├── package.json ├── plugin-name.php ├── readme.txt ├── src ├── Admin │ └── SettingsPage.php ├── Front │ └── Front.php └── Plugin.php ├── templates └── admin │ └── settings.php ├── uninstall.php └── vendor_prefixed └── .gitignore /.codeception.yml: -------------------------------------------------------------------------------- 1 | paths: 2 | tests: .tests/php 3 | output: .codeception/_output 4 | data: .codeception/_data 5 | support: .codeception/_support 6 | envs: .codeception/_envs 7 | actor_suffix: Tester 8 | extensions: 9 | enabled: 10 | - Codeception\Extension\RunFailed 11 | params: 12 | - env 13 | - .codeception/_config/params.php 14 | settings: 15 | backup_globals: false 16 | colors: true 17 | coverage: 18 | enabled: true 19 | low_limit: 20 20 | high_limit: 60 21 | show_only_summary: true 22 | include: 23 | - ./src/* 24 | -------------------------------------------------------------------------------- /.codeception/_config/params.php: -------------------------------------------------------------------------------- 1 | load( '.env.development' ); 27 | } catch ( ConfigurationException $e ) { 28 | throw new Exception( 'If you wan\'t to run your tests locally, then create the `.env.development` configuration file.' ); 29 | } 30 | } 31 | 32 | return [ 33 | 'WP_URL' => getenv( 'WP_URL' ), 34 | 'WP_ADMIN_USERNAME' => getenv( 'WP_ADMIN_USERNAME' ), 35 | 'WP_ADMIN_PASSWORD' => getenv( 'WP_ADMIN_PASSWORD' ), 36 | 'WP_ADMIN_PATH' => getenv( 'WP_ADMIN_PATH' ), 37 | 'DB_HOST' => getenv( 'DB_HOST' ), 38 | 'DB_NAME' => getenv( 'DB_NAME' ), 39 | 'DB_USER' => getenv( 'DB_USER' ), 40 | 'DB_PASSWORD' => getenv( 'DB_PASSWORD' ), 41 | 'DB_TABLE_PREFIX' => getenv( 'DB_TABLE_PREFIX' ), 42 | ]; 43 | 44 | -------------------------------------------------------------------------------- /.codeception/_data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /.codeception/_support/AcceptanceTester.php: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 18 | 19 | **Prerequisites (mark completed items with an [x]):** 20 | - [ ] I have have carried out troubleshooting steps and I believe I have found a bug. 21 | - [ ] I have searched for similar bugs in both open and closed issues and cannot find a duplicate. 22 | 23 | **Describe the bug** 24 | A clear and concise description of what the bug is. 25 | 26 | **Expected behavior** 27 | A clear and concise description of what you expected to happen. 28 | 29 | **Actual behavior** 30 | A clear and concise description of what actually happens. Please be as descriptive as possible; 31 | 32 | **Steps to reproduce the bug (We need to be able to reproduce the bug in order to fix it.)** 33 | Steps to reproduce the bug: 34 | 1. Go to '...' 35 | 2. Click on '....' 36 | 3. Scroll down to '....' 37 | 4. See error 38 | 39 | **Screenshots** 40 | 41 | **WordPress Environment** 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/4-Enhancement.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "✨ New Enhancement" 3 | about: If you have an idea to improve an existing feature in core or need something for development (such as a new hook) please let us know or submit a Pull Request! 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | **Is your feature request related to a problem? Please describe.** 13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 14 | 15 | **Describe the solution you'd like** 16 | A clear and concise description of what you want to happen. 17 | 18 | **Describe alternatives you've considered** 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | **Additional context** 22 | Add any other context or screenshots about the feature request here. 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/5-Feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature request" 3 | about: "Suggest a new feature \U0001F389 We'll consider building it if it receives sufficient interest! \U0001F44D" 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | **Is your feature request related to a problem? Please describe.** 12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 13 | 14 | **Describe the solution you'd like** 15 | A clear and concise description of what you want to happen. 16 | 17 | **Describe alternatives you've considered** 18 | A clear and concise description of any alternative solutions or features you've considered. 19 | 20 | **Additional context** 21 | Add any other context or screenshots about the feature request here. 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### All Submissions: 2 | 3 | 4 | 5 | ### Changes proposed in this Pull Request: 6 | 7 | Closes # . 8 | 9 | ### How to test the changes in this Pull Request: 10 | 11 | 1. 12 | 2. 13 | 3. 14 | 15 | ### Other information: 16 | 17 | 18 | * [ ] Have you added an explanation of what your changes do and why you'd like us to include them? 19 | * [ ] Have you written new tests for your changes, as applicable? 20 | * [ ] Have you successfully run tests with your changes locally? 21 | 22 | ### Changelog entry 23 | 24 | > Enter a summary of all changes on this Pull Request. This will appear in the changelog if accepted. 25 | -------------------------------------------------------------------------------- /.github/workflows/plugin-name.conf: -------------------------------------------------------------------------------- 1 | 2 | DocumentRoot /home/runner/work/WPPlugin/WPPlugin/wordpress 3 | ServerName plugin-name.test 4 | 5 | ErrorLog /home/runner/work/WPPlugin/WPPlugin/logs/error.log 6 | CustomLog /home/runner/work/WPPlugin/WPPlugin/logs/access.log combined 7 | 8 | DirectoryIndex index.php index.html /index.php 9 | 10 | 11 | Options FollowSymLinks 12 | DirectoryIndex index.php index.html /index.php 13 | AllowOverride All 14 | Require all granted 15 | 16 | 17 | 18 | 19 | DocumentRoot /home/runner/work/WPPlugin/WPPlugin/wordpress 20 | ServerName plugin-name.test 21 | 22 | ErrorLog /home/runner/work/WPPlugin/WPPlugin/logs/error.log 23 | CustomLog /home/runner/work/WPPlugin/WPPlugin/logs/access.log combined 24 | 25 | DirectoryIndex index.php index.html /index.php 26 | 27 | 28 | Options FollowSymLinks 29 | DirectoryIndex index.php index.html /index.php 30 | AllowOverride All 31 | Require all granted 32 | 33 | 34 | SSLEngine on 35 | SSLCertificateFile /etc/apache2/ssl/plugin-name.test/plugin-name.test.pem 36 | SSLCertificateKeyFile /etc/apache2/ssl/plugin-name.test/plugin-name.test-key.pem 37 | 38 | -------------------------------------------------------------------------------- /.github/workflows/plugin-name.yml: -------------------------------------------------------------------------------- 1 | name: PluginName GitHub Actions 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | strategy: 9 | matrix: 10 | php-versions: [7.4] 11 | 12 | runs-on: ubuntu-latest 13 | 14 | env: 15 | php-ext-cache-key: cache-v1 # can be any string, change to clear the extension cache. 16 | php-extensions: mysql 17 | php-ini-values: post_max_size=256M 18 | wp-directory: wordpress 19 | wp-plugins-directory: wordpress/wp-content/plugins/plugin-name/ 20 | DB_HOST: 127.0.0.1 21 | DB_TABLE_PREFIX: wp_ 22 | DB_NAME: test_db 23 | DB_USER: user 24 | DB_PASSWORD: passw0rd 25 | WP_URL: https://plugin-name.test 26 | WP_ADMIN_PATH: /wp-admin 27 | WP_DOMAIN: plugin-name.test 28 | WP_ADMIN_USERNAME: admin 29 | WP_ADMIN_PASSWORD: admin 30 | WP_ADMIN_EMAIL: admin@plugin-name.test 31 | 32 | services: 33 | mysql: 34 | image: mysql:5.6 35 | env: 36 | MYSQL_USER: ${{ env.DB_USER }} 37 | MYSQL_PASSWORD: ${{ env.DB_PASSWORD }} 38 | MYSQL_DATABASE: ${{ env.DB_NAME }} 39 | MYSQL_ALLOW_EMPTY_PASSWORD: yes 40 | ports: 41 | - 3306:3306 42 | options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 43 | 44 | steps: 45 | - name: Download Plugin 46 | uses: actions/checkout@v2 47 | with: 48 | path: ${{ env.wp-plugins-directory }} 49 | 50 | - name: Setup cache environment 51 | id: cache-env 52 | uses: shivammathur/cache-extensions@v1 53 | with: 54 | php-version: ${{ matrix.php-versions }} 55 | extensions: ${{ env.php-extensions }} 56 | key: ${{ env.php-ext-cache-key }} 57 | env: 58 | update: true 59 | 60 | - name: Cache extensions 61 | uses: actions/cache@v1 62 | with: 63 | path: ${{ steps.cache-env.outputs.dir }} 64 | key: ${{ steps.cache-env.outputs.key }} 65 | restore-keys: ${{ steps.cache-env.outputs.key }} 66 | 67 | - name: Setup PHP 68 | uses: shivammathur/setup-php@v2 69 | with: 70 | tools: pecl 71 | php-version: ${{ matrix.php-versions }} 72 | extensions: ${{ env.php-extensions }} 73 | ini-values: ${{ env.php-ini-values }} 74 | env: 75 | update: true 76 | 77 | - name: Validate composer.json and composer.lock 78 | working-directory: ${{ env.wp-plugins-directory }} 79 | run: composer validate 80 | 81 | - name: Install dependencies 82 | working-directory: ${{ env.wp-plugins-directory }} 83 | run: | 84 | composer install 85 | composer scoper 86 | composer dumpautoload 87 | npm install 88 | 89 | - name: Validate Coding Standard 90 | working-directory: ${{ env.wp-plugins-directory }} 91 | run: npm run cs 92 | 93 | - name: Run unit tests 94 | working-directory: ${{ env.wp-plugins-directory }} 95 | run: | 96 | composer unit 97 | npm run unit 98 | 99 | - name: Build assets 100 | working-directory: ${{ env.wp-plugins-directory }} 101 | run: npm run build:production 102 | 103 | - name: Install WP CLI 104 | run: | 105 | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar 106 | chmod +x wp-cli.phar 107 | mkdir -p wp-cli 108 | sudo mv wp-cli.phar wp-cli/wp 109 | echo "$GITHUB_WORKSPACE/wp-cli" >> $GITHUB_PATH 110 | echo -n "apache_modules:\n - mod_rewrite" > "${{ env.wp-directory }}/wp-cli.yml" 111 | 112 | - name: Install WP 113 | working-directory: ${{ env.wp-directory }} 114 | run: | 115 | wp core download --version=5.5 116 | wp config create --dbname="${{ env.DB_NAME }}" --dbuser="${{ env.DB_USER }}" --dbpass="${{ env.DB_PASSWORD }}" --dbhost="${{ env.DB_HOST }}" --dbprefix="${{ env.DB_TABLE_PREFIX }}" 117 | wp core install --url="${{ env.WP_URL }}" --title="Test" --admin_user="${{ env.WP_ADMIN_USERNAME }}" --admin_password="${{ env.WP_ADMIN_PASSWORD }}" --admin_email="${{ env.WP_ADMIN_EMAIL }}" --skip-email 118 | wp rewrite structure '/%postname%/' --hard 119 | wp plugin activate --all 120 | 121 | - name: Make a DB dump for Codeception 122 | working-directory: ${{ env.wp-plugins-directory }} 123 | run: mysqldump --column-statistics=0 --host="${{ env.DB_HOST }}" --user="${{ env.DB_USER }}" --password="${{ env.DB_PASSWORD }}" ${{ env.DB_NAME }} > .codeception/_data/dump.sql 124 | 125 | - name: Setup hosts 126 | run: | 127 | echo ${{ env.DB_HOST }} ${{ env.WP_DOMAIN }} | sudo tee -a /etc/hosts 128 | cat /etc/hosts 129 | 130 | - name: Force SSL 131 | run: | 132 | sudo apt install libnss3-tools -y 133 | wget https://github.com/FiloSottile/mkcert/releases/download/v1.4.3/mkcert-v1.4.3-linux-amd64 -O mkcert 134 | chmod +x mkcert 135 | sudo mv mkcert /usr/local/bin/ 136 | mkcert -install 137 | localcaroot=$(mkcert -CAROOT) 138 | sudo mkdir -p /etc/apache2/ssl/${{ env.WP_DOMAIN }} && cd $_ 139 | sudo CAROOT=$localcaroot mkcert ${{ env.WP_DOMAIN }} 140 | 141 | - name: Install & configure Apache 142 | run: | 143 | sudo add-apt-repository ppa:ondrej/php 144 | sudo apt-get update 145 | sudo apt-get install apache2 libapache2-mod-php7.4 146 | mkdir -p logs 147 | sudo cp ${{ env.wp-plugins-directory }}/.github/workflows/plugin-name.conf /etc/apache2/sites-available/plugin-name.conf 148 | sudo a2enmod headers 149 | sudo a2enmod rewrite 150 | sudo a2enmod ssl 151 | sudo a2ensite plugin-name 152 | sudo apachectl configtest 153 | sudo service apache2 restart 154 | 155 | - name: Set .htaccess 156 | working-directory: ${{ env.wp-directory }} 157 | run: | 158 | echo '# BEGIN WordPress 159 | RewriteEngine On 160 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 161 | RewriteBase / 162 | RewriteRule ^index\.php$ - [L] 163 | RewriteCond %{REQUEST_FILENAME} !-f 164 | RewriteCond %{REQUEST_FILENAME} !-d 165 | RewriteRule . /index.php [L] 166 | # END WordPress' > .htaccess 167 | 168 | - name: Setup Chromedriver 169 | uses: nanasess/setup-chromedriver@master 170 | 171 | - name: Run Chromedriver 172 | run: | 173 | export DISPLAY=:99 174 | chromedriver --url-base=/wd/hub & 175 | sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional 176 | 177 | - name: Run Acceptance Tests 178 | working-directory: ${{ env.wp-plugins-directory }} 179 | run: composer acceptance -- --env github-actions 180 | 181 | - name: Archive Codeception output 182 | uses: actions/upload-artifact@v1 183 | if: failure() 184 | with: 185 | name: codeception-output 186 | path: ${{ env.wp-plugins-directory }}/.codeception/_output 187 | 188 | - name: Archive Apache Logs 189 | uses: actions/upload-artifact@v1 190 | if: failure() 191 | with: 192 | name: apache-logs 193 | path: logs 194 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.idea/ 3 | /.codeception/_cache/ 4 | /.codeception/_output/ 5 | /.codeception/_config/params.local.php 6 | /.codeception/_support/_generated/ 7 | /assets/build/ 8 | /node_modules/ 9 | /vendor/ 10 | /vendor-bin/ 11 | /vendor_prefixed/ 12 | .env.development 13 | .env.production 14 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run cs -- --silent --continue-on-error -------------------------------------------------------------------------------- /.phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | The code standard for PluginName. 4 | 5 | \.codeception/* 6 | \.github/* 7 | vendor/* 8 | vendor_prefixed/* 9 | node_modules/* 10 | \.idea/* 11 | assets/* 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 0 42 | 43 | 44 | 45 | 46 | 47 | \.codeception/_support/* 48 | \.tests/php/* 49 | 50 | 51 | \.codeception/_support/* 52 | \.tests/php/* 53 | 54 | 55 | \.codeception/_support/* 56 | \.tests/php/* 57 | 58 | 59 | \.codeception/_support/* 60 | \.tests/php/* 61 | 62 | 63 | \.codeception/_support/* 64 | \.tests/php/* 65 | 66 | 67 | \.codeception/_support/* 68 | \.tests/php/* 69 | 70 | 71 | 72 | \.codeception/_support/* 73 | \.tests/php/* 74 | 75 | 76 | -------------------------------------------------------------------------------- /.scoper.inc.php: -------------------------------------------------------------------------------- 1 | 'PluginName\\Vendor', 10 | 'whitelist-global-constants' => false, 11 | 'whitelist-global-classes' => false, 12 | 'whitelist-global-functions' => false, 13 | 14 | /** 15 | * By default when running php-scoper add-prefix, it will prefix all relevant code found in the current working 16 | * directory. You can however define which files should be scoped by defining a collection of Finders in the 17 | * following configuration key. 18 | * 19 | * For more see: https://github.com/humbug/php-scoper#finders-and-paths. 20 | */ 21 | 'finders' => [ 22 | Finder::create()-> 23 | files()-> 24 | in( 25 | [ 26 | 'vendor/rdlowrey/auryn/lib', 27 | ] 28 | )-> 29 | exclude( 30 | [ 31 | 'test', 32 | 'examples', 33 | ] 34 | )-> 35 | name( [ '*.php' ] ), 36 | ], 37 | 38 | /** When scoping PHP files, there will be scenarios where some of the code being scoped indirectly references the 39 | * original namespace. These will include, for example, strings or string manipulations. PHP-Scoper has limited 40 | * support for prefixing such strings. To circumvent that, you can define patchers to manipulate the file to your 41 | * heart contents. 42 | * 43 | * For more see: https://github.com/humbug/php-scoper#patchers. 44 | */ 45 | 'patchers' => [ 46 | function ( string $file_path, string $prefix, string $contents ): string { 47 | 48 | // Change the contents here. 49 | return str_replace( 50 | 'Auryn\\\\', 51 | sprintf( '%s\\\\Auryn\\\\', addslashes( $prefix ) ), 52 | $contents 53 | ); 54 | }, 55 | ], 56 | ]; 57 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules": { 4 | "indentation": "tab", 5 | "selector-pseudo-element-colon-notation": "single", 6 | "at-rule-no-unknown": [ 7 | true, 8 | { 9 | "ignoreAtRules": [ 10 | "extend", 11 | "at-root", 12 | "debug", 13 | "warn", 14 | "error", 15 | "if", 16 | "else", 17 | "for", 18 | "each", 19 | "while", 20 | "mixin", 21 | "include", 22 | "content", 23 | "return", 24 | "tailwind", 25 | "apply", 26 | "responsive", 27 | "variants", 28 | "screen", 29 | "function" 30 | ] 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.tests/js/setupTests.js: -------------------------------------------------------------------------------- 1 | global.fetch = require( 'jest-fetch-mock' ); 2 | -------------------------------------------------------------------------------- /.tests/js/unit/main.test.js: -------------------------------------------------------------------------------- 1 | import { Main } from '../../../assets/.src/js/front/main/main.js'; 2 | 3 | describe( 'Main constructor', () => { 4 | it( 'console.log the text "Main was started"', () => { 5 | const consoleSpy = jest.spyOn( console, 'log' ); 6 | 7 | new Main(); 8 | 9 | expect( consoleSpy ).toHaveBeenCalledWith( 'Main was started' ); 10 | } ); 11 | } ); 12 | -------------------------------------------------------------------------------- /.tests/js/unit/settings.test.js: -------------------------------------------------------------------------------- 1 | import { Settings } from '../../../assets/.src/js/admin/settings/settings.js'; 2 | 3 | describe( 'Settings constructor', () => { 4 | it( 'console.log the text "Settings was started"', () => { 5 | const consoleSpy = jest.spyOn( console, 'log' ); 6 | 7 | new Settings(); 8 | 9 | expect( consoleSpy ).toHaveBeenCalledWith( 'Settings was started' ); 10 | } ); 11 | } ); 12 | -------------------------------------------------------------------------------- /.tests/php/acceptance.suite.yml: -------------------------------------------------------------------------------- 1 | # Codeception Test Suite Configuration 2 | # 3 | # Suite for acceptance tests. 4 | # Perform tests in browser using the WPWebDriver or WPBrowser. 5 | # Use WPDb to set up your initial database fixture. 6 | # If you need both WPWebDriver and WPBrowser tests - create a separate suite. 7 | 8 | actor: AcceptanceTester 9 | extensions: 10 | enabled: 11 | - Codeception\Extension\RunProcess: 12 | 0: chromedriver --url-base=/wd/hub 13 | sleep: 5 # wait 5 seconds for processes to boot 14 | - Codeception\Extension\RunFailed 15 | commands: 16 | - Codeception\Command\GenerateWPUnit 17 | - Codeception\Command\GenerateWPRestApi 18 | - Codeception\Command\GenerateWPRestController 19 | - Codeception\Command\GenerateWPRestPostTypeController 20 | - Codeception\Command\GenerateWPAjax 21 | - Codeception\Command\GenerateWPCanonical 22 | - Codeception\Command\GenerateWPXMLRPC 23 | modules: 24 | enabled: 25 | - Asserts 26 | - WPDb 27 | - WPWebDriver 28 | config: 29 | WPDb: 30 | dsn: 'mysql:host=%DB_HOST%;dbname=%DB_NAME%' 31 | user: '%DB_USER%' 32 | password: '%DB_PASSWORD%' 33 | dump: '.codeception/_data/dump.sql' 34 | #import the dump before the tests; this means the test site database will be repopulated before the tests. 35 | populate: true 36 | # re-import the dump between tests; this means the test site database will be repopulated between the tests. 37 | cleanup: true 38 | waitlock: 10 39 | url: '%WP_URL%' 40 | urlReplacement: true #replace the hardcoded dump URL with the one above 41 | tablePrefix: '%DB_TABLE_PREFIX%' 42 | WPWebDriver: 43 | url: '%WP_URL%' 44 | port: 9515 45 | window_size: maximize 46 | browser: chrome 47 | host: localhost 48 | adminUsername: '%WP_ADMIN_USERNAME%' 49 | adminPassword: '%WP_ADMIN_PASSWORD%' 50 | adminPath: '%WP_ADMIN_PATH%' 51 | capabilities: 52 | acceptInsecureCerts: true 53 | # Used in more recent releases of Selenium. 54 | "goog:chromeOptions": 55 | # Headless config for production, redefined in env section below. 56 | # args: ["--user-agent=wp-browser", "--headless"] 57 | # Non-headless config for debugging. 58 | args: ["--user-agent=wp-browser", "--ignore-certificate-errors"] 59 | 60 | env: 61 | github-actions: 62 | extensions: 63 | enabled: 64 | - Codeception\Extension\RunProcess: 65 | modules: 66 | config: 67 | WPWebDriver: 68 | capabilities: 69 | "goog:chromeOptions": 70 | args: ["--user-agent=wp-browser", "--headless"] 71 | -------------------------------------------------------------------------------- /.tests/php/acceptance/SettingsCest.php: -------------------------------------------------------------------------------- 1 | loginAsAdmin(); 26 | $i->amOnAdminPage( '/admin.php?page=plugin-name' ); 27 | $i->see( 'Plugin Name Settings' ); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /.tests/php/unit.suite.yml: -------------------------------------------------------------------------------- 1 | bootstrap: ./_bootstrap.php 2 | -------------------------------------------------------------------------------- /.tests/php/unit/Admin/SettingsPageTest.php: -------------------------------------------------------------------------------- 1 | hooks(); 34 | 35 | $this->assertSame( 10, has_action( 'admin_enqueue_scripts', [ $settings, 'enqueue_styles' ] ) ); 36 | $this->assertSame( 10, has_action( 'admin_enqueue_scripts', [ $settings, 'enqueue_scripts' ] ) ); 37 | $this->assertSame( 10, has_action( 'admin_menu', [ $settings, 'add_menu' ] ) ); 38 | } 39 | 40 | /** 41 | * Test don't enqueue styles 42 | */ 43 | public function testDontEnqueueStyles(): void { 44 | $settings = new SettingsPage(); 45 | 46 | $settings->enqueue_styles( 'hook-suffix' ); 47 | } 48 | 49 | /** 50 | * Test enqueue styles 51 | * 52 | * @throws ExpectationArgsRequired Invalid arguments. 53 | */ 54 | public function testEnqueueStyles(): void { 55 | $settings = new SettingsPage(); 56 | expect( 'wp_enqueue_style' ) 57 | ->once() 58 | ->with( 59 | 'plugin-name-settings', 60 | PLUGIN_NAME_URL . 'assets/build/css/admin/settings.css', 61 | [], 62 | Plugin::VERSION, 63 | 'all' 64 | ); 65 | 66 | $settings->enqueue_styles( 'plugin-name' ); 67 | } 68 | 69 | /** 70 | * Test don't enqueue scripts 71 | */ 72 | public function testDontEnqueueScripts(): void { 73 | $settings = new SettingsPage(); 74 | 75 | $settings->enqueue_scripts( 'hook-suffix' ); 76 | } 77 | 78 | /** 79 | * Test enqueue scripts 80 | * 81 | * @throws ExpectationArgsRequired Invalid arguments. 82 | */ 83 | public function testEnqueueScripts(): void { 84 | $settings = new SettingsPage(); 85 | expect( 'wp_enqueue_script' ) 86 | ->once() 87 | ->with( 88 | 'plugin-name-settings', 89 | PLUGIN_NAME_URL . 'assets/build/js/admin/settings.js', 90 | [ 'jquery' ], 91 | Plugin::VERSION, 92 | true 93 | ); 94 | 95 | $settings->enqueue_scripts( 'plugin-name' ); 96 | } 97 | 98 | /** 99 | * Test register menu 100 | * 101 | * @throws ExpectationArgsRequired 102 | */ 103 | public function testAddMenu(): void { 104 | $settings = new SettingsPage(); 105 | when( 'esc_html__' )->returnArg(); 106 | expect( 'add_menu_page' ) 107 | ->once() 108 | ->with( 109 | 'Plugin Name Settings', 110 | 'Plugin Name', 111 | 'manage_options', 112 | Plugin::SLUG, 113 | [ 114 | $settings, 115 | 'page_options', 116 | ] 117 | ); 118 | 119 | $settings->add_menu(); 120 | } 121 | 122 | /** 123 | * Test view for settings page 124 | * 125 | * @throws ExpectationArgsRequired 126 | */ 127 | public function testPageOption(): void { 128 | $pageTitle = 'Plugin Name Settings'; 129 | $settings = new SettingsPage(); 130 | expect( 'get_admin_page_title' ) 131 | ->once() 132 | ->withNoArgs() 133 | ->andReturn( $pageTitle ); 134 | when( 'esc_html' )->returnArg(); 135 | 136 | $settings->page_options(); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /.tests/php/unit/Front/FrontTest.php: -------------------------------------------------------------------------------- 1 | hooks(); 33 | 34 | $this->assertSame( 10, has_action( 'wp_enqueue_scripts', [ $front, 'enqueue_styles' ] ) ); 35 | $this->assertSame( 10, has_action( 'wp_enqueue_scripts', [ $front, 'enqueue_scripts' ] ) ); 36 | } 37 | 38 | /** 39 | * Test enqueue styles 40 | * 41 | * @throws ExpectationArgsRequired Invalid arguments. 42 | */ 43 | public function testEnqueueStyles(): void { 44 | $front = new Front(); 45 | expect( 'wp_enqueue_style' ) 46 | ->once() 47 | ->with( 48 | 'plugin-name', 49 | PLUGIN_NAME_URL . 'assets/build/css/main.css', 50 | [], 51 | Plugin::VERSION, 52 | 'all' 53 | ); 54 | 55 | $front->enqueue_styles(); 56 | } 57 | 58 | /** 59 | * Test enqueue scripts 60 | * 61 | * @throws ExpectationArgsRequired Invalid arguments. 62 | */ 63 | public function testEnqueueScripts(): void { 64 | $front = new Front(); 65 | expect( 'wp_enqueue_script' ) 66 | ->once() 67 | ->with( 68 | 'plugin-name', 69 | PLUGIN_NAME_URL . 'assets/build/js/main.js', 70 | [], 71 | Plugin::VERSION, 72 | true 73 | ); 74 | 75 | $front->enqueue_scripts(); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /.tests/php/unit/PluginTest.php: -------------------------------------------------------------------------------- 1 | once() 37 | ->withNoArgs() 38 | ->andReturn( true ); 39 | $settings = \Mockery::mock( SettingsPage::class ); 40 | $settings 41 | ->shouldReceive( 'hooks' ) 42 | ->once() 43 | ->withNoArgs(); 44 | $injector = \Mockery::mock( Injector::class ); 45 | $injector 46 | ->shouldReceive( 'make' ) 47 | ->once() 48 | ->with( SettingsPage::class ) 49 | ->andReturn( $settings ); 50 | $plugin = new Plugin( $injector ); 51 | 52 | $plugin->run(); 53 | } 54 | 55 | /** 56 | * Test for adding hooks 57 | * 58 | * @throws ExpectationArgsRequired 59 | * @throws Exception 60 | */ 61 | public function testRunFront(): void { 62 | expect( 'is_admin' ) 63 | ->once() 64 | ->withNoArgs() 65 | ->andReturn( false ); 66 | $front = \Mockery::mock( Front::class ); 67 | $front 68 | ->shouldReceive( 'hooks' ) 69 | ->once() 70 | ->withNoArgs(); 71 | $injector = \Mockery::mock( Injector::class ); 72 | $injector 73 | ->shouldReceive( 'make' ) 74 | ->once() 75 | ->with( Front::class ) 76 | ->andReturn( $front ); 77 | $plugin = new Plugin( $injector ); 78 | 79 | $plugin->run(); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /.tests/php/unit/_bootstrap.php: -------------------------------------------------------------------------------- 1 | = 7.2.5 (You can easily downgrade it) 21 | - DOM extension 22 | - CURL extension 23 | - Composer 24 | - Node.js >= 14.8 25 | - npm 26 | - ChromeDriver (for acceptance tests) 27 | 28 | ## Structure 29 | 30 | ``` 31 | plugins/your-awesome-plugin/ # → Root of your plugin. 32 | ├── .codeception/ # → Codeception additional directories. 33 | │ ├── _config/ # → Configs for DB connection. 34 | │ ├── _data/ # → Folder for SQL dump. 35 | │ └── _support/ # → Additional classes for the Codeception tests. 36 | ├── .github/ # → GitHub additional directories. 37 | │ └── workflows/ # → Workflows. 38 | │ ├── plugin-name.conf # → Config for the server. 39 | │ └── plugin-name.yml # → Actions for GitHub. 40 | ├── .tests/ # → Tests. 41 | │ └── php # → PHP tests. 42 | │ ├── acceptance # → PHP Acceptance tests. 43 | │ ├── unit # → PHP Unit tests. 44 | │ │ └── _bootstrap.php # → Bootstrap file for PHP unit tests. 45 | │ ├── acceptance.suite.yml # → Config file for the acceptance tests. 46 | │ └── unit.suite.yml # → Config file for the unit tests. 47 | ├── assets/ # → Assets directory. 48 | │ ├── build/ # → Assets build directory. 49 | │ └── src/ # → Assets source directory. 50 | ├── node_modules/ # → JS packages (never edit). 51 | ├── src/ # → PHP directory. 52 | ├── templates/ # → Templates for plugin views. 53 | ├── vendor/ # → Composer packages (never edit). 54 | ├── vendor_prefixes/ # → Prefixed composer packages for non-conflict mode (never edit). 55 | ├── .codeception.yml # → Main codeception config. 56 | ├── .env.example # → Example for the .env.development and .env.production files 57 | ├── .eslintignore # → JS Coding Standards ignore file. 58 | ├── .eslintrc.js # → JS Coding Standards config. 59 | ├── .gitconfig # → Config for git. 60 | ├── .gitignore # → Git ignore file. 61 | ├── .phpcs.xml # → Custom PHP Coding Standards. 62 | ├── .scoper.inc.php # → Config for the PHP Scoper. 63 | ├── .stylelintrc # → Config for the style linter. 64 | ├── .webpack.mix.js # → Laravel Mix configuration file. 65 | ├── CHANGELOG.md # → Changelog file for GH. 66 | ├── composer.json # → Composer dependencies and scripts. 67 | ├── composer.lock # → Composer lock file (never edit). 68 | ├── LICENSE # → License file. 69 | ├── package.json # → JS dependencies and scripts. 70 | ├── package-lock.json # → Package lock file (never edit). 71 | ├── plugin-name.php # → Bootstrap plugin file. 72 | ├── README.md # → Readme MD for GitHub repository. 73 | ├── readme.txt # → Readme TXT for the wp.org repository. 74 | └── uninstall.php # → Uninstall file. 75 | ``` 76 | 77 | ## Autoload 78 | 79 | We use PSR-4 and composer autoload for PSR-4. You can find it in `composer.json` in directive `autoload`. 80 | 81 | ## Coding Standards 82 | 83 | To check all coding standards: 84 | ``` 85 | npm run cs 86 | ``` 87 | 88 | ### PHP Coding Standard (PHPCS) 89 | 90 | We use a custom coding standard based on [WordPress Coding Standard](https://github.com/WordPress/WordPress-Coding-Standards). We disabled rules for the naming of WordPress files for using PSR-4 autoload. Also, we have a [feature](https://github.com/PHPCompatibility/PHPCompatibilityWP), which can allow testing your code using different PHP environments. 91 | 92 | Custom PHPCS your can find in the `.phpcs.xml`. 93 | 94 | Your can check PHPCS using a CLI: 95 | ``` 96 | composer cs 97 | ``` 98 | or 99 | ``` 100 | npm run cs:php 101 | ``` 102 | 103 | Pay attention, tests have a bit another coding standards because testing libraries all using camelCase format for methods, function, variables, and properties. 104 | 105 | PHPCS checked before each commit, before the push, and in GH Actions. 106 | 107 | ### JS Coding Standard (JSCS) 108 | 109 | We use a default WordPress JSCS, but you can modify it in the `.eslintrc` file. 110 | 111 | You can check JSCS using a CLI: 112 | 113 | ``` 114 | npm run cs:js 115 | ``` 116 | 117 | ### SCSS Coding Standard (SCSSCS) 118 | 119 | We use a default standards for SCSS, but you can modify it in the `.stylelintrc` file. 120 | 121 | You can check SCSSCS using a CLI: 122 | 123 | ``` 124 | npm run cs:scss 125 | ``` 126 | 127 | ## Environments 128 | 129 | For any constants you can create the `.env.development` and `.env.production` files. For example, we use these constants from the `.env.example` file for the browserSync inside the Laravel Mix config and for acceptance tests. 130 | 131 | ## Frontend 132 | 133 | All assets are located in `assets/src/*`. 134 | 135 | All builds are located in `assets/build/*`. 136 | 137 | CSS preprocessor is SCSS. 138 | 139 | We use [Laravel Mix](https://laravel-mix.com/) for the assets build. You can modify it in `.webpack.mix.js` file. 140 | 141 | For run Laravel mix you can use the next commands depend on situation: 142 | ``` 143 | npm run build 144 | npm run build:production 145 | npm run start 146 | ``` 147 | 148 | ## GitHub 149 | 150 | ### GH Actions 151 | All steps for GH Actions you can find in `.github/workflows/plugin-name.yml` file. Also, for wake up a webserver, we need to add `.github/workflows/plugin-name.conf` 152 | 153 | ### GH Hooks 154 | 155 | Just make you GH repository clear. We use the [Husky](https://github.com/typicode/husky) library to add actions before commit, push, etc. This helps developers make their GH more clear. 156 | 157 | ### GH Templates 158 | 159 | Basic GH templates for better security issues, support requests, bug reports, enhancements, feature requests, pull requests, and contributing templates. 160 | 161 | ## Dependency injection container 162 | 163 | The lightweight [Dependency Injection](https://github.com/rdlowrey/auryn) component implements a PSR-11 compatible service container that allows you to standardize and centralize the way objects are constructed in your application. 164 | 165 | Automatic load your dependencies using the type hinting. 166 | 167 | You can disable plugin hooks very easily using a DIC. Just get the plugin object from the dependency injection container `$container_builder->get( PluginName\Front\Front::class )`. Example just disabling frontend assets: 168 | ``` 169 | function remove_plugin_name_frontend_assets( $injector ) { 170 | $front = $injector->make( PluginName\Front\Front::class ); 171 | if ( ! $front ) { 172 | return; 173 | } 174 | remove_action( 'wp_enqueue_scripts', [ $front, 'enqueue_styles' ] ); 175 | remove_action( 'wp_enqueue_scripts', [ $front, 'enqueue_scripts' ] ); 176 | } 177 | 178 | add_action( 'plugin_name_init', 'remove_plugin_name_frontend_assets' ); 179 | ``` 180 | 181 | ## PHP Scoper 182 | 183 | You need to add prefixes for each outside dependency because other plugins or themes can use the same dependencies, and it can conflict between packages. 184 | 185 | ``` 186 | composer scoper 187 | ``` 188 | 189 | ## Automated testing 190 | 191 | We are using for automated testing a Codeception library runs all types of PHP tests. 192 | 193 | ### PHP unit tests 194 | 195 | For running use a CLI command: 196 | ``` 197 | composer unit 198 | ``` 199 | 200 | - Main configuration file `.tests/php/unit.suite.yml` 201 | - Unit tests inside `.tests/php/unit/*` folder. 202 | - Bootstrap file `.tests/php/unit/_bootstrap.php` 203 | - Each filename for test class must have a suffix on `*Test.php`. 204 | - Each test class must extend a `PluginNameUnitTests\TestCase` class. 205 | - You can also add some code to `PluginNameUnitTests\TestCase.php` 206 | - Each test method must have prefix `test_` 207 | - Additional files for autoloading in tests running you can add to `.codeception/_support/*` folder. 208 | 209 | Also, unit tests will be checked on a push to repository action and inside the GH Actions pipeline. 210 | 211 | ### PHP acceptance tests 212 | 213 | **Warning!** The acceptance tests make REAL actions on your site. Before running need to create another database and create a `dump.sql` file with fresh WP install. 214 | 215 | Before running, you need to (It needs to make just one time. I hope you can do it): 216 | 1. Install a [ChromeDriver](https://chromedriver.chromium.org/downloads) 217 | 2. Create a new database. For example, I named a database `codeception_db` 218 | 3. Install a clear WordPress 219 | 4. Export database to `dump.sql` 220 | 5. Move a `dump.sql` file to the `.codeception/_data/` folder. 221 | 6. Copy a file `.codeception/_config/params.example.php` to `.codeception/_config/params.local.php`. 222 | 7. Update your connection information to the testing site connection in `.codeception/_config/params.local.php` file. 223 | 8. Update your `wp-config.php` file: 224 | ```php 225 | if ( 226 | isset( $_SERVER['HTTP_X_TESTING'] ) 227 | || ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'wp-browser' ) 228 | || getenv( 'WPBROWSER_HOST_REQUEST' ) 229 | ) { 230 | // Use the test database if the request comes from a test. 231 | define( 'DB_NAME', 'codeception_db' ); 232 | } else { 233 | // Else use the default one (insert your local DB name here). 234 | define( 'DB_NAME', 'local' ); 235 | } 236 | ``` 237 | 238 | For running use a CLI command: 239 | ``` 240 | composer acceptance 241 | ``` 242 | 243 | - Main configuration file `.tests/php/acceptance.suite.yml` 244 | - Unit tests inside `.tests/php/acceptace/*` folder. 245 | - Each filename for test class must have a suffix on `*Cest.php`. 246 | - Each test method must have prefix `test_` 247 | - Each test method must include `AcceptanceTester` as argument. 248 | - You can add some methods to AcceptanceTester in `.codeception/_support/AcceptanceTests.php`. 249 | - Additional files for autoload in tests running you can add to `.codeception/_support/*` folder. 250 | 251 | ### JS unit tests 252 | 253 | For running use a CLI command: 254 | ``` 255 | npm run unit 256 | ``` 257 | 258 | - Main configuration inside `.tests/js/package.json` in directory `jest` 259 | - Unit tests inside `.tests/js/unit/*` folder. 260 | - Bootstrap file `.tests/js/setupTests.js` 261 | - Each filename for test class must have a suffix on `*.test.js`. 262 | - Just import your class for testing and write tests. 263 | 264 | Also, unit tests will be checked on a push to repository action and inside the GH Actions pipeline. 265 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 0.1.x | :x: | 11 | | 1.0.x | :white_check_mark: | 12 | 13 | ## Reporting a Vulnerability 14 | 15 | Use this section to tell people how to report a vulnerability. 16 | 17 | Tell them where to go, how often they can expect to get an update on a 18 | reported vulnerability, what to expect if the vulnerability is accepted or 19 | declined, etc. 20 | -------------------------------------------------------------------------------- /assets/.src/img/yoda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wppunk/WPPlugin/5aae11f2b50d1485b3a79089f5342176c3ef2c07/assets/.src/img/yoda.jpg -------------------------------------------------------------------------------- /assets/.src/js/admin/settings/app.js: -------------------------------------------------------------------------------- 1 | import { Settings } from './settings'; 2 | 3 | document.defaultView.document.addEventListener('DOMContentLoaded', () => { 4 | new Settings(); 5 | }); 6 | -------------------------------------------------------------------------------- /assets/.src/js/admin/settings/settings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Class Settings. 3 | * 4 | * @since 1.0.0 5 | */ 6 | export class Settings { 7 | /** 8 | * Settings constructor. 9 | * 10 | * @since 1.0.0 11 | */ 12 | constructor() { 13 | // eslint-disable-next-line no-console 14 | console.log('Settings was started'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /assets/.src/js/front/main/app.js: -------------------------------------------------------------------------------- 1 | import { Main } from './main'; 2 | 3 | document.defaultView.document.addEventListener('DOMContentLoaded', () => { 4 | new Main(); 5 | }); 6 | -------------------------------------------------------------------------------- /assets/.src/js/front/main/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Class Main. 3 | * 4 | * @since 1.0.0 5 | */ 6 | export class Main { 7 | /** 8 | * Main constructor. 9 | * 10 | * @since 1.0.0 11 | */ 12 | constructor() { 13 | // eslint-disable-next-line no-console 14 | console.log('Main was started'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /assets/.src/scss/admin/settings.scss: -------------------------------------------------------------------------------- 1 | $bg: lightgray; 2 | 3 | body { 4 | background-color: $bg; 5 | } 6 | -------------------------------------------------------------------------------- /assets/.src/scss/main.scss: -------------------------------------------------------------------------------- 1 | $bg: lightgray; 2 | 3 | body { 4 | background-color: $bg; 5 | } 6 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wppunk/wpplugin", 3 | "description": "Plugin description", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "WPPunk", 8 | "email": "i@wp-punk.com" 9 | } 10 | ], 11 | "config": { 12 | "platform": { 13 | "php": "7.2.5" 14 | } 15 | }, 16 | "require": { 17 | "rdlowrey/auryn": "^1.4" 18 | }, 19 | "require-dev": { 20 | "bamarni/composer-bin-plugin": "^1.4", 21 | "brain/monkey": "^2.6", 22 | "codeception/codeception": "^4.1", 23 | "codeception/module-asserts": "^1.3", 24 | "codeception/module-db": "^1.1", 25 | "codeception/module-webdriver": "^1.4", 26 | "dealerdirect/phpcodesniffer-composer-installer": "^0.7", 27 | "lucatume/wp-browser": "^3.0", 28 | "phpcompatibility/php-compatibility": "^9.3", 29 | "wp-coding-standards/wpcs": "^2.3" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "PluginName\\": "src/" 34 | }, 35 | "classmap": [ 36 | "vendor_prefixed/" 37 | ] 38 | }, 39 | "extra": { 40 | "phpcodesniffer-search-depth": 1 41 | }, 42 | "scripts": { 43 | "acceptance": "codecept run acceptance -c .codeception.yml", 44 | "unit": "codecept run unit -c .codeception.yml", 45 | "cs": "phpcs --standard=.phpcs.xml .", 46 | "scoper": [ 47 | "composer bin php-scoper config minimum-stability dev", 48 | "composer bin php-scoper config prefer-stable true", 49 | "composer bin php-scoper require --dev humbug/php-scoper", 50 | "php-scoper add-prefix --config .scoper.inc.php --output-dir vendor_prefixed/", 51 | "rm -rf vendor-bin/", 52 | "composer dumpautoload" 53 | ], 54 | "build": [ 55 | "composer require rdlowrey/auryn", 56 | "composer scoper -n", 57 | "composer remove rdlowrey/auryn", 58 | "composer dumpautoload" 59 | ], 60 | "init-project": [ 61 | "composer require wppunk/wpplugin-replace --dev", 62 | "@php vendor/wppunk/wpplugin-replace/wpplugin-replace.php", 63 | "composer remove wppunk/wpplugin-replace --dev", 64 | "composer build", 65 | "npm install" 66 | ], 67 | "post-create-project-cmd": [ 68 | "composer init-project" 69 | ] 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plugin-name", 3 | "version": "1.0.0", 4 | "repository": "{URL}", 5 | "author": "{AUTHOR} <{AUTHOR_URL}>", 6 | "license": "MIT", 7 | "dependencies": {}, 8 | "devDependencies": { 9 | "@wordpress/babel-preset-default": "^6.3.2", 10 | "@wordpress/browserslist-config": "^4.1.0", 11 | "@wordpress/dependency-extraction-webpack-plugin": "^3.2.1", 12 | "@wordpress/eslint-plugin": "^9.1.2", 13 | "babel-eslint": "^10.1.0", 14 | "babel-preset-env": "^1.7.0", 15 | "browser-sync": "^2.27.5", 16 | "browser-sync-webpack-plugin": "^2.3.0", 17 | "cross-env": "^7.0.3", 18 | "css-loader": "^6.3.0", 19 | "eslint": "^7.32.0", 20 | "eslint-loader": "^4.0.2", 21 | "eslint-plugin-compat": "^3.13.0", 22 | "eslint-plugin-import": "^2.24.2", 23 | "husky": "^7.0.2", 24 | "jest": "^27.2.5", 25 | "jest-fetch-mock": "^3.0.3", 26 | "laravel-mix": "^6.0.31", 27 | "laravel-mix-copy-watched": "^2.3.1", 28 | "laravel-mix-purgecss": "^6.0.0", 29 | "mix-env-file": "^0.1.1", 30 | "npm-run-all": "^4.1.5", 31 | "postcss": "^8.3.9", 32 | "prettier": "^2.4.1", 33 | "purgecss-with-wordpress": "^4.0.3", 34 | "sass": "^1.42.1", 35 | "sass-loader": "^12.1.0", 36 | "stylelint": "^13.13.1", 37 | "stylelint-config-standard": "^22.0.0", 38 | "typescript": "^4.4.3" 39 | }, 40 | "browserslist": [ 41 | "extends @wordpress/browserslist-config" 42 | ], 43 | "jest": { 44 | "automock": false, 45 | "verbose": true, 46 | "testURL": "http://domain.tld/", 47 | "setupFiles": [ 48 | "/.tests/js/setupTests.js" 49 | ], 50 | "testPathIgnorePatterns": [ 51 | "/node_modules/" 52 | ], 53 | "transform": { 54 | "\\.[tj]sx?$": [ 55 | "babel-jest", 56 | { 57 | "presets": [ 58 | [ 59 | "babel-preset-env", 60 | { 61 | "targets": { 62 | "node": 10 63 | } 64 | } 65 | ] 66 | ] 67 | } 68 | ] 69 | } 70 | }, 71 | "scripts": { 72 | "cs": "run-s -c cs:*", 73 | "cs:js": "eslint assets/.src/js", 74 | "cs:scss": "stylelint \"assets/.src/**/*.scss\"", 75 | "cs:php": "composer cs", 76 | "build": "cross-env NODE_ENV=development npx mix --mix-config=.webpack.mix.js", 77 | "build:production": "cross-env NODE_ENV=production npx mix --production --mix-config=.webpack.mix.js", 78 | "start": "cross-env NODE_ENV=development npx mix --mix-config=.webpack.mix.js -- --watch", 79 | "unit": "jest", 80 | "postinstall": "npx husky install" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /plugin-name.php: -------------------------------------------------------------------------------- 1 | 35 |
36 |

37 | 7.2.5. Please update the PHP on your server and try again.', 'plugin_name' ), 40 | [ 41 | 'strong' => [], 42 | ] 43 | ); 44 | ?> 45 |

46 |
47 | 48 | make( Plugin::class ) )->run(); 88 | 89 | /** 90 | * You can use the $injector->make( PluginName\Some\Class::class ) for get any plugin class. 91 | * More detail: https://github.com/wppunk/WPPlugin#dependency-injection-container 92 | */ 93 | do_action( 'plugin_name_init', $injector ); 94 | } 95 | 96 | add_action( 'plugins_loaded', 'run_plugin_name' ); 97 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === Plugin Name === 2 | Contributors: {AUTHOR} 3 | Donate link: TODO: Fill ( https://your-donate.link ) 4 | Tags: TODO: Fill ( tag1, tag2, tag3 ) 5 | Requires at least: 5.5 6 | Tested up to: 5.5 7 | Stable tag: 1.0.0 8 | Requires PHP: 7.2.5 9 | License: MIT 10 | 11 | Plugin description in search plugin. 12 | 13 | == Description == 14 | 15 | Plugin description on plugin page. 16 | 17 | = Features = 18 | * Feature 1 19 | * Feature 2 20 | 21 | == Installation == 22 | 23 | 1. Upload `plugin-name` folder to the `/wp-content/plugins/` directory. 24 | 2. Activate the plugin through the 'Plugins' menu in WordPress. 25 | 26 | == Frequently Asked Questions == 27 | 28 | = FAQ Question 1 = 29 | 30 | FAQ Answer 1 31 | 32 | = FAQ Question 2 = 33 | 34 | FAQ Answer 2 35 | 36 | == Changelog == 37 | 38 | = 1.0.0 = 39 | * Initial release 40 | 41 | == Upgrade Notice == 42 | 43 | = 1.0.0 = 44 | * Initial release 45 | 46 | == Screenshots == 47 | 48 | 1. /assets/img/screenshot-1.png 49 | -------------------------------------------------------------------------------- /src/Admin/SettingsPage.php: -------------------------------------------------------------------------------- 1 | injector = $injector; 57 | } 58 | 59 | /** 60 | * Run plugin 61 | * 62 | * @since {VERSION} 63 | * 64 | * @throws Exception Object doesn't exist. 65 | */ 66 | public function run(): void { 67 | is_admin() 68 | ? $this->run_admin() 69 | : $this->run_front(); 70 | } 71 | 72 | /** 73 | * Run admin part 74 | * 75 | * @since {VERSION} 76 | * 77 | * @throws InjectionException If a cyclic gets detected when provisioning. 78 | */ 79 | private function run_admin(): void { 80 | $this->injector->make( SettingsPage::class )->hooks(); 81 | } 82 | 83 | /** 84 | * Run frontend part 85 | * 86 | * @since {VERSION} 87 | * 88 | * @throws InjectionException If a cyclic gets detected when provisioning. 89 | */ 90 | private function run_front(): void { 91 | $this->injector->make( Front::class )->hooks(); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /templates/admin/settings.php: -------------------------------------------------------------------------------- 1 | 17 | 18 |

19 | -------------------------------------------------------------------------------- /uninstall.php: -------------------------------------------------------------------------------- 1 |