├── .editorconfig ├── .gitignore ├── Gruntfile.coffee ├── assets └── README.md ├── bin └── install-wp-tests.sh ├── classes └── plugin.php ├── images ├── README.md └── src │ └── README.md ├── languages └── wp-feature-better-passwords.pot ├── lib ├── requirements-check.php └── wp-stack-plugin.php ├── package.json ├── readme.md ├── tmpl └── fields.php └── wp-feature-better-passwords.php /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | # WordPress Coding Standards 5 | # http://make.wordpress.org/core/handbook/coding-standards/ 6 | 7 | root = true 8 | 9 | [*] 10 | charset = utf-8 11 | end_of_line = lf 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | indent_style = tab 15 | 16 | [{.jshintrc,*.json,*.yml}] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [{*.txt,wp-config-sample.php}] 21 | end_of_line = crlf 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /node_modules 3 | /release 4 | /js/*.js 5 | /js/*.map 6 | !/js/*.min.js 7 | !/js/*.min.js.map -------------------------------------------------------------------------------- /Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (grunt) -> 2 | 3 | # Project configuration 4 | grunt.initConfig 5 | pkg: grunt.file.readJSON('package.json') 6 | 7 | wp_deploy: 8 | default: 9 | options: 10 | plugin_slug: '<%= pkg.name %>' 11 | build_dir: 'release/svn/' 12 | assets_dir: 'assets/' 13 | 14 | clean: 15 | release: [ 16 | 'release/<%= pkg.version %>/' 17 | 'release/svn/' 18 | ] 19 | svn_readme_md: [ 20 | 'release/svn/readme.md' 21 | ] 22 | 23 | copy: 24 | main: 25 | src: [ 26 | '**' 27 | '!node_modules/**' 28 | '!release/**' 29 | '!assets/**' 30 | '!.git/**' 31 | '!img/src/**' 32 | '!Gruntfile.*' 33 | '!package.json' 34 | '!.gitignore' 35 | '!.gitmodules' 36 | '!bin/**' 37 | ] 38 | dest: 'release/<%= pkg.version %>/' 39 | svn: 40 | cwd: 'release/<%= pkg.version %>/' 41 | expand: yes 42 | src: '**' 43 | dest: 'release/svn/' 44 | 45 | replace: 46 | header: 47 | src: [ '<%= pkg.name %>.php' ] 48 | overwrite: yes 49 | replacements: [ 50 | from: /^Version:(\s*?)[\w.-]+$/m 51 | to: 'Version: <%= pkg.version %>' 52 | ] 53 | plugin: 54 | src: [ 'classes/plugin.php' ] 55 | overwrite: yes 56 | replacements: [ 57 | from: /^(\s*?)const(\s+?)VERSION(\s*?)=(\s+?)'[^']+';/m 58 | to: "$1const$2VERSION$3=$4'<%= pkg.version %>';" 59 | , 60 | from: /^(\s*?)const(\s+?)CSS_JS_VERSION(\s*?)=(\s+?)'[^']+';/m 61 | to: "$1const$2CSS_JS_VERSION$3=$4'<%= pkg.version %>';" 62 | ] 63 | svn_readme: 64 | src: [ 'release/svn/readme.md' ] 65 | dest: 'release/svn/readme.txt' 66 | replacements: [ 67 | from: /^# (.*?)( #+)?$/mg 68 | to: '=== $1 ===' 69 | , 70 | from: /^## (.*?)( #+)?$/mg 71 | to: '== $1 ==' 72 | , 73 | from: /^### (.*?)( #+)?$/mg 74 | to: '= $1 =' 75 | , 76 | from: /^Stable tag:\s*?[\w.-]+(\s*?)$/mi 77 | to: 'Stable tag: <%= pkg.version %>$1' 78 | ] 79 | 80 | compress: 81 | default: 82 | options: 83 | mode: 'zip' 84 | archive: './release/<%= pkg.name %>.<%= pkg.version %>.zip' 85 | expand: yes 86 | cwd: 'release/<%= pkg.version %>/' 87 | src: [ '**/*' ] 88 | dest: '<%= pkg.name %>/' 89 | 90 | # Load other tasks 91 | grunt.loadNpmTasks 'grunt-contrib-concat' 92 | grunt.loadNpmTasks 'grunt-contrib-clean' 93 | grunt.loadNpmTasks 'grunt-contrib-copy' 94 | grunt.loadNpmTasks 'grunt-contrib-compress' 95 | grunt.loadNpmTasks 'grunt-text-replace' 96 | grunt.loadNpmTasks 'grunt-wp-deploy' 97 | 98 | # Default task 99 | grunt.registerTask 'default', [ 100 | 'replace:header' 101 | 'replace:plugin' 102 | ] 103 | 104 | # Build task 105 | grunt.registerTask 'build', [ 106 | 'default' 107 | 'clean' 108 | 'copy:main' 109 | 'compress' # Can comment this out for WordPress.org plugins 110 | ] 111 | 112 | # Prepare a WordPress.org release 113 | grunt.registerTask 'release:prepare', [ 114 | 'build' 115 | 'copy:svn' 116 | 'replace:svn_readme' 117 | 'clean:svn_readme_md' 118 | ] 119 | 120 | # Deploy out a WordPress.org release 121 | grunt.registerTask 'release:deploy', [ 122 | 'wp_deploy' 123 | ] 124 | 125 | # WordPress.org release task 126 | grunt.registerTask 'release', [ 127 | 'release:prepare' 128 | 'release:deploy' 129 | ] 130 | 131 | grunt.util.linefeed = '\n' 132 | 133 | -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | # Assets directory 2 | 3 | This directory is for WordPress.org plugins. 4 | 5 | Put in two files: 6 | 7 | * `banner-1544x500.png` or `banner-1544x500.png` 8 | * `banner-772x250.png` or `banner-772x250.jpg` 9 | -------------------------------------------------------------------------------- /bin/install-wp-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ $# -lt 3 ]; then 4 | echo "usage: $0 [db-host] [wp-version]" 5 | exit 1 6 | fi 7 | 8 | DB_NAME=$1 9 | DB_USER=$2 10 | DB_PASS=$3 11 | DB_HOST=${4-localhost} 12 | WP_VERSION=${5-latest} 13 | 14 | WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} 15 | WP_CORE_DIR=/tmp/wordpress/ 16 | 17 | set -ex 18 | 19 | install_wp() { 20 | mkdir -p $WP_CORE_DIR 21 | 22 | if [ $WP_VERSION == 'latest' ]; then 23 | local ARCHIVE_URL='https://github.com/WordPress/WordPress/archive/master.tar.gz' 24 | else 25 | local ARCHIVE_NAME="wordpress-$WP_VERSION" 26 | local ARCHIVE_URL="http://wordpress.org/${ARCHIVE_NAME}.tar.gz" 27 | fi 28 | 29 | wget -nv -O /tmp/wordpress.tar.gz $ARCHIVE_URL 30 | tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR 31 | 32 | wget -nv -O $WP_CORE_DIR/wp-content/db.php https://raw.github.com/markoheijnen/wp-mysqli/master/db.php 33 | } 34 | 35 | install_test_suite() { 36 | # portable in-place argument for both GNU sed and Mac OSX sed 37 | if [[ $(uname -s) == 'Darwin' ]]; then 38 | local ioption='-i .bak' 39 | else 40 | local ioption='-i' 41 | fi 42 | 43 | # set up testing suite 44 | mkdir -p $WP_TESTS_DIR 45 | cd $WP_TESTS_DIR 46 | svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/ 47 | 48 | wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php 49 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php 50 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" wp-tests-config.php 51 | sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php 52 | sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php 53 | sed $ioption "s|localhost|${DB_HOST}|" wp-tests-config.php 54 | } 55 | 56 | install_db() { 57 | # parse DB_HOST for port or socket references 58 | local PARTS=(${DB_HOST//\:/ }) 59 | local DB_HOSTNAME=${PARTS[0]}; 60 | local DB_SOCK_OR_PORT=${PARTS[1]}; 61 | local EXTRA="" 62 | 63 | if ! [ -z $DB_HOSTNAME ] ; then 64 | if [[ "$DB_SOCK_OR_PORT" =~ ^[0-9]+$ ]] ; then 65 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" 66 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then 67 | EXTRA=" --socket=$DB_SOCK_OR_PORT" 68 | elif ! [ -z $DB_HOSTNAME ] ; then 69 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" 70 | fi 71 | fi 72 | 73 | # create database 74 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA 75 | } 76 | 77 | install_wp 78 | install_test_suite 79 | install_db 80 | -------------------------------------------------------------------------------- /classes/plugin.php: -------------------------------------------------------------------------------- 1 | hook( 'plugins_loaded', 'add_hooks' ); 13 | } 14 | 15 | /** 16 | * Adds hooks 17 | */ 18 | public function add_hooks() { 19 | $this->hook( 'init' ); 20 | $this->hook( 'show_password_fields' ); 21 | $this->hook( '__temp_password_field', 'password_field' ); 22 | } 23 | 24 | 25 | public function show_password_fields( $show, $profile_user = null ) { 26 | if ( $profile_user ) { 27 | return false; 28 | } else { 29 | return $show; 30 | } 31 | } 32 | 33 | public function password_field() { 34 | $this->include_file( 'tmpl/fields.php' ); 35 | } 36 | /** 37 | * Initializes the plugin, registers textdomain, etc 38 | */ 39 | public function init() { 40 | $this->load_textdomain( 'wp-feature-better-passwords', '/languages' ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /images/README.md: -------------------------------------------------------------------------------- 1 | # Project Images 2 | 3 | Only images in use by the project should be placed in this folder. Wherever possible, combine multiple small images into sprites to be used by CSS. Original (non-sprite) images should be placed in the `/src` subdirectory. -------------------------------------------------------------------------------- /images/src/README.md: -------------------------------------------------------------------------------- 1 | # Project Images 2 | 3 | Only source images (i.e. non-sprites, PSDs, raw photos) should be placed in this directory. Source files are meant to serve as a backup for any images that can be edited by an end user. -------------------------------------------------------------------------------- /languages/wp-feature-better-passwords.pot: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: WP Feature Better Passwords\n" 4 | "POT-Creation-Date: 2015-05-27 15:41-0400\n" 5 | "PO-Revision-Date: 2015-05-27 15:41-0400\n" 6 | "Last-Translator: Mark Jaquith \n" 7 | "Language-Team: \n" 8 | "MIME-Version: 1.0\n" 9 | "Content-Type: text/plain; charset=UTF-8\n" 10 | "Content-Transfer-Encoding: 8bit\n" 11 | "X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;" 12 | "_n_noop:1,2;_x:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;_ex:1,2c;" 13 | "esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c\n" 14 | "X-Poedit-Basepath: .\n" 15 | "X-Poedit-SearchPath-0: ..\n" 16 | 17 | -------------------------------------------------------------------------------- /lib/requirements-check.php: -------------------------------------------------------------------------------- 1 | $setting = $args[$setting]; 13 | } 14 | } 15 | } 16 | 17 | public function passes() { 18 | $passes = $this->php_passes() && $this->wp_passes(); 19 | if ( ! $passes ) { 20 | add_action( 'admin_notices', array( $this, 'deactivate' ) ); 21 | } 22 | return $passes; 23 | } 24 | 25 | public function deactivate() { 26 | if ( isset( $this->file ) ) { 27 | deactivate_plugins( plugin_basename( $this->file ) ); 28 | } 29 | } 30 | 31 | private function php_passes() { 32 | if ( $this->__php_at_least( $this->php ) ) { 33 | return true; 34 | } else { 35 | add_action( 'admin_notices', array( $this, 'php_version_notice' ) ); 36 | return false; 37 | } 38 | } 39 | 40 | private static function __php_at_least( $min_version ) { 41 | return version_compare( phpversion(), $min_version, '>=' ); 42 | } 43 | 44 | public function php_version_notice() { 45 | echo '
'; 46 | echo "

The “" . esc_html( $this->title ) . "” plugin cannot run on PHP versions older than " . $this->php . '. Please contact your host and ask them to upgrade.

'; 47 | echo '
'; 48 | } 49 | 50 | private function wp_passes() { 51 | if ( $this->__wp_at_least( $this->wp ) ) { 52 | return true; 53 | } else { 54 | add_action( 'admin_notices', array( $this, 'wp_version_notice' ) ); 55 | return false; 56 | } 57 | } 58 | 59 | private static function __wp_at_least( $min_version ) { 60 | return version_compare( get_bloginfo( 'version' ), $min_version, '>=' ); 61 | } 62 | 63 | public function wp_version_notice() { 64 | echo '
'; 65 | echo "

The “" . esc_html( $this->title ) . "” plugin cannot run on WordPress versions older than " . $this->wp . '. Please update WordPress.

'; 66 | echo '
'; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/wp-stack-plugin.php: -------------------------------------------------------------------------------- 1 | __FILE__ = $__FILE__; 25 | } 26 | return static::get_instance(); 27 | } 28 | 29 | /** 30 | * Returns the plugin's object instance 31 | * 32 | * @return object the plugin object instance 33 | */ 34 | public static function get_instance() { 35 | if ( isset( static::$instance ) ) { 36 | return static::$instance; 37 | } 38 | } 39 | 40 | /** 41 | * Add a WordPress hook (action/filter) 42 | * 43 | * @param mixed $hook,... first parameter is the name of the hook. If second or third parameters are included, they will be used as a priority (if an integer) or as a class method callback name (if a string) 44 | */ 45 | public function hook( $hook ) { 46 | $priority = 10; 47 | $method = $this->sanitize_method( $hook ); 48 | $args = func_get_args(); 49 | unset( $args[0] ); 50 | foreach( (array) $args as $arg ) { 51 | if ( is_int( $arg ) ) 52 | $priority = $arg; 53 | else 54 | $method = $arg; 55 | } 56 | return add_action( $hook, array( $this, $method ), $priority, 999 ); 57 | } 58 | 59 | private function sanitize_method( $method ) { 60 | return str_replace( array( '.', '-' ), array( '_DOT_', '_DASH_' ), $method ); 61 | } 62 | 63 | /** 64 | * Includes a file (relative to the plugin base path) 65 | * and optionally globalizes a named array passed in 66 | * 67 | * @param string $file the file to include 68 | * @param array $data a named array of data to globalize 69 | */ 70 | protected function include_file( $file, $data = array() ) { 71 | extract( $data, EXTR_SKIP ); 72 | include( $this->get_path() . $file ); 73 | } 74 | 75 | /** 76 | * Returns the URL to the plugin directory 77 | * 78 | * @return string the URL to the plugin directory 79 | */ 80 | public function get_url() { 81 | return plugin_dir_url( $this->__FILE__ ); 82 | } 83 | 84 | /** 85 | * Returns the path to the plugin directory 86 | * 87 | * @return string the absolute path to the plugin directory 88 | */ 89 | public function get_path() { 90 | return plugin_dir_path( $this->__FILE__ ); 91 | } 92 | 93 | public function load_textdomain( $name, $path ) { 94 | return load_plugin_textdomain( $name, false, basename( dirname( $this->__FILE__ ) ) . $path ); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wp-feature-better-passwords", 3 | "title": "WP Feature Better Passwords", 4 | "description": "Improves the password changing UI in WorddPress", 5 | "version": "0.1.0", 6 | "homepage": "", 7 | "author": { 8 | "name": "Mark Jaquith", 9 | "email": "mark@jaquith.me" 10 | }, 11 | "devDependencies": { 12 | "grunt": "~0.4.5", 13 | "grunt-contrib-concat": "~0.5.0", 14 | "grunt-contrib-coffee": "~0.13.0", 15 | "grunt-coffeelint": "~0.0.13", 16 | "grunt-contrib-uglify": "~0.6.0", 17 | "grunt-contrib-compass": "~1.0.1", 18 | "grunt-contrib-jshint": "~0.10.0", 19 | "grunt-contrib-nodeunit": "~0.4.1", 20 | "grunt-contrib-watch": "~0.6.1", 21 | "grunt-contrib-clean": "~0.6.0", 22 | "grunt-contrib-copy": "~0.7.0", 23 | "grunt-contrib-compress": "~0.12.0", 24 | "grunt-text-replace": "~0.4.0", 25 | "grunt-phpunit": "~0.3.6", 26 | "grunt-wp-deploy": "~1.0.3", 27 | "coffeelint": "^1" 28 | }, 29 | "keywords": [] 30 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # WP Feature Better Passwords # 2 | 3 | Contributors: markjaquith 4 | Tags: 5 | Requires at least: 4.3 6 | Tested up to: 4.3 7 | Stable tag: 0.1.0 8 | License: GPLv2 or later 9 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 10 | 11 | Improves the password changing UI in WordPress 12 | 13 | ## Description ## 14 | 15 | ## Installation ## 16 | 17 | ### Manual Installation ### 18 | 19 | 1. Upload the entire `/wp-feature-better-passwords` directory to the `/wp-content/plugins/` directory. 20 | 2. Activate WP Feature Better Passwords through the 'Plugins' menu in WordPress. 21 | 22 | ## Frequently Asked Questions ## 23 | 24 | ### Question ### 25 | 26 | Answer 27 | 28 | ## Screenshots ## 29 | 30 | 1. Description of first screenshot 31 | 32 | ## Contribute ## 33 | 34 | Here is how you can contribute: 35 | 36 | ## Changelog ## 37 | 38 | ### 0.1 ### 39 | * First release 40 | 41 | ## Upgrade Notice ## 42 | 43 | ### 0.1.0 ### 44 | First release 45 | -------------------------------------------------------------------------------- /tmpl/fields.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 77 | 78 | 113 | 114 | 115 | 116 | 117 | 118 | 119 |
120 | 124 | 125 |
126 | 127 | 128 | 129 | 130 | 131 | 132 |

133 | 134 | 135 | -------------------------------------------------------------------------------- /wp-feature-better-passwords.php: -------------------------------------------------------------------------------- 1 | 'WP Feature Better Passwords', 42 | 'php' => '5.3', 43 | 'wp' => '4.2.9999', 44 | 'file' => __FILE__, 45 | )); 46 | 47 | if ( $wp_feature_better_passwords_requirements_check->passes() ) { 48 | // Pull in the plugin classes and initialize 49 | include( dirname( __FILE__ ) . '/lib/wp-stack-plugin.php' ); 50 | include( dirname( __FILE__ ) . '/classes/plugin.php' ); 51 | WP_Feature_Better_Passwords_Plugin::start( __FILE__ ); 52 | } 53 | 54 | unset( $wp_feature_better_passwords_requirements_check ); 55 | --------------------------------------------------------------------------------