Initial commit, dashboard settings page seems to work fine.

This commit is contained in:
Brian 2021-05-31 15:03:52 -06:00
commit 5ce0217861
Signed by: brian
GPG Key ID: DE1A5390A3B84CD8
30 changed files with 825 additions and 0 deletions

28
.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
### Project Specific
# Files
.env
phpcs.xml
phpunit.xml
.phpunit.result.cache
# Directories
/vendor/
node_modules/
cache/
### Editor Specific
# Files
nmsp-plugin-name.sublime-project
nmsp-plugin-name.sublime-workspace
# Directories
.idea
.vscode
### System Specific
# Files
.DS_Store
Thumbs.db
# Directories
__MACOSX

0
CHANGELOG.md Normal file
View File

0
LICENSE.md Normal file
View File

0
README.md Normal file
View File

View File

0
assets/css/vendor/.gitkeep vendored Normal file
View File

View File

View File

0
assets/js/vendor/.gitkeep vendored Normal file
View File

24
bootstrap.php Normal file
View File

@ -0,0 +1,24 @@
<?php
use PluginNamespace\App;
/**
| ----------------------------------------------------------------
| Bootstrap
| ----------------------------------------------------------------
|
| Place anything that needs to be configured/defined in this
| file that needs to be set up before the plugin is
| utilized by WordPress.
|
*/
require_once 'constants/http-codes.php';
require_once 'constants/base.php';
require_once 'constants/rewrites.php';
if ( ! function_exists( 'nmsp_plugin_app' ) ) {
function nmsp_plugin_app(): App {
return App::get_instance();
}
}

47
composer.json Normal file
View File

@ -0,0 +1,47 @@
{
"name": "namespace/plugin-name",
"description": "A boilerplate repo for a WordPress plugin.",
"type": "wordpress-plugin",
"version": "1.0.0",
"license": "GPL",
"authors": [
{
"name": "Your Name",
"email": "you@email.com"
}
],
"require": {
"php": ">=7.3.0",
"eftec/bladeone": "^3.52"
},
"require-dev": {
"wp-coding-standards/wpcs": "^2.3"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"autoload": {
"psr-4": {
"PluginNamespace\\": "includes/"
},
"classmap": [
"includes/"
]
},
"autoload-dev": {
"psr-4": {
"PluginNamespaceTests\\": "tests/"
},
"classmap": [
"tests/"
]
},
"minimum-stability": "dev",
"prefer-stable": true,
"scripts": {
"post-autoload-dump": [],
"post-root-package-install": []
}
}

187
composer.lock generated Normal file
View File

@ -0,0 +1,187 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "bd67390e5b29dd8e1a56e6e73d50d2c7",
"packages": [
{
"name": "eftec/bladeone",
"version": "3.52",
"source": {
"type": "git",
"url": "https://github.com/EFTEC/BladeOne.git",
"reference": "a19bf66917de0b29836983db87a455a4f6e32148"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/EFTEC/BladeOne/zipball/a19bf66917de0b29836983db87a455a4f6e32148",
"reference": "a19bf66917de0b29836983db87a455a4f6e32148",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=5.6"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.16.1",
"phpunit/phpunit": "^5.7",
"squizlabs/php_codesniffer": "^3.5.4"
},
"suggest": {
"eftec/bladeonehtml": "Extension to create forms",
"ext-mbstring": "This extension is used if it's active"
},
"type": "library",
"autoload": {
"psr-4": {
"eftec\\bladeone\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jorge Patricio Castro Castillo",
"email": "jcastro@eftec.cl"
}
],
"description": "The standalone version Blade Template Engine from Laravel in a single php file",
"homepage": "https://github.com/EFTEC/BladeOne",
"keywords": [
"blade",
"php",
"template",
"templating",
"view"
],
"support": {
"issues": "https://github.com/EFTEC/BladeOne/issues",
"source": "https://github.com/EFTEC/BladeOne/tree/3.52"
},
"time": "2021-04-17T13:49:01+00:00"
}
],
"packages-dev": [
{
"name": "squizlabs/php_codesniffer",
"version": "3.6.0",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
"reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
"shasum": ""
},
"require": {
"ext-simplexml": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"bin": [
"bin/phpcs",
"bin/phpcbf"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Greg Sherwood",
"role": "lead"
}
],
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
"keywords": [
"phpcs",
"standards"
],
"support": {
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
},
"time": "2021-04-09T00:54:41+00:00"
},
{
"name": "wp-coding-standards/wpcs",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
"reference": "7da1894633f168fe244afc6de00d141f27517b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62",
"reference": "7da1894633f168fe244afc6de00d141f27517b62",
"shasum": ""
},
"require": {
"php": ">=5.4",
"squizlabs/php_codesniffer": "^3.3.1"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
"phpcompatibility/php-compatibility": "^9.0",
"phpcsstandards/phpcsdevtools": "^1.0",
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"suggest": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
},
"type": "phpcodesniffer-standard",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Contributors",
"homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
}
],
"description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
"keywords": [
"phpcs",
"standards",
"wordpress"
],
"support": {
"issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues",
"source": "https://github.com/WordPress/WordPress-Coding-Standards",
"wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki"
},
"time": "2020-05-13T23:57:56+00:00"
}
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
"php": ">=7.3.0"
},
"platform-dev": [],
"plugin-api-version": "2.0.0"
}

15
constants/base.php Normal file
View File

@ -0,0 +1,15 @@
<?php
/**
| ----------------------------------------------------------------
| Base Definitions
| ----------------------------------------------------------------
|
| This is meant to be a place to put various defined variables
| that will be used throughout the plugin.
|
*/
if ( ! defined( 'NMSP_PLUGIN_NONCE' ) ) {
define( 'NMSP_PLUGIN_NONCE', 'nmsp-plugin-nonce' );
}

65
constants/http-codes.php Normal file
View File

@ -0,0 +1,65 @@
<?php
/**
| ----------------------------------------------------------------
| HTTP Status Code Definitions
| ----------------------------------------------------------------
|
| Translate HTTP status codes from numerical to a more
| human-friendly string that's easier to remember.
|
*/
$codes = array(
// 200's (successful)
200 => 'HTTP_SUCCESS',
201 => 'HTTP_CREATED',
202 => 'HTTP_ACCEPTED',
204 => 'HTTP_NO_CONTENT',
205 => 'HTTP_RESET_CONTENT',
206 => 'HTTP_PARTIAL_CONTENT',
208 => 'HTTP_ALREADY_REPORTED',
// 300's (redirections)
301 => 'HTTP_MOVED_PERMANENTLY',
304 => 'HTTP_NOT_MODIFIED',
307 => 'HTTP_TEMP_REDIRECT',
308 => 'HTTP_PERMANENT_REDIRECT',
// 400's (app got the request but couldn't process it successfully, coding error)
400 => 'HTTP_BAD_REQUEST',
401 => 'HTTP_UNAUTHORIZED',
402 => 'HTTP_PAYMENT_REQUIRED',
403 => 'HTTP_FORBIDDEN',
404 => 'HTTP_NOT_FOUND',
405 => 'HTTP_METHOD_NOT_ALLOWED',
406 => 'HTTP_NOT_ACCEPTABLE',
408 => 'HTTP_TIMEOUT',
409 => 'HTTP_CONFLICT',
410 => 'HTTP_GONE',
412 => 'HTTP_PRECONDITION_FAILED',
413 => 'HTTP_PAYLOAD_TOO_LARGE',
415 => 'HTTP_UNSUPPORTED_MEDIA',
413 => 'HTTP_TOO_LARGE',
417 => 'HTTP_EXPECTATION_FAIL',
418 => 'HTTP_TEAPOT',
422 => 'HTTP_UNPROCESSABLE_ENTITY',
423 => 'HTTP_LOCKED',
424 => 'HTTP_FAILED_DEPENDENCY',
236 => 'HTTP_UPGRADE_REQUIRED',
428 => 'HTTP_PRECONDITION_REQUIRED',
429 => 'HTTP_TOO_MANY_REQUESTS',
451 => 'HTTP_GAG_ORDER',
// 500's (server-level problem, process died or configuration is incorrect)
500 => 'HTTP_SERVER_ERROR',
501 => 'HTTP_NOT_IMPLEMENTED',
503 => 'HTTP_UNAVAILABLE',
530 => 'HTTP_SUSPENDED',
);
foreach ( $codes as $code => $slug ) {
if ( ! defined( $slug ) ) {
define( $slug, $code );
}
}

23
constants/rewrites.php Normal file
View File

@ -0,0 +1,23 @@
<?php
/**
| ----------------------------------------------------------------
| URL Rewrite Definitions
| ----------------------------------------------------------------
|
| These are rewrite definitions that are language dependent.
| If new languages are added in WordPress, then you will
| have to add them here as well. These will be saved
| to the options table and reference a post ID.
|
*/
const NMSP_PLUGIN_SLUG_REWRITE_NAMES = array(
'NMSP_PLUGIN_SLUG_PAGE_NAME' => 'nmsp_plugin_slug_page_name',
);
foreach ( NMSP_PLUGIN_SLUG_REWRITE_NAMES as $page_slug => $page_name ) {
if ( ! defined( $page_slug ) ) {
define( $page_slug, $page_name );
}
}

166
includes/class-app.php Normal file
View File

@ -0,0 +1,166 @@
<?php
namespace PluginNamespace;
use eftec\bladeone\BladeOne;
use Exception;
class App {
/** @var \PluginNamespace\App */
public static $instance;
/** @var \eftec\bladeone\BladeOne */
public $blade;
/**
* Any logic that needs executed when the plugin is activated.
*
* @since 1.0.0
*
* @return void
*/
public static function plugin_activation(): void {
self::ensure_template_cache_dir_exists();
}
/**
* Any logic that needs executed when the plugin is deactivated.
*
* @since 1.0.0
*
* @return void
*/
public static function plugin_deactivation(): void {
//
}
/**
* Check that the cache directory for Blade exists and
* if not then attempt to create it.
*
* @since 1.0.0
*
* @throws \Exception
*
* @return void
*/
public static function ensure_template_cache_dir_exists(): void {
if ( ! file_exists( NMSP_PLUGIN_BASE_DIR . '/cache/blade/.gitignore' ) ) {
try {
mkdir( NMSP_PLUGIN_BASE_DIR . '/cache/blade', 0755, true );
} catch ( Exception $e ) {
$error_payload = array(
'level' => 'critical',
'message' => $e->getMessage(),
'context' => array(
'file' => $e->getFile(),
'line' => $e->getLine(),
),
);
error_log( json_encode( $error_payload, JSON_PRETTY_PRINT ) );
}
}
}
/**
* Return an instance of this plugin class. If it has
* not been initialized, do so then return it.
*
* @since 1.0.0
*
* @return \PluginNamespace\App
*/
public static function get_instance(): App {
if ( ! isset( self::$instance ) && ! ( self::$instance instanceof App ) ) {
self::$instance = new App();
self::$instance->load_plugin_textdomain();
self::$instance->scaffold_plugin();
self::$instance->includes();
}
return self::$instance;
}
/**
* Load your translation files for this plugin.
*
* @since 1.0.0
*
* @return void
*/
public function load_plugin_textdomain(): void {
load_plugin_textdomain( 'nmsp-plugin-name-text-domain', false, 'languages' );
}
/**
* Steps to take when initializing this plugin??
*
* @since 1.0.0
*
* @return void
*/
public function scaffold_plugin(): void {
add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
}
/**
* Setting up the WordPress dashboard menu for this plugin.
* Setting this here to be overriden later so that a base is always available.
*
* @since 1.0.0
*
* @return void
*/
public function add_admin_menu(): void {
$page_title = __( 'Namespace Plugin Name', 'nmsp_plugin_name_menu' );
$menu_title = __( 'Namespace Plugin Name', 'nmsp_plugin_name_menu' );
$capability = 'manage_options';
$menu_slug = 'nmsp-plugin-name-menu-slug';
$callback = '';
$icon = plugins_url( '../assets/images/menu-icon.svg', __FILE__ );
$position = 100;
add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $callback, $icon, $position );
}
/**
* Other files to include so that this plugin will
* have a single entrypoint but be able to break
* up code in a logical manor.
*
* @codeCoverageIgnore
*
* @since 1.0.0
*
* @return void
*/
public function includes(): void {
// Files to include on the dashboard.
if ( is_admin() ) {
require_once __DIR__ . '/dashboard/class-settings.php';
}
//
// Files to include on every request.
//
// Files to include that may be sub-namespaced.
//
}
/**
* .
*
* @since 1.0.0
*
* @param \eftec\bladeone\BladeOne $blade
*
* @return void
*/
public function load_blade( BladeOne $blade ): void {
$this->blade = $blade;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace PluginNamespace;
use WP_CLI;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class NmspCli {
/**
* Class constructor. Can add commands here.
*
* @since 1.0.0
*
* @return void
*/
public function __construct() {
WP_CLI::add_command(
'nmsp-plugin do',
array( $this, 'do_the_thing' ),
array(
'shortdesc' => 'The short description.',
'longdesc' => "This is the super long description that will go on and on my friend. Some people started writing it not knowing what it was, and we'll continue writing it forever just because this is the description that never ends...",
),
);
}
/**
* A sample method where something is done.
*
* @since 1.0.0
*
* @return void
*/
public function do_the_thing(): void {
//
}
}
new NmspCli();

View File

@ -0,0 +1,73 @@
<?php
namespace PluginNamespace;
class Settings {
/**
* Class constructor.
*
* @since 1.0.0
*
* @return void
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'append_to_main_dashboard_menu' ), 12 );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
}
/**
* Append to the dashboard menu (prevents doubling).
*
* @since 1.0.0
*
* @return void
*/
public function append_to_main_dashboard_menu(): void {
$parent_slug = 'nmsp-plugin-name-menu-slug';
$page_title = __( 'Namespace Plugin Name - Settings', 'nmsp_plugin_name_settings_title' );
$menu_title = __( 'Settings', 'nmsp_plugin_name_settings_title' );
$capability = 'manage_options';
$menu_slug = $parent_slug;
$callback = array( $this, 'show_settings_page' );
add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $callback );
}
/**
* Show the settings page on the dashboard.
*
* @since 1.0.0
*
* @return void
*/
public function show_settings_page(): void {
$data = array();
echo nmsp_plugin_app()->blade->run( 'dashboard.settings', $data );
}
/**
* Register and enqueue stylesheets and javascript files.
*
* @since 1.0.0
*
* @return void
*/
public function enqueue_scripts(): void {
wp_enqueue_style( 'nmsp-plugin-dashboard-css', plugins_url( '../../assets/css/nmsp-plugin-name.css', __FILE__ ), array(), '1.0.0', 'screen' );
wp_register_script( 'nmsp-plugin-dashboard-js', plugins_url( '../../assets/js/nmsp-plugin-name.js', __FILE__ ), array(), '1.0.0', false );
wp_enqueue_script( 'nmsp-plugin-dashboard-js' );
$payload = array(
'wp_ajax_url' => admin_url( 'admin-ajax.php' ),
'_nonce' => wp_create_nonce( NMSP_PLUGIN_NONCE ),
);
wp_localize_script( 'nmsp-plugin-dashboard-js', 'nmspDashboardApi', $payload );
}
}
new Settings();

View File

@ -0,0 +1,93 @@
<?php
namespace PluginNamespace\Front;
class Rewrites {
/**
* Class constructor.
*
* @since 1.0.0
*
* @return void
*/
public function __construct() {
add_action( 'init', array( $this, 'add_rewrite_rules' ), 5 );
add_filter( 'query_vars', array( $this, 'custom_query_vars' ) );
add_filter( 'nmsp_plugin_name_rewrite_urls', array( $this, 'build_rewrite_urls' ) );
}
/**
* Generate new rewrite rules and flush the cached values.
*
* @since 1.0.0
*
* @return void
*/
public function add_rewrite_rules(): void {
$filters = apply_filters( 'nmsp_plugin_name_rewrite_urls', array() );
add_rewrite_tag( 'foo', '([0-9]+)' );
if ( is_iterable( $filters ) && count( $filters ) > 0 ) {
foreach ( $filters as $item ) {
if ( $item['slug'] ) {
$slug = str_replace( home_url() . '/', '', get_permalink( $item['id'] ) );
add_rewrite_rule( '^' . $slug . '([^/]*' . $item['var'] . ')/([^/]*)/?', 'index.php?page_id=' . $item['id'] . '&$matches[1]=$matches[2]', 'top' );
}
}
flush_rewrite_rules();
}
}
/**
* Build the array of post IDs that have a slug for the URL
* along with what custom query variable to use.
*
* @since 1.0.0
*
* @return array
*/
public function build_rewrite_urls(): array {
$pages = array();
$page_list = array(
'NMSP_PLUGIN_SLUG_PAGE_NAME' => array( 'foo' ),
);
foreach ( $page_list as $key => $params ) {
$page_id = get_option( constant( $key ) );
$page = ( $page_id ) ? get_post( $page_id ) : false;
if ( ! empty( $page ) ) {
foreach ( $params as $param ) {
$pages[] = array(
'id' => $page_id,
'slug' => $page->post_name,
'var' => $param,
);
}
}
}
return $pages;
}
/**
* Append custom query variables to the list WordPress maintinas
* with each request.
*
* @since 1.0.0
*
* @param array $variable
*
* @return array
*/
public function custom_query_vars( array $vars ): array {
$vars[] = 'foo';
return $vars;
}
}
new Rewrites();

36
nmsp-plugin-name.php Normal file
View File

@ -0,0 +1,36 @@
<?php
use PluginNamespace\App;
use eftec\bladeone\BladeOne;
/*
Plugin Name: Boilerplate Plugin
Plugin URI: https://domain.com
Description: Your plugin description
Version: 1.0.0
Author: Plugin Author
Author URI: https://plugin-author.com
License: GPL v2
Text Domain: nmsp-plugin-name-text-domain
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
define( 'NMSP_PLUGIN_BASE_DIR', __DIR__ );
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/bootstrap.php';
// include the CLI utility of this plugin if WordPress has CLI functionality
if ( defined( 'WP_CLI' ) && WP_CLI ) {
require_once __DIR__ . '/includes/class-nmspcli.php';
}
$blade = new BladeOne( __DIR__ . '/templates', __DIR__ . '/cache/blade', BladeOne::MODE_DEBUG ); // BladeOne::MODE_AUTO
register_activation_hook( __FILE__, array( App::class, 'plugin_activation' ) );
register_deactivation_hook( __FILE__, array( App::class, 'plugin_deactivation') );
nmsp_plugin_app()->load_blade( $blade );

View File

View File

View File

@ -0,0 +1,5 @@
@extends('layouts.dashboard')
@section('content')
<p>PluginNamespace Plugin Settings Page</p>
@endsection

View File

@ -0,0 +1,5 @@
<div id="nmsp-plugin-dashboard-app" class="">
@yield('content')
</div>

View File

View File

View File

0
tests/Unit/.gitkeep Normal file
View File

3
tests/bootstrap.php Normal file
View File

@ -0,0 +1,3 @@
<?php
//

11
uninstall.php Normal file
View File

@ -0,0 +1,11 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit; // Exit if this isn't an uninstall action...maybe?
}
// Put logic here to undo things when this plugin is uninstalled.