├── .distignore ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc.json ├── assets ├── admin │ ├── css │ │ └── prefix-admin.css │ └── js │ │ └── prefix-admin.js └── public │ ├── css │ └── prefix-public.css │ └── js │ └── prefix-public.js ├── bin └── dist.sh ├── composer.json ├── composer.lock ├── includes ├── Bootstrap │ ├── AdminEnqueues.php │ ├── FrontendEnqueues.php │ ├── I18n.php │ ├── Loader.php │ ├── Main.php │ └── SetupCron.php ├── Controllers │ └── .gitkeep ├── Helpers │ └── Functions.php ├── Models │ └── .gitkeep ├── Notices │ ├── Admin.php │ ├── Loader.php │ ├── Notice.php │ ├── ReviewNotices.php │ └── UpsellsNotices.php ├── RootActivator.php ├── RootDeactivator.php ├── Traits │ └── PluginInfo.php └── Views │ └── .gitkeep ├── index.php ├── package-lock.json ├── package.json ├── phpcs.xml ├── plugin-boilerplate.php ├── readme.md ├── readme.txt └── uninstall.php /.distignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .parcel-cache 3 | .git 4 | .DS_Store 5 | .distignore 6 | .gitignore 7 | .husky 8 | .prettierignore 9 | .prettierrc.json 10 | .github 11 | .wordpress-org 12 | .idea 13 | composer.json 14 | composer.lock 15 | package.json 16 | package-lock.json 17 | node_modules 18 | artifact 19 | dist 20 | bin 21 | phpcs.xml 22 | logs 23 | assets/admin/js/*.js 24 | assets/public/js/*.js -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .parcel-cache 3 | .vscode 4 | .idea 5 | artifact 6 | dist 7 | logs 8 | node_modules 9 | vendor 10 | assets/admin/js/build/ 11 | assets/public/js/build/ -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run format 5 | composer run format -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | assets/admin/js/build/ 2 | assets/public/js/build/ 3 | assets/img/ 4 | *.php -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /assets/admin/css/prefix-admin.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UVLabs/wordpress-plugin-boilerplate/32251d5d207e4f2376834f1cbc27fe125f363b52/assets/admin/css/prefix-admin.css -------------------------------------------------------------------------------- /assets/admin/js/prefix-admin.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | "use strict"; 3 | 4 | /** 5 | * All of the code for your public-facing JavaScript source 6 | * should reside in this file. 7 | * 8 | * Note: It has been assumed you will write jQuery code here, so the 9 | * $ function reference has been prepared for usage within the scope 10 | * of this function. 11 | * 12 | * This enables you to define handlers, for when the DOM is ready: 13 | * 14 | * $(function() { 15 | * 16 | * }); 17 | * 18 | * When the window is loaded: 19 | * 20 | * $( window ).load(function() { 21 | * 22 | * }); 23 | * 24 | * ...and/or other possibilities. 25 | * 26 | * Ideally, it is not considered best practise to attach more than a 27 | * single DOM-ready or window-load handler for a particular page. 28 | * Although scripts in the WordPress core, Plugins and Themes may be 29 | * practising this, we should strive to set a better example in our own work. 30 | */ 31 | 32 | $(document).ready(function () {}); 33 | })(jQuery); 34 | -------------------------------------------------------------------------------- /assets/public/css/prefix-public.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UVLabs/wordpress-plugin-boilerplate/32251d5d207e4f2376834f1cbc27fe125f363b52/assets/public/css/prefix-public.css -------------------------------------------------------------------------------- /assets/public/js/prefix-public.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | "use strict"; 3 | 4 | /** 5 | * All of the code for your public-facing JavaScript source 6 | * should reside in this file. 7 | * 8 | * Note: It has been assumed you will write jQuery code here, so the 9 | * $ function reference has been prepared for usage within the scope 10 | * of this function. 11 | * 12 | * This enables you to define handlers, for when the DOM is ready: 13 | * 14 | * $(function() { 15 | * 16 | * }); 17 | * 18 | * When the window is loaded: 19 | * 20 | * $( window ).load(function() { 21 | * 22 | * }); 23 | * 24 | * ...and/or other possibilities. 25 | * 26 | * Ideally, it is not considered best practise to attach more than a 27 | * single DOM-ready or window-load handler for a particular page. 28 | * Although scripts in the WordPress core, Plugins and Themes may be 29 | * practising this, we should strive to set a better example in our own work. 30 | */ 31 | 32 | $(document).ready(function () {}); 33 | })(jQuery); 34 | -------------------------------------------------------------------------------- /bin/dist.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Prepare plugin for uploading to wp.org. 4 | 5 | # Start fresh 6 | rm -rf dist 7 | rm -rf artifact 8 | 9 | # Make our directories 10 | mkdir -p dist 11 | mkdir -p artifact 12 | 13 | # Remove vendor folder so we can redownload without dev dependencies. 14 | rm -rf vendor 15 | 16 | # Install without dev dependencies and optimize composer. 17 | composer install --no-dev -o 18 | composer dumpautoload -o 19 | 20 | # Run Prettier 21 | npm run format 22 | 23 | # Build our JS files with parcel 24 | npm run build 25 | 26 | # Sync dist folder 27 | rsync -acvP --delete --exclude-from=".distignore" ./ "./dist" 28 | 29 | #Change to our dist folder and zip to artifact folder 30 | (cd dist && zip -r ../artifact/prefix.zip .) 31 | 32 | # Delete dist folder 33 | rm -rf dist 34 | 35 | # Re-add dev dependencies 36 | composer install 37 | composer dumpautoload 38 | 39 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "lint" : "mkdir -p logs; vendor/bin/phpcs -s > ./logs/log.txt", 4 | "format": "vendor/bin/phpcbf -p", 5 | "dist": "sh bin/dist.sh" 6 | }, 7 | "require-dev": { 8 | "dealerdirect/phpcodesniffer-composer-installer": "0.7.1", 9 | "wp-coding-standards/wpcs": "2.3", 10 | "suin/phpcs-psr4-sniff": "^3.0" 11 | }, 12 | "autoload":{ 13 | "psr-4": { 14 | "Root\\" : "includes/" 15 | } 16 | }, 17 | "config": { 18 | "allow-plugins": { 19 | "dealerdirect/phpcodesniffer-composer-installer": true 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "8cbff63dc670f52b3505139ed181a4ab", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "dealerdirect/phpcodesniffer-composer-installer", 12 | "version": "v0.7.1", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", 16 | "reference": "fe390591e0241955f22eb9ba327d137e501c771c" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/fe390591e0241955f22eb9ba327d137e501c771c", 21 | "reference": "fe390591e0241955f22eb9ba327d137e501c771c", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "composer-plugin-api": "^1.0 || ^2.0", 26 | "php": ">=5.3", 27 | "squizlabs/php_codesniffer": "^2.0 || ^3.0 || ^4.0" 28 | }, 29 | "require-dev": { 30 | "composer/composer": "*", 31 | "phpcompatibility/php-compatibility": "^9.0", 32 | "sensiolabs/security-checker": "^4.1.0" 33 | }, 34 | "type": "composer-plugin", 35 | "extra": { 36 | "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" 41 | } 42 | }, 43 | "notification-url": "https://packagist.org/downloads/", 44 | "license": [ 45 | "MIT" 46 | ], 47 | "authors": [ 48 | { 49 | "name": "Franck Nijhof", 50 | "email": "franck.nijhof@dealerdirect.com", 51 | "homepage": "http://www.frenck.nl", 52 | "role": "Developer / IT Manager" 53 | } 54 | ], 55 | "description": "PHP_CodeSniffer Standards Composer Installer Plugin", 56 | "homepage": "http://www.dealerdirect.com", 57 | "keywords": [ 58 | "PHPCodeSniffer", 59 | "PHP_CodeSniffer", 60 | "code quality", 61 | "codesniffer", 62 | "composer", 63 | "installer", 64 | "phpcs", 65 | "plugin", 66 | "qa", 67 | "quality", 68 | "standard", 69 | "standards", 70 | "style guide", 71 | "stylecheck", 72 | "tests" 73 | ], 74 | "support": { 75 | "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", 76 | "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" 77 | }, 78 | "time": "2020-12-07T18:04:37+00:00" 79 | }, 80 | { 81 | "name": "phpstan/phpdoc-parser", 82 | "version": "1.4.5", 83 | "source": { 84 | "type": "git", 85 | "url": "https://github.com/phpstan/phpdoc-parser.git", 86 | "reference": "129a63b3bc7caeb593c224c41f420675e63cfefc" 87 | }, 88 | "dist": { 89 | "type": "zip", 90 | "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/129a63b3bc7caeb593c224c41f420675e63cfefc", 91 | "reference": "129a63b3bc7caeb593c224c41f420675e63cfefc", 92 | "shasum": "" 93 | }, 94 | "require": { 95 | "php": "^7.2 || ^8.0" 96 | }, 97 | "require-dev": { 98 | "php-parallel-lint/php-parallel-lint": "^1.2", 99 | "phpstan/extension-installer": "^1.0", 100 | "phpstan/phpstan": "^1.5", 101 | "phpstan/phpstan-strict-rules": "^1.0", 102 | "phpunit/phpunit": "^9.5", 103 | "symfony/process": "^5.2" 104 | }, 105 | "type": "library", 106 | "autoload": { 107 | "psr-4": { 108 | "PHPStan\\PhpDocParser\\": [ 109 | "src/" 110 | ] 111 | } 112 | }, 113 | "notification-url": "https://packagist.org/downloads/", 114 | "license": [ 115 | "MIT" 116 | ], 117 | "description": "PHPDoc parser with support for nullable, intersection and generic types", 118 | "support": { 119 | "issues": "https://github.com/phpstan/phpdoc-parser/issues", 120 | "source": "https://github.com/phpstan/phpdoc-parser/tree/1.4.5" 121 | }, 122 | "time": "2022-04-22T11:11:01+00:00" 123 | }, 124 | { 125 | "name": "slevomat/coding-standard", 126 | "version": "7.1", 127 | "source": { 128 | "type": "git", 129 | "url": "https://github.com/slevomat/coding-standard.git", 130 | "reference": "b521bd358b5f7a7d69e9637fd139e036d8adeb6f" 131 | }, 132 | "dist": { 133 | "type": "zip", 134 | "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b521bd358b5f7a7d69e9637fd139e036d8adeb6f", 135 | "reference": "b521bd358b5f7a7d69e9637fd139e036d8adeb6f", 136 | "shasum": "" 137 | }, 138 | "require": { 139 | "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", 140 | "php": "^7.2 || ^8.0", 141 | "phpstan/phpdoc-parser": "^1.4.1", 142 | "squizlabs/php_codesniffer": "^3.6.2" 143 | }, 144 | "require-dev": { 145 | "phing/phing": "2.17.2", 146 | "php-parallel-lint/php-parallel-lint": "1.3.2", 147 | "phpstan/phpstan": "1.4.10|1.5.2", 148 | "phpstan/phpstan-deprecation-rules": "1.0.0", 149 | "phpstan/phpstan-phpunit": "1.0.0|1.1.0", 150 | "phpstan/phpstan-strict-rules": "1.1.0", 151 | "phpunit/phpunit": "7.5.20|8.5.21|9.5.19" 152 | }, 153 | "type": "phpcodesniffer-standard", 154 | "extra": { 155 | "branch-alias": { 156 | "dev-master": "7.x-dev" 157 | } 158 | }, 159 | "autoload": { 160 | "psr-4": { 161 | "SlevomatCodingStandard\\": "SlevomatCodingStandard" 162 | } 163 | }, 164 | "notification-url": "https://packagist.org/downloads/", 165 | "license": [ 166 | "MIT" 167 | ], 168 | "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", 169 | "support": { 170 | "issues": "https://github.com/slevomat/coding-standard/issues", 171 | "source": "https://github.com/slevomat/coding-standard/tree/7.1" 172 | }, 173 | "funding": [ 174 | { 175 | "url": "https://github.com/kukulich", 176 | "type": "github" 177 | }, 178 | { 179 | "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", 180 | "type": "tidelift" 181 | } 182 | ], 183 | "time": "2022-03-29T12:44:16+00:00" 184 | }, 185 | { 186 | "name": "squizlabs/php_codesniffer", 187 | "version": "3.6.2", 188 | "source": { 189 | "type": "git", 190 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", 191 | "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" 192 | }, 193 | "dist": { 194 | "type": "zip", 195 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", 196 | "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", 197 | "shasum": "" 198 | }, 199 | "require": { 200 | "ext-simplexml": "*", 201 | "ext-tokenizer": "*", 202 | "ext-xmlwriter": "*", 203 | "php": ">=5.4.0" 204 | }, 205 | "require-dev": { 206 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" 207 | }, 208 | "bin": [ 209 | "bin/phpcs", 210 | "bin/phpcbf" 211 | ], 212 | "type": "library", 213 | "extra": { 214 | "branch-alias": { 215 | "dev-master": "3.x-dev" 216 | } 217 | }, 218 | "notification-url": "https://packagist.org/downloads/", 219 | "license": [ 220 | "BSD-3-Clause" 221 | ], 222 | "authors": [ 223 | { 224 | "name": "Greg Sherwood", 225 | "role": "lead" 226 | } 227 | ], 228 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 229 | "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", 230 | "keywords": [ 231 | "phpcs", 232 | "standards" 233 | ], 234 | "support": { 235 | "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", 236 | "source": "https://github.com/squizlabs/PHP_CodeSniffer", 237 | "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" 238 | }, 239 | "time": "2021-12-12T21:44:58+00:00" 240 | }, 241 | { 242 | "name": "suin/phpcs-psr4-sniff", 243 | "version": "v3.0.0", 244 | "source": { 245 | "type": "git", 246 | "url": "https://github.com/suin/phpcs-psr4-sniff.git", 247 | "reference": "b000ca1e3d04c9876b39c2e56859760b93dfc84d" 248 | }, 249 | "dist": { 250 | "type": "zip", 251 | "url": "https://api.github.com/repos/suin/phpcs-psr4-sniff/zipball/b000ca1e3d04c9876b39c2e56859760b93dfc84d", 252 | "reference": "b000ca1e3d04c9876b39c2e56859760b93dfc84d", 253 | "shasum": "" 254 | }, 255 | "require": { 256 | "ext-json": "*", 257 | "php": ">=7.1", 258 | "slevomat/coding-standard": ">=4.7 <8.0.0", 259 | "squizlabs/php_codesniffer": ">=3.3 <4.0.0" 260 | }, 261 | "type": "phpcodesniffer-standard", 262 | "autoload": { 263 | "psr-0": { 264 | "Suin\\Sniffs\\Classes\\": "src" 265 | } 266 | }, 267 | "notification-url": "https://packagist.org/downloads/", 268 | "license": [ 269 | "MIT" 270 | ], 271 | "authors": [ 272 | { 273 | "name": "suin", 274 | "email": "suinyeze@gmail.com", 275 | "homepage": "https://github.com/suin", 276 | "role": "Developer" 277 | } 278 | ], 279 | "description": "PHP_CodeSniffer sniff that checks class name matches PSR-4 project structure.", 280 | "homepage": "https://github.com/suin/php", 281 | "keywords": [ 282 | "PSR-4", 283 | "coding-standards", 284 | "coding-style", 285 | "namespace", 286 | "php-codesniffer", 287 | "phpcs", 288 | "static-analysis" 289 | ], 290 | "support": { 291 | "issues": "https://github.com/suin/php/issues", 292 | "source": "https://github.com/suin/phpcs-psr4-sniff/tree/v3.0.0" 293 | }, 294 | "time": "2021-06-02T06:16:24+00:00" 295 | }, 296 | { 297 | "name": "wp-coding-standards/wpcs", 298 | "version": "2.3.0", 299 | "source": { 300 | "type": "git", 301 | "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", 302 | "reference": "7da1894633f168fe244afc6de00d141f27517b62" 303 | }, 304 | "dist": { 305 | "type": "zip", 306 | "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62", 307 | "reference": "7da1894633f168fe244afc6de00d141f27517b62", 308 | "shasum": "" 309 | }, 310 | "require": { 311 | "php": ">=5.4", 312 | "squizlabs/php_codesniffer": "^3.3.1" 313 | }, 314 | "require-dev": { 315 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", 316 | "phpcompatibility/php-compatibility": "^9.0", 317 | "phpcsstandards/phpcsdevtools": "^1.0", 318 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" 319 | }, 320 | "suggest": { 321 | "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." 322 | }, 323 | "type": "phpcodesniffer-standard", 324 | "notification-url": "https://packagist.org/downloads/", 325 | "license": [ 326 | "MIT" 327 | ], 328 | "authors": [ 329 | { 330 | "name": "Contributors", 331 | "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" 332 | } 333 | ], 334 | "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", 335 | "keywords": [ 336 | "phpcs", 337 | "standards", 338 | "wordpress" 339 | ], 340 | "support": { 341 | "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", 342 | "source": "https://github.com/WordPress/WordPress-Coding-Standards", 343 | "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" 344 | }, 345 | "time": "2020-05-13T23:57:56+00:00" 346 | } 347 | ], 348 | "aliases": [], 349 | "minimum-stability": "stable", 350 | "stability-flags": [], 351 | "prefer-stable": false, 352 | "prefer-lowest": false, 353 | "platform": [], 354 | "platform-dev": [], 355 | "plugin-api-version": "2.1.0" 356 | } 357 | -------------------------------------------------------------------------------- /includes/Bootstrap/AdminEnqueues.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | 12 | namespace Root\Bootstrap; 13 | 14 | if ( ! defined( 'ABSPATH' ) ) { 15 | exit; 16 | } 17 | 18 | use Root\Helpers\Functions; 19 | 20 | /** 21 | * Class responsible for methods to do with admin enqueing of JS and CSS. 22 | * 23 | * @package Root\Bootstrap 24 | * @since 1.0.0 25 | */ 26 | class AdminEnqueues { 27 | 28 | /** 29 | * The ID of this plugin. 30 | * 31 | * @since 1.0.0 32 | * @access private 33 | * @var string $plugin_name The ID of this plugin. 34 | */ 35 | private $plugin_name; 36 | 37 | /** 38 | * The version of this plugin. 39 | * 40 | * @since 1.0.0 41 | * @access private 42 | * @var string $version The current version of this plugin. 43 | */ 44 | private $version; 45 | 46 | /** 47 | * Burst cache if on Local dev environment. 48 | * 49 | * @var int 50 | * @since 1.0.0 51 | */ 52 | private $maybe_burst_cache; 53 | 54 | /** 55 | * Initialize the class and set its properties. 56 | * 57 | * @since 1.0.0 58 | */ 59 | public function __construct() { 60 | $this->plugin_name = PREFIX_PLUGIN_NAME; 61 | $this->version = PREFIX_VERSION; 62 | $this->maybe_burst_cache = ( defined( 'PREFIX_DEBUG' ) && PREFIX_DEBUG ) ? time() : ''; 63 | } 64 | 65 | /** 66 | * Register the stylesheets for the admin area. 67 | * 68 | * @since 1.0.0 69 | */ 70 | public function enqueueStyles() { 71 | wp_enqueue_style( $this->plugin_name, PREFIX_PLUGIN_ASSETS_PATH_URL . 'admin/css/prefix-admin.css', array(), $this->version . $this->maybe_burst_cache, 'all' ); 72 | } 73 | 74 | /** 75 | * Register the JavaScript for the admin area. 76 | * 77 | * @since 1.0.0 78 | */ 79 | public function enqueueScripts() { 80 | $path = ! ( PREFIX_DEBUG ) ? 'build/' : ''; 81 | wp_enqueue_script( $this->plugin_name, PREFIX_PLUGIN_ASSETS_PATH_URL . 'admin/js/' . $path . 'prefix-admin.js', array( 'jquery' ), $this->version . $this->maybe_burst_cache, false ); 82 | } 83 | 84 | /** 85 | * Turn a script into a module so that we can make use of JS components. 86 | * 87 | * @param string $tag 88 | * @param string $handle 89 | * @param string $src 90 | * @return string 91 | * @since 1.0.0 92 | */ 93 | public function getScriptsAsModules( string $tag, string $handle, string $src ) { 94 | 95 | if ( PREFIX_DEBUG === false ) { // Live scripts are built in Parcel so no need to make them modules. 96 | return $tag; 97 | } 98 | 99 | $modules_handlers = array( 100 | $this->plugin_name, // Name of default js handler 101 | // $this->plugin_name . '-my-other-script', // You can add other script handlers. 102 | ); 103 | 104 | if ( ! in_array( $handle, $modules_handlers, true ) ) { 105 | return $tag; 106 | } 107 | 108 | return Functions::makeScriptsModules( $tag, $handle, $src ); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /includes/Bootstrap/FrontendEnqueues.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | namespace Root\Bootstrap; 21 | 22 | if ( ! defined( 'ABSPATH' ) ) { 23 | exit; 24 | } 25 | 26 | use Root\Helpers\Functions; 27 | 28 | /** 29 | * Class responsible for methods to do with frontend enqueing of JS and CSS. 30 | * 31 | * @package Root\Bootstrap 32 | * @since 1.0.0 33 | */ 34 | class FrontendEnqueues { 35 | 36 | /** 37 | * The ID of this plugin. 38 | * 39 | * @since 1.0.0 40 | * @access private 41 | * @var string $plugin_name The ID of this plugin. 42 | */ 43 | private $plugin_name; 44 | 45 | /** 46 | * The version of this plugin. 47 | * 48 | * @since 1.0.0 49 | * @access private 50 | * @var string $version The current version of this plugin. 51 | */ 52 | private $version; 53 | 54 | /** 55 | * Burst cache if on Local dev environment. 56 | * 57 | * @var int 58 | * @since 1.0.0 59 | */ 60 | private $maybe_burst_cache; 61 | 62 | /** 63 | * Initialize the class and set its properties. 64 | * 65 | * @since 1.0.0 66 | */ 67 | public function __construct() { 68 | $this->plugin_name = PREFIX_PLUGIN_NAME; 69 | $this->version = PREFIX_VERSION; 70 | $this->maybe_burst_cache = ( defined( 'PREFIX_DEBUG' ) && PREFIX_DEBUG ) ? time() : ''; 71 | } 72 | 73 | /** 74 | * Register the stylesheets for the public-facing side of the site. 75 | * 76 | * @since 1.0.0 77 | */ 78 | public function enqueueStyles() { 79 | wp_enqueue_style( $this->plugin_name, PREFIX_PLUGIN_ASSETS_PATH_URL . 'public/css/prefix-public.css', array(), $this->version . $this->maybe_burst_cache, 'all' ); 80 | } 81 | 82 | /** 83 | * Register the JavaScript for the public-facing side of the site. 84 | * 85 | * @since 1.0.0 86 | */ 87 | public function enqueueScripts() { 88 | $path = ! ( PREFIX_DEBUG ) ? 'build/' : ''; 89 | wp_enqueue_script( $this->plugin_name, PREFIX_PLUGIN_ASSETS_PATH_URL . 'public/js/' . $path . 'prefix-public.js', array( 'jquery' ), $this->version . $this->maybe_burst_cache, false ); 90 | } 91 | 92 | /** 93 | * Turn a script into a module so that we can make use of JS components. 94 | * 95 | * @param string $tag 96 | * @param string $handle 97 | * @param string $src 98 | * @return string 99 | * @since 1.0.0 100 | */ 101 | public function getScriptsAsModules( string $tag, string $handle, string $src ) { 102 | 103 | if ( PREFIX_DEBUG === false ) { // Live scripts are built in Parcel so no need to make them modules. 104 | return $tag; 105 | } 106 | 107 | $modules_handlers = array( 108 | $this->plugin_name, 109 | // $this->plugin_name . '-my-other-script', // You can add other script handlers. 110 | ); 111 | 112 | if ( ! in_array( $handle, $modules_handlers, true ) ) { 113 | return $tag; 114 | } 115 | 116 | return Functions::makeScriptsModules( $tag, $handle, $src ); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /includes/Bootstrap/I18n.php: -------------------------------------------------------------------------------- 1 | 23 | */ 24 | namespace Root\Bootstrap; 25 | 26 | if ( ! defined( 'ABSPATH' ) ) { 27 | exit; 28 | } 29 | 30 | /** 31 | * Class responsible for setting up text domain. 32 | * 33 | * @package Root\Bootstrap 34 | */ 35 | class I18n { 36 | 37 | /** 38 | * Load the plugin text domain for translation. 39 | * 40 | * @since 1.0.0 41 | */ 42 | public function loadPluginTextdomain() { 43 | 44 | load_plugin_textdomain( 45 | 'text-domain', 46 | false, 47 | dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/' 48 | ); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /includes/Bootstrap/Loader.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | class Loader { 28 | 29 | /** 30 | * The array of actions registered with WordPress. 31 | * 32 | * @since 1.0.0 33 | * @access protected 34 | * @var array $actions The actions registered with WordPress to fire when the plugin loads. 35 | */ 36 | protected $actions; 37 | 38 | /** 39 | * The array of filters registered with WordPress. 40 | * 41 | * @since 1.0.0 42 | * @access protected 43 | * @var array $filters The filters registered with WordPress to fire when the plugin loads. 44 | */ 45 | protected $filters; 46 | 47 | /** 48 | * Initialize the collections used to maintain the actions and filters. 49 | * 50 | * @since 1.0.0 51 | */ 52 | public function __construct() { 53 | $this->actions = array(); 54 | $this->filters = array(); 55 | } 56 | 57 | /** 58 | * Add a new action to the collection to be registered with WordPress. 59 | * 60 | * @since 1.0.0 61 | * @param string $hook The name of the WordPress action that is being registered. 62 | * @param object $component A reference to the instance of the object on which the action is defined. 63 | * @param string $callback The name of the function definition on the $component. 64 | * @param int $priority Optional. The priority at which the function should be fired. Default is 10. 65 | * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1. 66 | */ 67 | public function add_action( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) { 68 | $this->actions = $this->add( $this->actions, $hook, $component, $callback, $priority, $accepted_args ); 69 | } 70 | 71 | /** 72 | * Add a new filter to the collection to be registered with WordPress. 73 | * 74 | * @since 1.0.0 75 | * @param string $hook The name of the WordPress filter that is being registered. 76 | * @param object $component A reference to the instance of the object on which the filter is defined. 77 | * @param string $callback The name of the function definition on the $component. 78 | * @param int $priority Optional. The priority at which the function should be fired. Default is 10. 79 | * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1. 80 | */ 81 | public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) { 82 | $this->filters = $this->add( $this->filters, $hook, $component, $callback, $priority, $accepted_args ); 83 | } 84 | 85 | /** 86 | * A utility function that is used to register the actions and hooks into a single 87 | * collection. 88 | * 89 | * @since 1.0.0 90 | * @access private 91 | * @param array $hooks The collection of hooks that is being registered (that is, actions or filters). 92 | * @param string $hook The name of the WordPress filter that is being registered. 93 | * @param object $component A reference to the instance of the object on which the filter is defined. 94 | * @param string $callback The name of the function definition on the $component. 95 | * @param int $priority The priority at which the function should be fired. 96 | * @param int $accepted_args The number of arguments that should be passed to the $callback. 97 | * @return array The collection of actions and filters registered with WordPress. 98 | */ 99 | private function add( $hooks, $hook, $component, $callback, $priority, $accepted_args ) { 100 | 101 | $hooks[] = array( 102 | 'hook' => $hook, 103 | 'component' => $component, 104 | 'callback' => $callback, 105 | 'priority' => $priority, 106 | 'accepted_args' => $accepted_args, 107 | ); 108 | 109 | return $hooks; 110 | } 111 | 112 | /** 113 | * Register the filters and actions with WordPress. 114 | * 115 | * @since 1.0.0 116 | */ 117 | public function run() { 118 | 119 | foreach ( $this->filters as $hook ) { 120 | add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); 121 | } 122 | 123 | foreach ( $this->actions as $hook ) { 124 | add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] ); 125 | } 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /includes/Bootstrap/Main.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | 28 | namespace Root\Bootstrap; 29 | 30 | if ( ! defined( 'ABSPATH' ) ) { 31 | exit; 32 | } 33 | 34 | /* 35 | use Root\Notices\Loader as NoticesLoader; 36 | use Root\Notices\Notice; 37 | */ 38 | 39 | /** 40 | * Class Main. 41 | * 42 | * Class responsible for firing public and admin hooks. 43 | */ 44 | class Main { 45 | 46 | /** 47 | * The loader that's responsible for maintaining and registering all hooks that power 48 | * the plugin. 49 | * 50 | * @since 1.0.0 51 | * @access protected 52 | * @var Loader $loader Maintains and registers all hooks for the plugin. 53 | */ 54 | protected $loader; 55 | 56 | /** 57 | * The unique identifier of this plugin. 58 | * 59 | * @since 1.0.0 60 | * @access protected 61 | * @var string $plugin_name The string used to uniquely identify this plugin. 62 | */ 63 | protected $plugin_name; 64 | 65 | /** 66 | * The current version of the plugin. 67 | * 68 | * @since 1.0.0 69 | * @access protected 70 | * @var string $version The current version of the plugin. 71 | */ 72 | protected $version; 73 | 74 | /** 75 | * Plugin instance 76 | * 77 | * @var mixed 78 | */ 79 | private static $instance; 80 | 81 | /** 82 | * Gets an instance of our plugin. 83 | * 84 | * @return Main() 85 | */ 86 | public static function getInstance() { 87 | if ( self::$instance === null ) { 88 | self::$instance = new self(); 89 | } 90 | 91 | return self::$instance; 92 | } 93 | 94 | /** 95 | * Define the core functionality of the plugin. 96 | * 97 | * Set the plugin name and the plugin version that can be used throughout the plugin. 98 | * Load the dependencies, define the locale, and set the hooks for the admin area and 99 | * the public-facing side of the site. 100 | * 101 | * @since 1.0.0 102 | */ 103 | private function __construct() { 104 | $this->version = PREFIX_VERSION; 105 | 106 | $this->plugin_name = PREFIX_PLUGIN_NAME; 107 | 108 | $this->loadDependencies(); 109 | $this->setLocale(); 110 | $this->defineAdminHooks(); 111 | $this->definePublicHooks(); 112 | } 113 | 114 | /** 115 | * Load the required dependencies for this plugin. 116 | * 117 | * Create an instance of the loader which will be used to register the hooks 118 | * with WordPress. 119 | * 120 | * @since 1.0.0 121 | * @access private 122 | */ 123 | private function loadDependencies() { 124 | $this->loader = new Loader(); 125 | } 126 | 127 | /** 128 | * Define the locale for this plugin for internationalization. 129 | * 130 | * Uses the i18n class in order to set the domain and to register the hook 131 | * with WordPress. 132 | * 133 | * @since 1.0.0 134 | * @access private 135 | */ 136 | private function setLocale() { 137 | $plugin_i18n = new I18n(); 138 | $this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'loadPluginTextdomain' ); 139 | } 140 | 141 | /** 142 | * Register all of the hooks related to the admin area functionality 143 | * of the plugin. 144 | * 145 | * @since 1.0.0 146 | * @access private 147 | */ 148 | private function defineAdminHooks() { 149 | 150 | if ( ! is_admin() && ! wp_doing_cron() ) { 151 | return; // Bail if not admin request and not doing cron. 152 | } 153 | 154 | $plugin_admin = new AdminEnqueues(); 155 | $bootstrap_cron_setup = new SetupCron(); 156 | /* 157 | // (uncomment if making use of notice class). 158 | $notice = new Notice(); 159 | $notices_loader = new NoticesLoader(); 160 | */ 161 | 162 | $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueueStyles' ); 163 | $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueueScripts' ); 164 | 165 | $this->loader->add_filter( 'plugin_action_links', $this, 'addPluginActionLinks', PHP_INT_MAX, 2 ); 166 | 167 | // Cron tasks. 168 | $this->loader->add_action( 'admin_init', $bootstrap_cron_setup, 'setCronTasks' ); 169 | 170 | /** 171 | * Make scripts modules 172 | * See the getScriptsAsModules() method for how this works. 173 | */ 174 | $this->loader->add_filter( 'script_loader_tag', $plugin_admin, 'getScriptsAsModules', 10, 3 ); 175 | 176 | /* 177 | // Notices Loader (uncomment if making use of notice class). 178 | $this->loader->add_action( 'admin_notices', $notices_loader, 'loadNotices' ); 179 | 180 | // Notices Ajax dismiss method (uncomment if making use of notice class). 181 | $this->loader->add_action( 'wp_ajax_prefix_dismissNotice', $notice, 'dismissNotice' ); 182 | */ 183 | } 184 | 185 | /** 186 | * Register all of the hooks related to the public-facing functionality 187 | * of the plugin. 188 | * 189 | * @since 1.0.0 190 | * @access private 191 | */ 192 | private function definePublicHooks() { 193 | 194 | if ( is_admin() && ! wp_doing_ajax() ) { 195 | return; // Bail if is admin request and not doing ajax. 196 | } 197 | 198 | $plugin_public = new FrontendEnqueues(); 199 | 200 | $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueueStyles' ); 201 | $this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueueScripts' ); 202 | 203 | /** 204 | * Make scripts modules 205 | */ 206 | $this->loader->add_filter( 'script_loader_tag', $plugin_public, 'getScriptsAsModules', 10, 3 ); 207 | } 208 | 209 | /** 210 | * Run the loader to execute all of the hooks with WordPress. 211 | * 212 | * @since 1.0.0 213 | */ 214 | public function run() { 215 | $this->loader->run(); 216 | } 217 | 218 | /** 219 | * The name of the plugin used to uniquely identify it within the context of 220 | * WordPress and to define internationalization functionality. 221 | * 222 | * @since 1.0.0 223 | * @return string The name of the plugin. 224 | */ 225 | public function getPluginName() { 226 | return $this->plugin_name; 227 | } 228 | 229 | /** 230 | * The reference to the class that orchestrates the hooks with the plugin. 231 | * 232 | * @since 1.0.0 233 | * @return Loader Orchestrates the hooks of the plugin. 234 | */ 235 | public function getLoader() { 236 | return $this->loader; 237 | } 238 | 239 | /** 240 | * Retrieve the version number of the plugin. 241 | * 242 | * @since 1.0.0 243 | * @return string The version number of the plugin. 244 | */ 245 | public function getVersion() { 246 | return $this->version; 247 | } 248 | 249 | /** 250 | * Add action Links for plugin 251 | * 252 | * @param array $plugin_actions Current plugin actions. 253 | * @param string $plugin_file Plugin file name. 254 | * @return array 255 | */ 256 | public function addPluginActionLinks( $plugin_actions, $plugin_file ) { 257 | return $plugin_actions; 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /includes/Bootstrap/SetupCron.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | 12 | namespace Root\Helpers; 13 | 14 | if ( ! defined( 'ABSPATH' ) ) { 15 | exit; 16 | } 17 | 18 | /** 19 | * Class responsible for creating helper static methods. 20 | * 21 | * @package Root\Helpers 22 | * @since 1.0.0 23 | */ 24 | class Functions { 25 | 26 | /** 27 | * Turn a script into a module so that we can make use of JS components. 28 | * 29 | * @param string $tag 30 | * @param string $handle 31 | * @param string $src 32 | * @return string 33 | * @since 1.0.0 34 | */ 35 | public static function makeScriptsModules( string $tag, string $handle, string $src ) { 36 | 37 | $id = $handle . '-js'; 38 | $parts = explode( '', $tag ); // Break up our string 39 | 40 | foreach ( $parts as $key => $part ) { 41 | if ( strpos( $part, $src ) !== false ) { // Make sure we're only altering the tag for our module script. 42 | $parts[ $key ] = '', $parts ); // Bring everything back together 47 | 48 | return $tags; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /includes/Models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UVLabs/wordpress-plugin-boilerplate/32251d5d207e4f2376834f1cbc27fe125f363b52/includes/Models/.gitkeep -------------------------------------------------------------------------------- /includes/Notices/Admin.php: -------------------------------------------------------------------------------- 1 | 42 | 43 |
44 | HTML element 2: Opening HTML element 3: Closing HTML element 4: Closing

HTML element */ 46 | echo sprintf( esc_html__( '%1$s%2$s my_plugin_name NOTICE:%3$s HTTPS not detected on this website. The plugin will not work. Please enable HTTPS on this website.%4$s', 'text-domain' ), '

', '', '', '

' ); 47 | ?> 48 |
49 | getUserID(), 'prefix_dismissed_notices', true ); 39 | } 40 | 41 | /** 42 | * Create the dismiss URL for a notice. 43 | * 44 | * @param string $notice_id The ID of the particular notice. 45 | * @return string 46 | */ 47 | protected function createDismissUrl( string $notice_id ) { 48 | 49 | if ( ! function_exists( 'wp_create_nonce' ) ) { 50 | require_once ABSPATH . 'wp-includes/pluggable.php'; 51 | } 52 | $nonce = wp_create_nonce( 'prefix_notice_nonce_value' ); 53 | 54 | return admin_url( 'admin-ajax.php?action=prefix_dismissNotice&prefix_notice_id=' . $notice_id . '&prefix_notice_nonce=' . $nonce ); 55 | } 56 | 57 | /** 58 | * Create the markup for a notice 59 | * 60 | * @param string $notice_id The ID of the particular notice. 61 | * @param array $content The content to add to the notice. 62 | * @return string 63 | */ 64 | protected function createNoticeMarkup( string $notice_id, array $content ) { 65 | 66 | // Only show the Notice to Admins. 67 | if ( ! current_user_can( 'manage_options' ) ) { 68 | return; 69 | } 70 | 71 | $dismissed_notices = $this->getDismissedNotices(); 72 | 73 | // Bail if this notice has been dismissed. 74 | if ( is_array( $dismissed_notices ) && in_array( $notice_id, $dismissed_notices, true ) ) { 75 | return; 76 | } 77 | 78 | $title = $content['title'] ?? ''; 79 | $body = $content['body'] ?? ''; 80 | $cta_text = $content['cta'] ?? __( 'Learn more', 'text-domain' ); 81 | $learn_more_link = $content['link'] ?? ''; 82 | 83 | $dismiss_url = $this->createDismissUrl( $notice_id ); 84 | $dismiss_text = __( 'Dismiss', 'text-domain' ); 85 | ?> 86 | 87 |
88 | 89 |

90 |

91 |
    92 | 93 |
  • 94 | 95 |
  • 96 |
97 |
98 | 99 | getNoticeID(); 138 | 139 | if ( empty( $notice_id ) ) { 140 | return; 141 | } 142 | 143 | $dismissed_notices = $this->getDismissedNotices(); 144 | 145 | if ( empty( $dismissed_notices ) ) { 146 | $dismissed_notices = array(); 147 | } 148 | 149 | // Add our new notice ID to the currently dismissed ones. 150 | array_push( $dismissed_notices, $notice_id ); 151 | 152 | $dismissed_notices = array_unique( $dismissed_notices ); 153 | 154 | update_user_meta( $this->getUserID(), 'prefix_dismissed_notices', $dismissed_notices ); 155 | 156 | wp_safe_redirect( sanitize_text_field( wp_unslash( $_SERVER['HTTP_REFERER'] ?? get_admin_url() ) ) ); 157 | exit; 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /includes/Notices/ReviewNotices.php: -------------------------------------------------------------------------------- 1 | createReviewPluginNotice(); 37 | } 38 | 39 | /** 40 | * Create leave review for plugin notice. 41 | * 42 | * @return void 43 | */ 44 | public function createReviewPluginNotice() { 45 | 46 | $days_since_installed = $this->getDaysSinceInstalled(); 47 | 48 | // Show notice after 3 weeks. 49 | if ( $days_since_installed < 21 ) { 50 | return; 51 | } 52 | 53 | $content = array( 54 | 'title' => __( 'Has my_plugin_name Helped You?', 'text-domain' ), 55 | 'body' => __( 'Hey! its plugin_author_name, Sole Developer working on my_plugin_name. Has the plugin benefitted your website? If yes, then would you mind taking a few seconds to leave a kind review? Reviews go a long way and they really help keep me motivated to continue working on the plugin and making it better.', 'text-domain' ), 56 | 'cta' => __( 'Sure!', 'text-domain' ), 57 | 'link' => 'https://wordpress.org/support/plugin/text-domain/reviews/#new-post', 58 | ); 59 | 60 | $this->createNoticeMarkup( 'leave_review_notice_1', $content ); 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /includes/Notices/UpsellsNotices.php: -------------------------------------------------------------------------------- 1 | getDaysSinceInstalled(); 44 | 45 | // Show notice after 4 days. 46 | if ( $days_since_installed < 3 ) { 47 | return; 48 | } 49 | 50 | $content = array( 51 | 'title' => __( 'Try out the PRO version.', 'text-domain' ), 52 | 'body' => __( 'Replace me with content.', 'text-domain' ), 53 | 'link' => '', 54 | ); 55 | 56 | $this->createNoticeMarkup( 'initial_pro_launch_notice', $content ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /includes/RootActivator.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | class RootActivator { 27 | 28 | /** 29 | * Method fired on plugin activation. 30 | * 31 | * @since 1.0.0 32 | */ 33 | public static function activate() { 34 | self::prefix_add_default_settings(); 35 | } 36 | 37 | /** 38 | * Add our default settings to the site DB. 39 | * 40 | * @return void 41 | */ 42 | private static function prefix_add_default_settings() { 43 | 44 | $installed_at = get_option( 'prefix_installed_at_version' ); 45 | $install_date = get_option( 'prefix_first_install_date' ); 46 | 47 | // Create date timestamp when plugin was first installed. 48 | if ( empty( $install_date ) ) { 49 | add_option( 'prefix_first_install_date', time(), '', 'yes' ); 50 | } 51 | 52 | // Create entry for plugin first install version. 53 | if ( empty( $installed_at ) ) { 54 | add_option( 'prefix_installed_at_version', PREFIX_VERSION, '', false ); 55 | } 56 | 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /includes/RootDeactivator.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | class RootDeactivator { 27 | 28 | /** 29 | * Method fired on plugin deactivation. 30 | * 31 | * @since 1.0.0 32 | */ 33 | public static function deactivate() { 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /includes/Traits/PluginInfo.php: -------------------------------------------------------------------------------- 1 | diff( $today ); 48 | $days_since_installed = $date_difference->format( '%a' ); 49 | return (int) $days_since_installed; 50 | } 51 | 52 | /** 53 | * Get the version PREFIX was installed at. 54 | * 55 | * @return mixed 56 | */ 57 | private function getInstalledAtVersion() { 58 | return get_option( 'prefix_installed_at_version' ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /includes/Views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UVLabs/wordpress-plugin-boilerplate/32251d5d207e4f2376834f1cbc27fe125f363b52/includes/Views/.gitkeep -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 0.5%, last 2 versions, not dead", 34 | "outputFormat": "global", 35 | "repository": { 36 | "type": "git", 37 | "url": "" 38 | }, 39 | "author": "plugin_author_name", 40 | "license": "GPL-3.0-or-later", 41 | "bugs": { 42 | "url": "plugin_author_url" 43 | }, 44 | "homepage": "" 45 | } 46 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | PREFIX rules for PHP_CodeSnifferr 4 | 5 | . 6 | 7 | vendor/* 8 | dist/* 9 | *.js 10 | *.css 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /plugin-boilerplate.php: -------------------------------------------------------------------------------- 1 | "; 46 | /* translators: 1: Opening

HTML element 2: Opening HTML element 3: Closing HTML element 4: Closing

HTML element */ 47 | echo sprintf( esc_html__( '%1$s%2$s my_plugin_name NOTICE:%3$s PHP version too low to use this plugin. Please change to at least PHP 7.4. You can contact your web host for assistance in updating your PHP version.%4$s', 'text-domain' ), '

', '', '', '

' ); 48 | echo ''; 49 | } 50 | ); 51 | return; 52 | } 53 | } 54 | 55 | /** 56 | * Check PHP versions 57 | */ 58 | if ( defined( 'PHP_VERSION' ) ) { 59 | if ( version_compare( PHP_VERSION, '7.4', '<' ) ) { 60 | add_action( 61 | 'admin_notices', 62 | function() { 63 | echo "
"; 64 | /* translators: 1: Opening

HTML element 2: Opening HTML element 3: Closing HTML element 4: Closing

HTML element */ 65 | echo sprintf( esc_html__( '%1$s%2$s my_plugin_name NOTICE:%3$s PHP version too low to use this plugin. Please change to at least PHP 7.4. You can contact your web host for assistance in updating your PHP version.%4$s', 'text-domain' ), '

', '', '', '

' ); 66 | echo '
'; 67 | } 68 | ); 69 | return; 70 | } 71 | } 72 | 73 | // Composer autoload. 74 | require_once dirname( __FILE__ ) . '/vendor/autoload.php'; 75 | 76 | /** 77 | * The code that runs during plugin activation. 78 | * This action is documented in includes/class-prefix-activator.php 79 | */ 80 | if ( ! function_exists( 'activate_prefix' ) ) { 81 | /** 82 | * Code to run when plugin is activated. 83 | * 84 | * @return void 85 | */ 86 | function activate_prefix() { 87 | \Root\Notices\RootActivator::activate(); 88 | } 89 | } 90 | 91 | /** 92 | * The code that runs during plugin deactivation. 93 | * This action is documented in includes/class-prefix-deactivator.php 94 | */ 95 | if ( ! function_exists( 'deactivate_prefix' ) ) { 96 | /** 97 | * Code to run when plugin is deactivated. 98 | * 99 | * @return void 100 | */ 101 | function deactivate_prefix() { 102 | \Root\Notices\RootDeactivator::deactivate(); 103 | } 104 | } 105 | 106 | register_activation_hook( __FILE__, 'activate_prefix' ); 107 | register_deactivation_hook( __FILE__, 'deactivate_prefix' ); 108 | 109 | define( 'PREFIX_BASE_FILE', basename( plugin_dir_path( __FILE__ ) ) ); 110 | define( 'PREFIX_PLUGIN_NAME', 'my_plugin_shortname' ); 111 | define( 'PREFIX_PLUGIN_DIR', __DIR__ . '/' ); 112 | define( 'PREFIX_PLUGIN_ASSETS_DIR', __DIR__ . '/assets/' ); 113 | define( 'PREFIX_PLUGIN_ASSETS_PATH_URL', plugin_dir_url( __FILE__ ) . 'assets/' ); 114 | define( 'PREFIX_PLUGIN_PATH_URL', plugin_dir_url( __FILE__ ) ); 115 | 116 | $debug = false; 117 | 118 | // Add SL_DEV_DEBUGGING to your wp-config.php file on your test environment. Feel free to rename constant. 119 | if ( defined( 'SL_DEV_DEBUGGING' ) ) { 120 | $debug = true; 121 | } 122 | 123 | define( 'PREFIX_DEBUG', $debug ); 124 | 125 | if ( ! function_exists( 'PREFIX_INIT' ) ) { 126 | function PREFIX_INIT() { 127 | $plugin_instance = \Root\Bootstrap\Main::getInstance(); 128 | $plugin_instance->run(); 129 | } 130 | } 131 | add_action( 'plugins_loaded', 'PREFIX_INIT' ); 132 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ### [WordPress MVC Plugin Boilerplate](https://github.com/UVLabs/wordpress-plugin-boilerplate) 2 | 3 | #### A WordPress plugin boilerplate made with PS4 autoloading and MVC design pattern in mind. 4 | 5 | Original boilerplate code was made with https://wppb.me/, but changes made to accommodate MVC design pattern and PSR4 autoloading. Some additional tools for WordPress, PHP and JS development were added. 6 | 7 | There might be more replacements to be done to get all placeholder text changed but I've tried to list all of them below. Feel free to submit a pull request for any changes. 8 | 9 | 10 | ### Steps 11 | 12 | #### Composer 13 | 14 | Run `composer install` 15 | 16 | #### NPM 17 | 18 | - Add relevant info to package.json 19 | - Run `npm install` 20 | 21 | #### Replacements: 22 | 23 | #### Search and replaces (ALL SEARCHES SHOULD BE CASE SENSITIVE): 24 | 25 | - Replace 'my_plugin_name' with the Plugin name example `Awesome WordPress Plugin` (exact match [whole word]) 26 | 27 | - Replace 'my_plugin_shortname' with a short lowercase version of the plugin name example `awesome_wp_plugin`. USE UNDERSCORES for the sparation (exact match [whole word]) 28 | 29 | - Replace 'text-domain' with plugin text domain (exact match [whole word]) 30 | 31 | - Replace 'PREFIX' with a prefix for constants (loose match, case sensitive) 32 | 33 | - Replace 'prefix_' with a lowercase version of the plugin name example `myplugin_` etc. USE UNDERSCORES for the sparation example `my_plugin_` (loose match, case sensitive) 34 | 35 | - Replace '_prefix' with lowercase version of plugin name example `_my_plugin` (loose match, case sensitive) 36 | 37 | - Replace 'prefix-' with a lowercase version of the plugin name example `myplugin-` etc. USE DASHES for the sparation example `my-plugin-` (exact match [whole word], case sensitive) 38 | 39 | - Replace 'root' in file name for activator and deactivator classes located in `/includes` with a lowercase version of the plugin name, example `myplugin`. USE DASHES for the sparation example `my-plugin-` 40 | 41 | - Replace `RootActivator` and `RootDeactivator` class names with the preferred class names for the activator and deactivator files. (exact match [whole word], case sensitive) 42 | 43 | - Replace 'prefix' in file name for your asset files located in `/assets` with a lowercase version of the plugin name, example `myplugin`. USE DASHES for the sparation example `my-plugin-` 44 | 45 | - Open `dist.sh` in the `bin` folder and replace prefix.zip with the name for your dist file that will be created when you run `composer dist` example `myplugin.zip` 46 | 47 | - Replace 'Root' with a shortname for plugin example `Myplugin`. This is used as your namespace prefix. (exact match, whole word) 48 | 49 | You need to run `composer dumpautoload` after making this change to refresh autoload file with correct details. 50 | 51 | - Replace 'plugin_author_name' with your name, (exact match [whole word]) 52 | 53 | - Replace 'plugin_author_url' with your website, (exact match [whole word]) 54 | 55 | - Replace 'plugin_author_email' with your email address (exact match [whole word]) 56 | 57 | - Replace `SL_DEV_DEBUGGING` with a constant of your choice. This constant should be defined as true in your local wp install's `wp-config.php` file where you work on the plugin. It is used to set the plugin's main debug constant as true and loads the unminified JS of the plugin while working in your local environment. 58 | 59 | ### Note 60 | 61 | If deploying plugin from github then remove the following lines from the `.gitignore` file: 62 | 63 |
64 | assets/admin/js/build/
65 | assets/public/js/build/
66 | 
67 | 68 | These are the build files for your JS and should be committed if you're deploying the plugin from github using a plugin like Git Updater. -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === my_plugin_name === 2 | Contributors: user, user, user 3 | Tags: tag, tag, tag 4 | Donate link: http://example.com/ 5 | Requires at least: 4.0 6 | Tested up to: 4.8 7 | Requires PHP: 7.4 8 | Stable tag: 1.0.0 9 | License: GPLv2 or later 10 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 11 | 12 | Short description of this great plugin. No more than 150 characters, no markup. 13 | 14 | == Description == 15 | Long description of this great plugin. No characters limit, and you can use markdown. 16 | 17 | For backwards compatibility, if this section is missing, the full length of the short description will be used, and 18 | markdown parsed. 19 | 20 | Ordered list: 21 | 22 | 1. Some feature 23 | 1. Another feature 24 | 1. Something else about the plugin 25 | 26 | Unordered list: 27 | 28 | * something 29 | * something else 30 | * third thing 31 | 32 | Link to [WordPress](http://wordpress.org/ "Your favorite software") and one to [Markdown's Syntax Documentation][markdown syntax]. 33 | 34 | Titles are optional, naturally. 35 | 36 | Asterisks for *emphasis*. 37 | 38 | Double it up for **strong**. 39 | 40 | == Installation == 41 | 1. Upload "test-plugin.php" to the "/wp-content/plugins/" directory. 42 | 1. Activate the plugin through the "Plugins" menu in WordPress. 43 | 1. Place "do_action( 'plugin_name_hook' );" in your templates. 44 | 45 | == Frequently Asked Questions == 46 | = A question that someone might have = 47 | An answer to that question. 48 | 49 | = What about foo bar? = 50 | Answer to foo bar dilemma. 51 | 52 | == Screenshots == 53 | 1. The screenshot description corresponds to screenshot-1.(png|jpg|jpeg|gif). 54 | 2. The screenshot description corresponds to screenshot-2.(png|jpg|jpeg|gif). 55 | 3. The screenshot description corresponds to screenshot-3.(png|jpg|jpeg|gif). 56 | 57 | == Changelog == 58 | = 1.0.1 = 59 | * A change since the previous version. 60 | * Another change. 61 | 62 | = 1.0.0 = 63 | * Initial release. 64 | 65 | == Upgrade Notice == 66 | = 1.0.1 = 67 | Upgrade notices describe the reason a user should upgrade 68 | 69 | = 1.0.0 = 70 | This version fixes a security related bug. Upgrade immediately. -------------------------------------------------------------------------------- /uninstall.php: -------------------------------------------------------------------------------- 1 |