diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml deleted file mode 100644 index 7378254..0000000 --- a/.github/workflows/unit-test.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Testing Suite - -on: - push: - branches: - - develop - pull_request: - schedule: - - cron: '0 0 * * *' - -jobs: - php-tests: - strategy: - matrix: - php: [8.0, 8.1] - wordpress: ["latest"] - uses: alleyinteractive/.github/.github/workflows/php-tests.yml@main - with: - php: ${{ matrix.php }} - wordpress: ${{ matrix.wordpress }} diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml deleted file mode 100644 index b20f3b6..0000000 --- a/.github/workflows/update-changelog.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: "Update Changelog" - -on: - release: - types: [released] - -jobs: - update: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - with: - ref: main - - - name: Update Changelog - uses: stefanzweifel/changelog-updater-action@v1 - with: - latest-version: ${{ github.event.release.name }} - release-notes: ${{ github.event.release.body }} - - - name: Commit updated CHANGELOG - uses: stefanzweifel/git-auto-commit-action@v4 - with: - branch: main - commit_message: Update CHANGELOG - file_pattern: CHANGELOG.md diff --git a/.github/workflows/upgrade-wordpress-plugin.yml b/.github/workflows/upgrade-wordpress-plugin.yml deleted file mode 100644 index ba41962..0000000 --- a/.github/workflows/upgrade-wordpress-plugin.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Update WordPress Plugin - -on: - schedule: - - cron: '0 */6 * * *' - -permissions: - contents: write - pull-requests: write - -jobs: - update-plugin: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: alleyinteractive/action-update-wordpress-plugin@v1.2.1 - with: - plugin-file: 'wp-environment-switcher.php' - upgrade-npm-dependencies: "true" diff --git a/.phpcs.xml b/.phpcs.xml index cf85b94..080e971 100644 --- a/.phpcs.xml +++ b/.phpcs.xml @@ -38,6 +38,7 @@ + diff --git a/README.md b/README.md index 525ff9f..eba1553 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,14 @@ # WordPress Environment Switcher -Contributors: srtfisher - -Tags: alleyinteractive, wp-environment-switcher - -Stable tag: 0.1.0 - -Requires at least: 5.9 - -Tested up to: 6.1 - -Requires PHP: 8.0 - -License: GPL v2 or later - [![Coding Standards](https://github.com/alleyinteractive/wp-environment-switcher/actions/workflows/coding-standards.yml/badge.svg)](https://github.com/alleyinteractive/wp-environment-switcher/actions/workflows/coding-standards.yml) -[![Testing Suite](https://github.com/alleyinteractive/wp-environment-switcher/actions/workflows/unit-test.yml/badge.svg)](https://github.com/alleyinteractive/wp-environment-switcher/actions/workflows/unit-test.yml) -Easily switch between different site environments from the WordPress admin bar.. +Easily switch between different site environments from the WordPress admin bar. + +> Props to [WordPress Stage Switcher](https://github.com/roots/wp-stage-switcher) for the inspiration. ## Installation -You can install the package via composer: +You can install the package via Composer: ```bash composer require alleyinteractive/wp-environment-switcher @@ -29,60 +16,29 @@ composer require alleyinteractive/wp-environment-switcher ## Usage -Activate the plugin in WordPress and use it like so: - -```php -$plugin = Alley\WP\WordPress_Environment_Switcher\WordPress_Environment_Switcher\WordPress_Environment_Switcher(); -$plugin->perform_magic(); -``` - -## Testing - -Run `npm run test` to run Jest tests against JavaScript files. Run -`npm run test:watch` to keep the test runner open and watching for changes. - -Run `npm run lint` to run ESLint against all JavaScript files. Linting will also -happen when running development or production builds. +Activate the plugin in WordPress and you will see the switcher appear in the top right admin bar: -Run `composer test` to run tests against PHPUnit and the PHP code in the plugin. +![Screenshot of plugin](https://github.com/alleyinteractive/wp-environment-switcher/assets/346399/83684c99-4f74-4969-b302-a0c617c17190) -### The `entries` directory and entry points +The plugin reads the current WordPress environment from `wp_get_environment_type()` which can be set by defining `WP_ENVIRONMENT_TYPE` in your `wp-config.php` file. You can define the available environments by using the `wp_environment_switcher_environments` filter: -All directories created in the `entries` directory can serve as entry points and will be compiled with [@wordpress/scripts](https://github.com/WordPress/gutenberg/blob/trunk/packages/scripts/README.md#scripts) into the `build` directory with an accompanied `index.asset.php` asset map. - -#### Enqueuing Entry Points - -You can also include an `index.php` file in the entry point directory for enqueueing or registering a script. This file will then be moved to the build directory and will be auto-loaded with the `load_scripts()` function in the `functions.php` file. Alternatively, if a script is to be enqueued elsewhere there are helper functions in the `src/assets.php` file for getting the assets. - -### Scaffold a dynamic block with `create-block` - -Use the `create-block` command to create custom blocks with [@alleyinteractive/create-block](https://github.com/alleyinteractive/alley-scripts/tree/main/packages/create-block) script and follow the prompts to generate all the block assets in the `blocks/` directory. -Block registration, script creation, etc will be scaffolded from the `create-block` script. Run `npm run build` to compile and build the custom block. Blocks are enqueued using the `load_scripts()` function in `src/assets.php`. - -### Updating WP Dependencies - -Update the [WordPress dependency packages](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/#packages-update) used in the project to their latest version. - -To update `@wordpress` dependencies to their latest version use the packages-update command: - -```sh -npx wp-scripts packages-update +```php +add_filter( + 'wp_environment_switcher_environments', + fn () => [ + 'production' => 'https://example.org', + 'staging' => 'https://staging.example.org', + 'local' => 'https://example.test', + ] +); ``` -This script provides the following custom options: +The plugin will automatically detect the current environment and highlight it in +the switcher. -- `--dist-tag` – allows specifying a custom dist-tag when updating npm packages. Defaults to `latest`. This is especially useful when using [`@wordpress/dependency-extraction-webpack-plugin`](https://www.npmjs.com/package/@wordpress/dependency-extraction-webpack-plugin). It lets installing the npm dependencies at versions used by the given WordPress major version for local testing, etc. Example: - -```sh -npx wp-scripts packages-update --dist-tag=wp-WPVERSION` -``` - -Where `WPVERSION` is the version of WordPress you are targeting. The version -must include both the major and minor version (e.g., `6.1`). For example: +## Testing -```sh -npx wp-scripts packages-update --dist-tag=wp-6.1` -``` +Run `composer test` to run tests against PHPStan/PHPCS. ## Changelog @@ -92,11 +48,11 @@ Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed re This project is actively maintained by [Alley Interactive](https://github.com/alleyinteractive). Like what you see? [Come work -with us](https://alley.co/careers/). +with us](https://alley.com/careers/). -- [Sean Fisher](https://github.com/Sean Fisher) +- [Sean Fisher](https://github.com/srtfisher) - [All Contributors](../../contributors) ## License -The GNU General Public License (GPL) license. Please see [License File](LICENSE) for more information. \ No newline at end of file +The GNU General Public License (GPL) license. Please see [License File](LICENSE) for more information. diff --git a/composer.json b/composer.json index 41b09f7..25c1739 100644 --- a/composer.json +++ b/composer.json @@ -11,16 +11,14 @@ "authors": [ { "name": "Sean Fisher", - "email": "srtfisher@gmail.com" + "email": "sean@alley.com" } ], "require": { - "php": "^8.0", - "alleyinteractive/composer-wordpress-autoloader": "^1.0" + "php": "^8.0" }, "require-dev": { "alleyinteractive/alley-coding-standards": "^1.0", - "mantle-framework/testkit": "^0.11", "szepeviktor/phpstan-wordpress": "^1.1" }, "config": { @@ -31,27 +29,15 @@ }, "sort-packages": true }, - "extra": { - "wordpress-autoloader": { - "autoload": { - "Alley\\WP\\WordPress_Environment_Switcher": "src" - }, - "autoload-dev": { - "Alley\\WP\\WordPress_Environment_Switcher\\Tests": "tests" - } - } - }, "minimum-stability": "dev", "prefer-stable": true, "scripts": { "phpcbf": "phpcbf .", "phpcs": "phpcs .", - "phpunit": "phpunit", "phpstan": "phpstan --memory-limit=512M", "test": [ "@phpcs", - "@phpstan", - "@phpunit" + "@phpstan" ] } } diff --git a/phpstan.neon b/phpstan.neon index 4e5ed90..5e0cefa 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -6,9 +6,6 @@ parameters: level: max paths: - - blocks/ - - entries/ - - src/ - wp-environment-switcher.php # ignoreErrors: diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index ab2a15e..0000000 --- a/phpunit.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - tests/feature - - - tests/unit - - - diff --git a/src/class-wordpress-environment-switcher.php b/src/class-wordpress-environment-switcher.php deleted file mode 100644 index d0f9daf..0000000 --- a/src/class-wordpress-environment-switcher.php +++ /dev/null @@ -1,15 +0,0 @@ - $args Optional. Additional arguments for register_post_meta or register_term_meta. Defaults to an empty array. - * @return bool True if the meta key was successfully registered in the global array, false if not. - */ -function register_meta_helper( - string $object_type, - array $object_slugs, - string $meta_key, - array $args = [] -) : bool { - - // Object type must be either post or term. - if ( ! in_array( $object_type, [ 'post', 'term' ], true ) ) { - throw new \InvalidArgumentException( - __( - 'Object type must be one of "post", "term".', - 'wp-environment-switcher' - ) - ); - } - - /** - * Merge provided arguments with defaults and filter register_meta() args. - * - * @link https://developer.wordpress.org/reference/functions/register_meta/ - * - * @param array $args { - * Array of args to be passed to register_meta(). - * - * @type string $object_subtype A subtype; e.g. if the object type is "post", the post type. If left empty, - * the meta key will be registered on the entire object type. Default empty. - * @type string $type The type of data associated with this meta key. Valid values are - * 'string', 'boolean', 'integer', 'number', 'array', and 'object'. - * @type string $description A description of the data attached to this meta key. - * @type bool $single Whether the meta key has one value per object, or an array of values per object. - * @type mixed $default The default value returned from get_metadata() if no value has been set yet. - * When using a non-single meta key, the default value is for the first entry. In other words, - * when calling get_metadata() with $single set to false, the default value given here will be wrapped in an array. - * @type callable $sanitize_callback A function or method to call when sanitizing $meta_key data. - * @type callable $auth_callback Optional. A function or method to call when performing edit_post_meta, - * add_post_meta, and delete_post_meta capability checks. - * @type bool|array $show_in_rest Whether data associated with this meta key can be considered public and should be - * accessible via the REST API. A custom post type must also declare support - * for custom fields for registered meta to be accessible via REST. When registering - * complex meta values this argument may optionally be an array with 'schema' - * or 'prepare_callback' keys instead of a boolean. - * } - * @param string $object_type The type of meta to register, which must be one of 'post' or 'term'. - * @param array $object_slugs The post type or taxonomy slugs to register with. - * @param string $meta_key The meta key to register. - */ - $args = apply_filters( - 'wp_environment_switcher_register_meta_helper_args', // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound - wp_parse_args( - $args, - [ - 'show_in_rest' => true, - 'single' => true, - 'type' => 'string', - ] - ), - $object_type, - $object_slugs, - $meta_key - ); - - // Fork for object type. - switch ( $object_type ) { - case 'post': - foreach ( $object_slugs as $object_slug ) { - if ( ! register_post_meta( $object_slug, $meta_key, $args ) ) { - return false; - } - } - break; - case 'term': - foreach ( $object_slugs as $object_slug ) { - if ( ! register_term_meta( $object_slug, $meta_key, $args ) ) { - return false; - } - } - break; - default: - return false; - } - - return true; -} - -/** - * Reads the post meta definitions from config and registers them. - */ -function register_post_meta_from_defs(): void { - // Ensure the config file exists. - $filepath = dirname( __DIR__ ) . '/config/post-meta.json'; - if ( ! file_exists( $filepath ) - || 0 !== validate_file( $filepath ) - ) { - return; - } - - // Try to read the file's contents. We can dismiss the "uncached" warning here because it is a local file. - // phpcs:ignore WordPressVIPMinimum.Performance.FetchingRemoteData.FileGetContentsUnknown - $definitions = json_decode( (string) file_get_contents( $filepath ), true ); - if ( empty( $definitions ) || ! is_array( $definitions ) ) { - return; - } - - // Loop through definitions and register each. - foreach ( $definitions as $meta_key => $definition ) { - // Extract post types. - $post_types = $definition['post_types'] ?? []; - // Unset since $definition is passed as register_meta args. - unset( $definition['post_types'] ); - - // Relocate schema, if specified at the top level. - if ( ! empty( $definition['schema'] ) ) { - $definition['show_in_rest']['schema'] = $definition['schema']; - // Unset since $definition is passed as register_meta args. - unset( $definition['schema'] ); - } - - // Register the meta. - register_meta_helper( - 'post', - $post_types, - $meta_key, - $definition - ); - } -} diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index 7376004..0000000 --- a/tests/bootstrap.php +++ /dev/null @@ -1,16 +0,0 @@ -maybe_rsync_plugin() - ->with_sqlite() - // Load the main file of the plugin. - ->loaded( fn () => require_once __DIR__ . '/../wp-environment-switcher.php' ) - ->install(); diff --git a/tests/class-test-case.php b/tests/class-test-case.php deleted file mode 100644 index 47d05c6..0000000 --- a/tests/class-test-case.php +++ /dev/null @@ -1,17 +0,0 @@ -assertTrue( true ); - $this->assertNotEmpty( home_url() ); - } -} diff --git a/tests/unit/class-example-unit-test.php b/tests/unit/class-example-unit-test.php deleted file mode 100644 index 762abc5..0000000 --- a/tests/unit/class-example-unit-test.php +++ /dev/null @@ -1,24 +0,0 @@ -assertTrue( true ); - } -} diff --git a/wp-environment-switcher.php b/wp-environment-switcher.php index 202940e..a6dfd6e 100644 --- a/wp-environment-switcher.php +++ b/wp-environment-switcher.php @@ -3,10 +3,10 @@ * Plugin Name: WordPress Environment Switcher * Plugin URI: https://github.com/alleyinteractive/wp-environment-switcher * Description: Easily switch between different site environments from the WordPress admin bar. - * Version: 0.1.0 + * Version: 1.0.0 * Author: Sean Fisher * Author URI: https://github.com/alleyinteractive/wp-environment-switcher - * Requires at least: 6.0 + * Requires at least: 5.5.0 * Tested up to: 6.2 * * Text Domain: wp-environment-switcher @@ -21,17 +21,153 @@ } /** - * Root directory to this plugin. + * Instantiate the plugin. */ -define( 'WP_ENVIRONMENT_SWITCHER_DIR', __DIR__ ); +function main(): void { + add_action( 'admin_bar_menu', __NAMESPACE__ . '\\register_admin_bar', 300 ); + add_action( 'wp_before_admin_bar_render', __NAMESPACE__ . '\\add_switcher_css' ); +} +main(); -// Load the plugin's main files. -require_once __DIR__ . '/src/meta.php'; +/** + * Retrieve all the available environments for the switcher. + * + * @return array + */ +function get_environments(): array { + return (array) apply_filters( 'wp_environment_switcher_environments', [] ); +} /** - * Instantiate the plugin. + * Translate the current request path to a different host. + * + * Used to translate www.example.org/the/path to staging.example.org/the/path + * for switching environments with ease. + * + * @param string $environment_url The new base URL. + * @return string */ -function main(): void { - // ... +function get_translated_url( string $environment_url ): string { + if ( empty( $_SERVER['REQUEST_URI'] ) ) { + return $environment_url; + } + + return rtrim( $environment_url, '/' ) . sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ); +} + +/** + * Register the admin environment switcher in the admin bar. + */ +function register_admin_bar(): void { + $environments = get_environments(); + + if ( empty( $environments ) ) { + return; + } + + $current = wp_get_environment_type(); + + // Bail if we can't determine the current environment. + if ( empty( $current ) ) { + _doing_it_wrong( + __FUNCTION__, + esc_html__( 'The current environment could not be determined.', 'wp-environment-switcher' ), + '0.1.0' + ); + + return; + } + + // Fire a warning if the current environment is not in the list of environments. + if ( ! isset( $environments[ $current ] ) ) { + _doing_it_wrong( + __FUNCTION__, + sprintf( + /* translators: %s is the current environment */ + esc_html__( 'The current environment (%s) is not in the list of environments.', 'wp-environment-switcher' ), + esc_html( $current ) + ), + '0.1.0' + ); + } + + global $wp_admin_bar; + + $wp_admin_bar->add_menu( + [ + 'id' => 'wp-environment-switcher', + 'title' => ucwords( $current ), + 'href' => '#', + 'parent' => 'top-secondary', + 'meta' => [ + 'class' => 'wp-environment-switcher', + ], + ] + ); + + /** + * Filter the method used to translate the URL to the new environment. + * + * @param callable $callback The callback to use to translate the URL. + */ + $callback = apply_filters( 'wp_environment_switcher_url_translation', __NAMESPACE__ . '\\get_translated_url' ); + + // Fire a warning if the translation callback is not callable. + if ( ! is_callable( $callback ) ) { + _doing_it_wrong( + __FUNCTION__, + esc_html__( 'The URL translation callback is not callable.', 'wp-environment-switcher' ), + '0.1.0' + ); + + // Reverse the callback to the default. + $callback = __NAMESPACE__ . '\\get_translated_url'; + } + + foreach ( $environments as $environment => $url ) { + $wp_admin_bar->add_menu( + [ + 'id' => 'wp-environment-switcher-' . $environment, + 'parent' => 'wp-environment-switcher', + 'title' => ucwords( $environment ), + 'href' => $callback( $url ), + 'meta' => [ + 'class' => 'wp-environment-switcher__item ' . ( $environment === $current ? 'wp-environment-switcher__item--active' : '' ), + ], + ] + ); + } +} + +/** + * Add CSS to support the environment switcher. + */ +function add_switcher_css(): void { + if ( empty( get_environments() ) ) { + return; + } + + ?> + +