Add an admin page, build a simple component + filters

This commit is contained in:
Kelly Dwan 2018-04-17 19:51:48 -04:00
parent dbe06969fe
commit 05dacbe212
16 changed files with 1255 additions and 221 deletions

View File

@ -1,17 +1,21 @@
{
"env": {},
"ignore": [],
"plugins": [
"transform-object-rest-spread"
],
"presets": [
"react",
[ "env", {
"targets": {
"browsers": ["last 2 versions", "not ie <= 10"],
"node": "current"
},
"useBuiltIns": true
} ]
]
"@wordpress/default"
],
"plugins": [
"transform-async-generator-functions"
],
"env": {
"production": {
"plugins": [
[
"@wordpress/babel-plugin-makepot",
{
"output": "languages/woo-dash.pot"
}
],
"transform-async-generator-functions"
]
}
}
}

View File

@ -7,4 +7,10 @@ node_modules/
*.sql
*.tar.gz
*.zip
js/index.js
js/index.js
js/index.js.map
js/style.css
js/style.css.map
languages/*
!languages/README.md

View File

@ -19,14 +19,6 @@ module.exports = function( grunt ) {
}
},
wp_readme_to_markdown: {
your_target: {
files: {
'README.md': 'readme.txt'
}
},
},
makepot: {
target: {
options: {
@ -46,9 +38,7 @@ module.exports = function( grunt ) {
} );
grunt.loadNpmTasks( 'grunt-wp-i18n' );
grunt.loadNpmTasks( 'grunt-wp-readme-to-markdown' );
grunt.registerTask( 'i18n', ['addtextdomain', 'makepot'] );
grunt.registerTask( 'readme', ['wp_readme_to_markdown'] );
grunt.util.linefeed = '\n';

View File

@ -0,0 +1,16 @@
# WooCommerce Dashboard
This is a feature plugin for a modern, javascript-driven dashboard for WooCommerce.
## Development
After cloning the repo, install dependencies with `npm install`. Now you can build the files using one of these commands:
- `npm run build` : Build a production version
- `npm run dev` : Build a development version
- `npm run watch` : Build a development version, watch files for changes
There are also some helper scripts:
- `npm run lint` : Run eslint over the javascript files
- `npm run i18n` : Create a PHP file with the strings from the javascript files, [used to get around lack of JS support in WordPress.org](https://github.com/WordPress/packages/tree/master/packages/i18n#build).

View File

@ -0,0 +1,39 @@
/** @format */
/**
* External dependencies
*/
import { __, _n, sprintf } from '@wordpress/i18n';
import { applyFilters } from '@wordpress/hooks';
import { Button } from '@wordpress/components';
import { Component } from '@wordpress/element';
/**
* External dependencies
*/
import './style.scss';
import useFilters from '../use-filters';
class Dashboard extends Component {
render() {
return (
<div>
<h2>{ applyFilters( 'woodash.example2', __( 'Example Widget', 'woo-dash' ) ) }</h2>
<div className="wd_widget">
<div className="wd_widget-item">
{ sprintf( _n( '%d New Customer', '%d New Customers', 4, 'woo-dash' ), 4 ) }
</div>
<div className="wd_widget-item">
{ sprintf( _n( '%d New Order', '%d New Orders', 10, 'woo-dash' ), 10 ) }
</div>
<div className="wd_widget-item">
<Button isPrimary href="#">{ __( 'View Orders', 'woo-dash' ) }</Button>
</div>
</div>
<h3>{ applyFilters( 'woodash.example', __( 'Example Text', 'woo-dash' ) ) }</h3>
</div>
);
}
}
export default useFilters( [ 'woodash.example', 'woodash.example2' ] )( Dashboard );

View File

@ -0,0 +1,12 @@
.wd_widget {
display: flex;
background: white;
border: 1px solid rgba( black, 0.2 );
padding: 2em;
align-items: center;
text-align: center;
}
.wd_widget-item {
flex: 1;
}

View File

@ -1,3 +1,28 @@
document.addEventListener( 'DOMContentLoaded', function() {
console.log( 'hi!' );
} );
/** @format */
/**
* External dependencies
*/
import { createElement, render } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';
/**
* Internal dependencies
*/
import Dashboard from './dashboard';
render(
createElement( Dashboard ),
document.getElementById( 'root' )
);
setTimeout( function() {
function editText( string ) {
return `Also filtered: ${ string }`;
}
addFilter( 'woodash.example', 'editText', editText );
}, 1500 );
function editText2( string ) {
return `Filtered: ${ string }`;
}
addFilter( 'woodash.example2', 'editText2', editText2 );

View File

@ -0,0 +1,64 @@
/**
* External dependencies
*/
import { debounce, isArray, uniqueId } from 'lodash';
/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';
import { addAction, removeAction } from '@wordpress/hooks';
const ANIMATION_FRAME_PERIOD = 16;
/**
* Creates a higher-order component which adds filtering capability to the
* wrapped component. Filters get applied when the original component is about
* to be mounted. When a filter is added or removed that matches the hook name,
* the wrapped component re-renders.
*
* @param {string|array} hookName Hook names exposed to be used by filters.
*
* @return {Function} Higher-order component factory.
*/
export default function useFilters( hookName ) {
const hookNames = isArray( hookName ) ? hookName : [ hookName ];
return function( OriginalComponent ) {
return class FilteredComponent extends Component {
constructor( props ) {
super( props );
this.onHooksUpdated = this.onHooksUpdated.bind( this );
this.namespace = uniqueId( 'woo-dash/use-filters/component-' );
this.throttledForceUpdate = debounce( () => {
this.forceUpdate();
}, ANIMATION_FRAME_PERIOD );
addAction( 'hookRemoved', this.namespace, this.onHooksUpdated );
addAction( 'hookAdded', this.namespace, this.onHooksUpdated );
}
componentWillUnmount() {
this.throttledForceUpdate.cancel();
removeAction( 'hookRemoved', this.namespace );
removeAction( 'hookAdded', this.namespace );
}
/**
* When a filter is added or removed for any matching hook name, the wrapped component should re-render.
*
* @param {string} updatedHookName Name of the hook that was updated.
*/
onHooksUpdated( updatedHookName ) {
if ( -1 !== hookNames.indexOf( updatedHookName ) ) {
this.throttledForceUpdate();
}
}
render() {
return <OriginalComponent { ...this.props } />;
}
};
};
}

View File

@ -0,0 +1,42 @@
<?php
/**
* Register a new menu page for the Dashboard
*/
function woo_dash_register_page(){
add_menu_page(
__( 'Woo Dash', 'woo-dash' ),
__( 'WC Dashboard', 'woo-dash' ),
'manage_options',
'woodash',
'woo_dash_page',
'dashicons-cart',
6
);
}
add_action( 'admin_menu', 'woo_dash_register_page' );
/**
* Load the assets on the Dashboard page
*/
function woo_dash_enqueue_script( $hook ){
if ( 'toplevel_page_woodash' !== $hook ) {
return;
}
wp_enqueue_script( WOO_DASH_APP );
wp_enqueue_style( WOO_DASH_APP );
}
add_action( 'admin_enqueue_scripts', 'woo_dash_enqueue_script' );
/**
* Set up a div for the app to render into.
*/
function woo_dash_page(){
?>
<div class="wrap">
<h1 class="wp-heading-inline"><?php esc_html_e( 'Woo Dashboard Demo', 'woo-dash' ); ?></h1>
<div id="root"></div>
</div>
<?php
}

View File

@ -0,0 +1,35 @@
<?php
/**
* Registers the JS & CSS for the Dashboard
*/
function woo_dash_register_script() {
wp_register_script(
WOO_DASH_APP,
woo_dash_url( 'js/index.js' ),
[ 'wp-blocks', 'wp-element', 'wp-i18n' ],
filemtime( woo_dash_dir_path( '/js/index.js' ) ),
true
);
wp_register_style(
WOO_DASH_APP,
woo_dash_url( 'js/style.css' ),
[ 'wp-components', 'wp-blocks', 'wp-edit-blocks' ],
filemtime( woo_dash_dir_path( '/js/index.js' ) )
);
// Set up the text domain and translations
$locale_data = gutenberg_get_jed_locale_data( 'woo-dash' );
$content = 'wp.i18n.setLocaleData( ' . json_encode( $locale_data ) . ', "woo-dash" );';
wp_add_inline_script( WOO_DASH_APP, $content, 'before' );
}
add_action( 'init', 'woo_dash_register_script' );
/**
* Load plugin text domain for translations.
*/
function woo_dash_load_plugin_textdomain() {
load_plugin_textdomain( 'woo-dash', false, basename( dirname( __FILE__ ) ) . '/languages' );
}
add_action( 'plugins_loaded', 'woo_dash_load_plugin_textdomain' );

View File

@ -0,0 +1,21 @@
<?php
/**
* Retrieves the root plugin path.
*
* @return string Root path to the gutenberg custom fields plugin.
*/
function woo_dash_dir_path() {
return plugin_dir_path( dirname(__FILE__ ) );
}
/**
* Retrieves a URL to a file in the gutenberg custom fields plugin.
*
* @param string $path Relative path of the desired file.
*
* @return string Fully qualified URL pointing to the desired file.
*/
function woo_dash_url( $path ) {
return plugins_url( $path, dirname( __FILE__ ) );
}

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
{
"name": "woo-dash",
"version": "0.1.0",
"main": "Gruntfile.js",
"main": "js/index.js",
"author": "Automattic",
"license": "GPL-2.0-or-later",
"repository": "",
"engines": {
"node": "8.11.0",
"npm": "5.6.0"
@ -11,16 +13,17 @@
"build": "NODE_ENV=production webpack",
"dev": "webpack",
"watch": "webpack --watch",
"lint": "eslint js --ext=js,jsx",
"readme": "grunt readme",
"i18n": "grunt i18n"
"lint": "eslint js/src --ext=js,jsx",
"i18n": "pot-to-php ./languages/woo-dash.pot ./languages/woo-dash.php woo-dash && grunt i18n"
},
"devDependencies": {
"@wordpress/babel-plugin-makepot": "^1.0.0",
"@wordpress/babel-preset-default": "^1.2.0",
"@wordpress/i18n": "^1.1.0",
"babel-core": "^6.26.0",
"babel-eslint": "^8.2.3",
"babel-loader": "^7.1.4",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"babel-plugin-transform-async-generator-functions": "^6.24.1",
"css-loader": "^0.28.11",
"eslint": "^4.18.2",
"eslint-config-wpcalypso": "^2.0.0",
@ -30,11 +33,14 @@
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"grunt": "^1.0.2",
"grunt-wp-i18n": "^1.0.2",
"grunt-wp-readme-to-markdown": "^2.0.1",
"node-sass": "^4.8.3",
"prettier": "github:automattic/calypso-prettier#c56b4251",
"sass-loader": "^7.0.1",
"style-loader": "^0.20.3",
"webpack": "^4.6.0",
"webpack-cli": "^2.0.14"
},
"dependencies": {
"lodash": "^4.17.5"
}
}

View File

@ -1,114 +0,0 @@
=== Woo Dash ===
Contributors: (this should be a list of wordpress.org userid's)
Donate link: https://example.com/
Tags: comments, spam
Requires at least: 4.4
Tested up to: 4.9.5
Stable tag: 0.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Here is a short description of the plugin. This should be no more than 150 characters. No markup here.
== Description ==
This is the long description. No limit, and you can use Markdown (as well as in the following sections).
For backwards compatibility, if this section is missing, the full length of the short description will be used, and
Markdown parsed.
A few notes about the sections above:
* "Contributors" is a comma separated list of wp.org/wp-plugins.org usernames
* "Tags" is a comma separated list of tags that apply to the plugin
* "Requires at least" is the lowest version that the plugin will work on
* "Tested up to" is the highest version that you've *successfully used to test the plugin*. Note that it might work on
higher versions... this is just the highest one you've verified.
* Stable tag should indicate the Subversion "tag" of the latest stable version, or "trunk," if you use `/trunk/` for
stable.
Note that the `readme.txt` of the stable tag is the one that is considered the defining one for the plugin, so
if the `/trunk/readme.txt` file says that the stable tag is `4.3`, then it is `/tags/4.3/readme.txt` that'll be used
for displaying information about the plugin. In this situation, the only thing considered from the trunk `readme.txt`
is the stable tag pointer. Thus, if you develop in trunk, you can update the trunk `readme.txt` to reflect changes in
your in-development version, without having that information incorrectly disclosed about the current stable version
that lacks those changes -- as long as the trunk's `readme.txt` points to the correct stable tag.
If no stable tag is provided, it is assumed that trunk is stable, but you should specify "trunk" if that's where
you put the stable version, in order to eliminate any doubt.
== Installation ==
This section describes how to install the plugin and get it working.
e.g.
1. Upload `plugin-name.php` to the `/wp-content/plugins/` directory
1. Activate the plugin through the 'Plugins' menu in WordPress
1. Place `<?php do_action('plugin_name_hook'); ?>` in your templates
== Frequently Asked Questions ==
= A question that someone might have =
An answer to that question.
= What about foo bar? =
Answer to foo bar dilemma.
== Screenshots ==
1. This screen shot description corresponds to screenshot-1.(png|jpg|jpeg|gif). Note that the screenshot is taken from
the /assets directory or the directory that contains the stable readme.txt (tags or trunk). Screenshots in the /assets
directory take precedence. For example, `/assets/screenshot-1.png` would win over `/tags/4.3/screenshot-1.png`
(or jpg, jpeg, gif).
2. This is the second screen shot
== Changelog ==
= 1.0 =
* A change since the previous version.
* Another change.
= 0.5 =
* List versions from most recent at top to oldest at bottom.
== Upgrade Notice ==
= 1.0 =
Upgrade notices describe the reason a user should upgrade. No more than 300 characters.
= 0.5 =
This version fixes a security related bug. Upgrade immediately.
== Arbitrary section ==
You may provide arbitrary sections, in the same format as the ones above. This may be of use for extremely complicated
plugins where more information needs to be conveyed that doesn't fit into the categories of "description" or
"installation." Arbitrary sections will be shown below the built-in sections outlined above.
== A brief Markdown Example ==
Ordered list:
1. Some feature
1. Another feature
1. Something else about the plugin
Unordered list:
* something
* something else
* third thing
Here's a link to [WordPress](https://wordpress.org/ "Your favorite software") and one to [Markdown's Syntax Documentation][markdown syntax].
Titles are optional, naturally.
[markdown syntax]: https://daringfireball.net/projects/markdown/syntax
"Markdown is what the parser uses to process much of the readme file"
Markdown uses email style notation for blockquotes and I've been told:
> Asterisks for *emphasis*. Double it up for **strong**.
`<?php code(); // goes in backticks ?>`

View File

@ -43,7 +43,6 @@ const externals = {
tinymce: 'tinymce',
moment: 'moment',
jquery: 'jQuery',
lodash: 'lodash',
};
coreGlobals.forEach( ( name ) => {
@ -58,7 +57,7 @@ const webpackConfig = {
output: {
path: path.resolve( 'js' ),
filename: 'index.js',
library: [ 'wp', '[name]' ],
library: [ 'wp', 'woodash' ],
libraryTarget: 'this',
},
externals,
@ -83,4 +82,8 @@ const webpackConfig = {
],
};
if ( webpackConfig.mode !== 'production' ) {
webpackConfig.devtool = process.env.SOURCEMAP || 'source-map';
}
module.exports = webpackConfig;

View File

@ -1,15 +1,28 @@
<?php
/**
* Plugin Name: Woo Dash
* Plugin URI: PLUGIN SITE HERE
* Description: PLUGIN DESCRIPTION HERE
* Author: YOUR NAME HERE
* Author URI: YOUR SITE HERE
* Text Domain: woo-dash
* Domain Path: /languages
* Version: 0.1.0
* Plugin Name: Woo Dashboard
* Plugin URI: https://woocommerce.com/
* Description: A feature plugin for a new Dashboard view of WooCommerce
* Author: Automattic
* Author URI: https://woocommerce.com/
* Text Domain: woo-dash
* Domain Path: /languages
* Version: 0.1.0
*
* @package Woo_Dash
*/
// Your code starts here.
if ( ! defined( 'WOO_DASH_APP' ) ) {
define( 'WOO_DASH_APP', 'woo-dash-app' );
}
// @TODO check for Gutenberg + WooCommerce
// Some common utilities
require_once dirname( __FILE__ ) . '/lib/common.php';
// Register script files
require_once dirname( __FILE__ ) . '/lib/client-assets.php';
// Create the Admin pages
require_once dirname( __FILE__ ) . '/lib/admin.php';