diff --git a/.travis.yml b/.travis.yml index d11bd20..39ec022 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,29 +1,67 @@ -language: php - -notifications: - email: - on_success: never - on_failure: change +sudo: false -branches: - only: - - master +language: php -php: - - 5.3 - - 5.6 +git: + depth: 1 -env: - - WP_VERSION=latest WP_MULTISITE=0 - - WP_VERSION=3.7 WP_MULTISITE=0 - - WP_VERSION=4.7-alpha-38178-src WP_MULTISITE=0 +notifications: + email: false matrix: + # - Lint PHP once per PHP version. + # + # - Run `phpunit` for each version of PHP and WordPress in single- and multisite. + # + # - Run `qunit:recent` once. The `recent` task handles running tests against + # different versions of WordPress. If we switch to WP_VERSION=x.y.z we could + # instead run `qunit:specific --wp=$WP_VERSION` so that control over which + # versions are tested stays in this config. include: - php: 5.3 - env: WP_VERSION=latest WP_MULTISITE=1 + env: WP_VERSION=latest PHP_LINT=1 + + - php: 5.6 + env: WP_VERSION=latest PHP_LINT=1 + + - php: 7.0 + env: WP_VERSION=trunk QUNIT_RECENT=1 + - php: 7.0 + env: WP_VERSION=latest PHP_LINT=1 + + - php: 7.1 + env: WP_VERSION=latest PHP_LINT=1 before_script: + - export PATH="$HOME/.composer/vendor/bin:$PATH" + - export WP_CORE_DIR=/tmp/wordpress + + - | + if [[ ${TRAVIS_PHP_VERSION:0:2} == "7." ]]; then + composer global require "phpunit/phpunit=5.7.*" + else + composer global require "phpunit/phpunit=4.8.*" + fi + - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION -script: phpunit + - git clone --depth=1 https://github.com/alleyinteractive/wordpress-fieldmanager $WP_CORE_DIR/wp-content/plugins/wordpress-fieldmanager + + - | + if [[ "$QUNIT_RECENT" == "1" ]]; then + npm install + fi + +script: + - | + if [[ "$PHP_LINT" == "1" ]]; then + find . -type "f" -iname "*.php" | xargs -L "1" php -l + fi + + - | + if [[ "$QUNIT_RECENT" == "1" ]]; then + grunt qunit:recent + fi + + - export WP_MULTISITE=0 && phpunit + - export WP_MULTISITE=1 && phpunit diff --git a/Gruntfile.js b/Gruntfile.js index b16448a..ef15c70 100755 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,10 +1,10 @@ module.exports = function( grunt ) { - 'use strict'; + var banner = '/**\n * <%= pkg.homepage %>\n * Copyright (c) <%= grunt.template.today("yyyy") %>\n * This file is generated automatically. Do not edit.\n */\n'; + // Project configuration grunt.initConfig( { - pkg: grunt.file.readJSON( 'package.json' ), addtextdomain: { @@ -18,15 +18,12 @@ module.exports = function( grunt ) { } }, - wp_readme_to_markdown: { - options: { - screenshot_url: './assets/{screenshot}.png', - }, - your_target: { - files: { - 'README.md': 'readme.txt' + connect: { + server: { + options: { + base: '.' } - }, + } }, makepot: { @@ -44,14 +41,53 @@ module.exports = function( grunt ) { } } }, + + qunit: { + trunk: { + options: { + urls: ['http://localhost:8000/tests/js/index.html'] + } + }, + recent: { + options: { + urls: [ + 'http://localhost:8000/tests/js/index.html', + 'http://localhost:8000/tests/js/index.html?wp=4.7', + 'http://localhost:8000/tests/js/index.html?wp=4.6', + ] + } + }, + specific: { + options: { + urls: [ 'http://localhost:8000/tests/js/index.html?wp=' + grunt.option( 'wp' ) ] + } + } + }, + + wp_readme_to_markdown: { + options: { + screenshot_url: './assets/{screenshot}.png', + }, + your_target: { + files: { + 'README.md': 'readme.txt' + } + }, + }, } ); + grunt.loadNpmTasks( 'grunt-contrib-connect' ); + grunt.loadNpmTasks( 'grunt-contrib-qunit' ); grunt.loadNpmTasks( 'grunt-wp-i18n' ); grunt.loadNpmTasks( 'grunt-wp-readme-to-markdown' ); + + if ( /(qunit|prerelease)/.test( grunt.cli.tasks.join( '' ).toLowerCase() ) ) { + grunt.task.run( 'connect' ); + } + grunt.registerTask( 'i18n', [ 'addtextdomain', 'makepot' ] ); grunt.registerTask( 'readme', [ 'wp_readme_to_markdown' ] ); - grunt.registerTask( 'prerelease', [ 'i18n', 'readme' ] ); + grunt.registerTask( 'prerelease', [ 'qunit:recent', 'i18n', 'readme' ] ); grunt.util.linefeed = '\n'; - }; diff --git a/README.md b/README.md index e2a3b0b..de392b7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Fieldmanager Beta: Customize # **Contributors:** [dlh](https://profiles.wordpress.org/dlh), [jamesburke](https://profiles.wordpress.org/jamesburke), [alleyinteractive](https://profiles.wordpress.org/alleyinteractive) -**Requires at least:** 4.4 +**Requires at least:** 4.5 **Tested up to:** 4.7 -**Stable tag:** 0.3.1 +**Stable tag:** 0.4.0 **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html @@ -12,7 +12,7 @@ A Fieldmanager Beta plugin for the Customize Context. This is a proposed Customize context for Fieldmanager. You can install the plugin alongside a stable Fieldmanager release to help test and refine the context. -The official Pull Request for this context, plus tests, is [on GitHub](https://github.com/alleyinteractive/wordpress-fieldmanager/pull/399). +The official Pull Request for this context is [on GitHub](https://github.com/alleyinteractive/wordpress-fieldmanager/pull/399). ## Installation ## @@ -41,6 +41,13 @@ For more code examples, browse `php/demos/class-fieldmanager-beta-customize-demo ## Changelog ## +### 0.4.0 ### +* Added: PHP and JavaScript tests. +* Added: Demo a field with selective-refresh support. +* Changed: Use better TinyMCE events for tracking `Fieldmanager_RichTextArea` changes. +* Changed: Require at least WordPress 4.5. +* Fixed: Fix a case where invisible Customizer sections could be created. + ### 0.3.1 ### * Fixed: Track the changes to instances of repeatable RichTextAreas and Colorpickers added after loading the Customizer. diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh index cf709c2..73bb4c7 100755 --- a/bin/install-wp-tests.sh +++ b/bin/install-wp-tests.sh @@ -80,6 +80,7 @@ install_test_suite() { # set up testing suite mkdir -p $WP_TESTS_DIR svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data fi if [ ! -f wp-tests-config.php ]; then diff --git a/fieldmanager-beta-customize.php b/fieldmanager-beta-customize.php index 5f6ae55..f0624cf 100755 --- a/fieldmanager-beta-customize.php +++ b/fieldmanager-beta-customize.php @@ -7,7 +7,7 @@ * Author URI: https://www.alleyinteractive.com * Text Domain: fieldmanager-beta-customizer * Domain Path: /languages - * Version: 0.3.1 + * Version: 0.4.0 * * @package Fieldmanager_Beta_Customize */ @@ -25,7 +25,19 @@ /** * Plugin version. */ -define( 'FM_BETA_CUSTOMIZE_VERSION', '0.3.1' ); +define( 'FM_BETA_CUSTOMIZE_VERSION', '0.4.0' ); + +/** + * Load plugin class files. + * + * @since 0.4.0 + */ +function fm_beta_customize_load_plugin_classes() { + require_once( FM_BETA_CUSTOMIZE_PATH . 'php/context/class-fieldmanager-beta-context-customize.php' ); + require_once( FM_BETA_CUSTOMIZE_PATH . 'php/customize/class-fieldmanager-beta-customize-control.php' ); + require_once( FM_BETA_CUSTOMIZE_PATH . 'php/customize/class-fieldmanager-beta-customize-setting.php' ); + require_once( FM_BETA_CUSTOMIZE_PATH . 'php/field/class-fieldmanager-beta-customize-richtextarea.php' ); +} /** * Calculate a Fieldmanager context for the Customizer. @@ -50,13 +62,7 @@ * We aren't registering an autoloader because if Fieldmanager core's autoloader * is registered first, and it doesn't find a file, it throws an exception. */ -add_action( 'fm_beta_customize', function () { - require_once( FM_BETA_CUSTOMIZE_PATH . 'php/context/class-fieldmanager-beta-context-customize.php' ); - require_once( FM_BETA_CUSTOMIZE_PATH . 'php/customize/class-fieldmanager-beta-customize-control.php' ); - require_once( FM_BETA_CUSTOMIZE_PATH . 'php/customize/class-fieldmanager-beta-customize-setting.php' ); - require_once( FM_BETA_CUSTOMIZE_PATH . 'php/demo/class-fieldmanager-beta-customize-demo.php' ); - require_once( FM_BETA_CUSTOMIZE_PATH . 'php/field/class-fieldmanager-beta-customize-richtextarea.php' ); -}, 0 ); +add_action( 'fm_beta_customize', 'fm_beta_customize_load_plugin_classes', 0 ); /** * Enqueue assets managed by Fieldmanager_Util_Assets in the Customizer. @@ -130,5 +136,6 @@ function fm_beta_customize_add_to_customizer( $args = array(), $fm ) { * Instantiate the bundled context demos. */ function fm_beta_customize_demo() { + require_once( FM_BETA_CUSTOMIZE_PATH . 'php/demo/class-fieldmanager-beta-customize-demo.php' ); Fieldmanager_Beta_Customize_Demo::instance(); } diff --git a/js/fieldmanager-beta-customize-overrides.js b/js/fieldmanager-beta-customize-overrides.js index 0df7758..00142d5 100644 --- a/js/fieldmanager-beta-customize-overrides.js +++ b/js/fieldmanager-beta-customize-overrides.js @@ -70,12 +70,12 @@ // Respond to RichTextArea changes. $( document ).on( 'tinymce-editor-init', function ( event, editor ) { - var editor_element = document.getElementById( editor.id ); + var editorElement = document.getElementById( editor.id ); - if ( editor_element && editor_element.classList.contains( 'fm-richtext' ) ) { - editor.on( 'keyup AddUndo SetContent', function () { + if ( editorElement && editorElement.classList.contains( 'fm-richtext' ) ) { + editor.on( 'input change keyup', function () { editor.save(); - fm.beta.customize.setControlsContainingElement( editor_element ); + fm.beta.customize.setControlsContainingElement( editorElement ); }); } }); diff --git a/js/fieldmanager-beta-customize.js b/js/fieldmanager-beta-customize.js index fd5e78d..da71e3d 100644 --- a/js/fieldmanager-beta-customize.js +++ b/js/fieldmanager-beta-customize.js @@ -49,6 +49,14 @@ /** * Set a Fieldmanager setting to its control's form values. * + * Updates to fields are generally not debounced or throttled because + * these create FM-specific deviations to how users experience the + * Customizer and add maintenance requirements for the plugin. + * + * Without debouncing or throttling, changes to settings using the + * `postMessage` transport are faster. The Customizer's refresh + * framework also debounces natively. + * * @param {Object} control Customizer Control object. * @return {Object} The updated Control. */ diff --git a/languages/fieldmanager-beta-customize.pot b/languages/fieldmanager-beta-customize.pot index 78b8d25..4fb66cb 100644 --- a/languages/fieldmanager-beta-customize.pot +++ b/languages/fieldmanager-beta-customize.pot @@ -2,10 +2,10 @@ # This file is distributed under the same license as the Fieldmanager Beta: Customize package. msgid "" msgstr "" -"Project-Id-Version: Fieldmanager Beta: Customize 0.3.1\n" +"Project-Id-Version: Fieldmanager Beta: Customize 0.4.0\n" "Report-Msgid-Bugs-To: " "https://wordpress.org/support/plugin/fieldmanager-beta-customize\n" -"POT-Creation-Date: 2017-01-22 00:22:27+00:00\n" +"POT-Creation-Date: 2017-03-23 03:56:54+00:00\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -25,7 +25,7 @@ msgstr "" "X-Poedit-Bookmarks: \n" "X-Textdomain-Support: yes\n" -#: php/context/class-fieldmanager-beta-context-customize.php:90 +#: php/context/class-fieldmanager-beta-context-customize.php:89 msgid "Invalid value." msgstr "" @@ -41,22 +41,30 @@ msgid "" "Fieldmanager_Beta_Context_Customize" msgstr "" -#: php/demo/class-fieldmanager-beta-customize-demo.php:87 +#: php/demo/class-fieldmanager-beta-customize-demo.php:116 msgid "Twitter Handle" msgstr "" -#: php/demo/class-fieldmanager-beta-customize-demo.php:88 +#: php/demo/class-fieldmanager-beta-customize-demo.php:117 msgid "Facebook URL" msgstr "" -#: php/demo/class-fieldmanager-beta-customize-demo.php:89 +#: php/demo/class-fieldmanager-beta-customize-demo.php:118 msgid "Instagram Handle" msgstr "" -#: php/demo/class-fieldmanager-beta-customize-demo.php:90 +#: php/demo/class-fieldmanager-beta-customize-demo.php:119 msgid "YouTube URL" msgstr "" +#: tests/php/test-fieldmanager-beta-context-customize.php:189 +msgid "Failed with $debug = true" +msgstr "" + +#: tests/php/test-fieldmanager-beta-context-customize.php:189 +msgid "Failed with $debug = false" +msgstr "" + #. Plugin Name of the plugin/theme msgid "Fieldmanager Beta: Customize" msgstr "" diff --git a/package.json b/package.json index f6e03ac..0d64ab7 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fieldmanager-beta-customize", - "version": "0.1.0", + "version": "0.4.0", "main": "Gruntfile.js", "contributors": [ "David Herrera", @@ -8,8 +8,11 @@ "Alley Interactive" ], "devDependencies": { - "grunt": "~0.4.5", + "grunt": "~1.0.0", + "grunt-contrib-connect": "~1.0.0", + "grunt-contrib-qunit": "~1.3.0", "grunt-wp-i18n": "~0.5.0", - "grunt-wp-readme-to-markdown": "~2.0.0" + "grunt-wp-readme-to-markdown": "~2.0.0", + "qunitjs": "^2.1.1" } } diff --git a/php/context/class-fieldmanager-beta-context-customize.php b/php/context/class-fieldmanager-beta-context-customize.php index 4353e94..9b17330 100644 --- a/php/context/class-fieldmanager-beta-context-customize.php +++ b/php/context/class-fieldmanager-beta-context-customize.php @@ -13,8 +13,7 @@ class Fieldmanager_Beta_Context_Customize extends Fieldmanager_Context { * Arguments to construct Customizer objects. * * @var array $args { - * @type array|bool $section_args Arguments for constructing a {@see WP_Customize_Section}, - * or false to not create one for this context. + * @type array $section_args Arguments for constructing a {@see WP_Customize_Section}. * @type array $setting_args Arguments for constructing a {@see Fieldmanager_Beta_Customize_Setting}. * @type array $control_args Arguments for constructing a {@see Fieldmanager_Beta_Customize_Control}. * } @@ -29,7 +28,7 @@ class Fieldmanager_Beta_Context_Customize extends Fieldmanager_Context { */ public function __construct( $args, $fm ) { $this->args = wp_parse_args( $args, array( - 'section_args' => false, + 'section_args' => array(), 'setting_args' => array(), 'control_args' => array(), ) ); @@ -187,11 +186,14 @@ protected function register( $manager ) { /** * Add a Customizer section for this field. * + * @since 0.4.0 Does not create a section when the context's $args['section_args'] is an + * empty array. In practice, a Customizer section requires at least a title. + * * @param WP_Customize_Manager $manager WP_Customize_Manager instance. * @return WP_Customize_Section|void Section object, where supported, if created. */ protected function register_section( $manager ) { - if ( false === $this->args['section_args'] ) { + if ( ! $this->args['section_args'] ) { return; } diff --git a/php/demo/class-fieldmanager-beta-customize-demo.php b/php/demo/class-fieldmanager-beta-customize-demo.php index 6458717..d262381 100644 --- a/php/demo/class-fieldmanager-beta-customize-demo.php +++ b/php/demo/class-fieldmanager-beta-customize-demo.php @@ -33,21 +33,50 @@ public static function instance() { * Set up. */ public function setup() { + add_action( 'customize_register', array( $this, 'add_partial' ) ); add_action( 'fm_beta_customize', array( $this, 'customizer_init' ), 1000 ); } + /** + * Register a demo selective-refresh partial. + */ + public function add_partial( $wp_customize ) { + if ( empty( $wp_customize->selective_refresh ) ) { + return; + } + + $wp_customize->selective_refresh->add_partial( 'basic_partial', array( + 'selector' => '#fm-demo-customizer-basic-partial', + 'settings' => array( 'basic_partial' ), + 'render_callback' => array( $this, 'get_basic_partial' ), + ) ); + } + + /** + * Render callback for basic_partial. + */ + public function get_basic_partial() { + return get_option( 'basic_partial' ); + } + /** * Initialize demos. */ public function customizer_init() { - $fm = new Fieldmanager_Textfield( array( 'name' => 'basic_text' ) ); + $fm = new Fieldmanager_Textfield( 'Text Field', array( 'name' => 'basic_text' ) ); fm_beta_customize_add_to_customizer( array( 'section_args' => array( 'priority' => 10, - 'title' => 'Fieldmanager Text Field', + 'title' => 'Fieldmanager Text Fields', ), ), $fm ); + $fm = new Fieldmanager_TextField( 'Text Field with Selective Refresh', array( 'name' => 'basic_partial' ) ); + fm_beta_customize_add_to_customizer( array( + 'control_args' => array( 'section' => 'basic_text' ), + 'setting_args' => array( 'transport' => 'postMessage' ), + ), $fm ); + $fm = new Fieldmanager_Group( array( 'name' => 'option_fields', 'children' => array( @@ -185,6 +214,11 @@ public function wp_footer() {

The values you see below are controlled by "Fieldmanager Text Field" and "Fieldmanager Group" sections in the Customizer. Try changing them to see the results.