diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..5c5d1db Binary files /dev/null and b/.DS_Store differ diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index d74ecaf..7b7af40 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,7 +1,3 @@ # These are supported funding model platforms -github: leonstafford -custom: ['https://paypal.me/ljsdotdev', 'https://ljs.dev', 'https://donorbox.org/leonstafford'] -patreon: leonstafford -ko_fi: leonstafford - +custom: ['https://paypal.me/adamtwar'] diff --git a/CHANGELOG.md b/CHANGELOG.md old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index e7853e1..f2d7f5c --- a/README.md +++ b/README.md @@ -1,6 +1,220 @@ -# WP2Static Amazon S3 Deployment Add-on +# WP2Static Add-on: Copy to Folder -Adds Amazon S3 as a deployment option for WP2Static. +The WP2Static Copy to Folder Deployment Add-on is an extension for the [WP2Static](https://wp2static.com/) plugin. It allows you to automatically copy your generated static WordPress site to a different folder on the same server where your WordPress installation resides. -Take advantage of Amazon S3 to host your WordPress powered static website. +## What it Does +When WP2Static finishes exporting your WordPress site into a static HTML version (typically located in `wp-content/uploads/wp2static-processed-site`), this add-on takes over and copies the entire contents of that processed site directory to a target folder you specify. + +This is useful for: + +* Deploying your static site to a directory served directly by your web server (e.g., a subdirectory of your main domain, or a different virtual host pointing to a local path). +* Keeping a local copy of your static site in a specific, easily accessible location. +* Integrating with other scripts or processes that expect the static site files in a particular directory. + +## Who it's For + +This add-on is for WordPress users who utilize WP2Static to generate a static version of their site and need a simple, automated way to deploy or copy these static files to another location on the *same server*. + +## Why it's Useful + +* **Simplicity:** Offers a straightforward method for local deployment without needing external services, FTP, or complex deployment scripts. +* **Automation:** Integrates directly into the WP2Static deployment process, copying files automatically after generation. +* **Control:** You specify the exact target directory for your static files. +* **Flexibility:** Options to clean the target directory before deployment and to include additional custom files or folders. + +## Features + +* **Define Target Directory:** Specify the absolute path on your server where the static site should be copied. +* **Clean Target Directory:** Optionally, automatically remove all existing files and folders from the target directory before copying the new static site. +* **Extra Source Folder:** Optionally, specify an additional folder on your server whose contents will also be copied into the target directory after the main static site files. This is useful for including files not generated by WordPress, such as a custom `.htaccess`, verification files, or other static assets. + +## Requirements + +* A working WordPress installation. +* The main [WP2Static](https://wp2static.com/) plugin installed and activated. +* PHP version 7.3 or higher. + +## Installation + +1. **Install WP2Static:** If you haven't already, install and activate the core [WP2Static plugin](https://wp2static.com/) from the WordPress plugin directory or its official website. +2. **Download the Add-on:** + * Download the latest `wp2static-addon-copy.zip` file from the [official GitHub releases page](https://github.com/twardoch/wp2static-addon-copy/releases). +3. **Upload and Activate in WordPress:** + * In your WordPress admin area, navigate to **Plugins > Add New**. + * Click the **Upload Plugin** button at the top. + * Choose the `wp2static-addon-copy.zip` file you downloaded and click **Install Now**. + * After installation, click **Activate Plugin**. + +## Configuration + +1. Once activated, navigate to **WP2Static > Addons** in your WordPress admin menu. +2. Locate **Copy Deployment** in the list of available add-ons. +3. If it's marked as "Disabled", click the status toggle to **Enable** it. +4. Click the **Configure** button next to "Copy Deployment". + +You will see the following options: + +* **Target folder (absolute):** + * Enter the full absolute path to the folder on your server where you want the static site files to be copied. For example: `/var/www/mystaticsite` or `/home/user/public_html/static_version`. + * Ensure this directory is writable by your web server. +* **Clean target folder before deployment:** + * Check this box if you want the add-on to delete all contents of the "Target folder" before copying the new files. This ensures a clean deployment without any leftover files from previous exports. +* **Extra source folder (absolute):** + * (Optional) If you have other files or folders (e.g., a custom `.htaccess`, `robots.txt`, or a directory of shared assets) that you want to include with your static site, enter the full absolute path to that folder here. Its contents will be copied into the "Target folder" after the main static site files are copied. + +After configuring the options, click **Save Options**. + +## Usage + +### Via WordPress UI + +1. After configuring the add-on, ensure that "Copy Deployment" is selected as the active deployment method in the main **WP2Static > Deploy static website** tab (or relevant deployment settings area within WP2Static). +2. Generate your static site using WP2Static as you normally would (e.g., by clicking "Generate static site" or "Run all actions"). +3. Once WP2Static has processed your site, this add-on will automatically be triggered to copy the files to your configured "Target folder". +4. You can check the WP2Static logs (usually under **WP2Static > Logs**) for messages related to the copy process, such as "Copy Addon deploying", "Copying /path/to/processed-site to /path/to/targetFolder", etc. + +### Via WP-CLI + +The add-on registers a basic WP-CLI command structure, but its functionality is currently limited. + +* **Command:** `wp wp2static copy ` + +* **Available Actions:** + * `options`: This subcommand is intended for managing add-on options via WP-CLI. However, it is currently a placeholder and outputs: "TBC setting options for Copy addon". Full CLI-based option management is not yet implemented. + +Triggering the actual deployment/copy process via WP-CLI depends on the main WP2Static plugin's CLI commands for running an export and deployment. This add-on will hook into that process if it's the enabled deployer. + +--- + +## Technical Documentation + +This section provides a more detailed look into how the WP2Static Copy to Folder Add-on works internally. + +### How it Works (Code Architecture) + +The plugin follows a standard WordPress plugin structure with its core logic organized into PHP classes. + +* **Plugin Initialization (`wp2static-addon-copy.php`):** + * This is the main plugin file that WordPress recognizes. + * It defines essential constants like `WP2STATIC_COPY_PATH` (plugin's directory path) and `WP2STATIC_COPY_VERSION`. + * It includes the Composer `vendor/autoload.php` file for class loading. + * It instantiates the `WP2StaticCopy\Controller` class and calls its `run()` method to initialize the add-on. + * It registers WordPress activation and deactivation hooks: + * `Controller::activate`: Called on plugin activation. It creates the custom database table used for storing the add-on's options and seeds it with default values. + * `Controller::deactivate`: Called on plugin deactivation. Currently, this method is empty but could be used for cleanup tasks in the future. + +* **Controller (`src/Controller.php`):** + * This class is responsible for integrating the add-on with the WordPress admin interface and the WP2Static plugin. + * The `run()` method sets up various WordPress actions and filters: + * `wp2static_add_menu_items`: Adds a link to the add-on's settings page under the "WP2Static" admin menu (specifically within the "Addons" section). + * `admin_post_wp2static_copy_save_options`: Defines a handler for when the options form (in `views/copy-page.php`) is submitted. It saves the sanitized option values to the database. + * `wp2static_deploy`: This is a crucial hook. It listens for the WP2Static deployment action. If this "Copy Deployment" add-on is the currently enabled deployer, it triggers the file copying process by calling `Deployer->uploadFiles()`. + * `admin_menu`: Registers the submenu page for the add-on's options, making it accessible. + * `wp2static_register_addon`: Registers this add-on with the main WP2Static plugin, allowing WP2Static to recognize and manage it. + * **Options Management:** + * Options are stored in a custom database table: `{$wpdb->prefix}wp2static_addon_copy_options`. + * `createOptionsTable()`: Defines and creates this table schema during activation. + * `seedOptions()`: Populates the table with default option names and initial values. + * `getOptions()`: Retrieves all options from the database. + * `saveOption()`: Updates a specific option's value (used internally by `saveOptionsFromUI`). + * `getValue(string $name)`: Retrieves the value of a single named option. + * `renderCopyPage()`: This method is called to display the add-on's settings page. It prepares data (like current option values and nonce fields) and then includes `views/copy-page.php` to render the HTML form. + +* **Deployer (`src/Deployer.php`):** + * This class contains the core logic for the file copying operations. + * `uploadFiles(string $processed_site_path)`: This is the main method executed during deployment. + 1. It retrieves the necessary options (`copyTargetFolder`, `copyRemoveTarget`, `copyExtraFolder`) using `Controller::getValue()`. + 2. It performs basic validation (e.g., checking if the processed site path and target folder exist). + 3. If the "Clean target folder" option (`copyRemoveTarget`) is enabled, it calls the `rrmdir()` helper function to recursively delete all contents of the target directory. + 4. It then calls the `xcopy()` helper function to recursively copy all files and directories from the `$processed_site_path` (where WP2Static places the generated static site) to the `copyTargetFolder`. + 5. If an "Extra source folder" (`copyExtraFolder`) is specified and exists, it again uses `xcopy()` to copy the contents of this extra folder into the `copyTargetFolder`. + 6. Logs its actions using `\WP2Static\WsLog::l()`. + * **Helper Functions:** + * `rrmdir(string $path)`: A utility function to recursively remove a directory and all its contents. It's careful not to delete the root directory itself if given an empty path component. + * `xcopy(string $source, string $dest, int $permissions = 0755)`: A utility function to recursively copy files and directories from a source to a destination. It attempts to preserve symlinks and sets directory permissions. It includes a `hashDirectory()` check to prevent infinite loops if, by some misconfiguration, the source is a parent of the destination (though this is less of a concern for this plugin's typical usage). + * `hashDirectory(string $directory)`: Calculates an MD5 hash based on the files within a directory. Used by `xcopy` to detect if a source directory has changed during a recursive copy operation (primarily for the self-copying prevention). + +* **CLI (`src/CLI.php`):** + * This class registers WP-CLI commands for the add-on. + * `\WP_CLI::add_command('wp2static copy', [CLI::class, 'copy'])` registers the main `wp wp2static copy` command. + * The `copy(array $args, array $assoc_args)` method currently only handles an `options` subcommand, which, as noted, is a placeholder ("TBC setting options for Copy addon"). + +* **Views (`views/copy-page.php`):** + * This is a PHP file that generates the HTML for the add-on's settings page in the WordPress admin area. + * It displays a form with input fields for "Target folder", a checkbox for "Clean target folder", and an input field for "Extra source folder". + * It uses WordPress functions like `esc_url()`, `admin_url()`, and `wp_nonce_field()` for security and proper URL generation. + +* **Uninstall (`uninstall.php`):** + * This script is executed when the plugin is uninstalled from WordPress. + * Its primary function is to clean up by dropping the custom database table (`{$wpdb->prefix}wp2static_addon_copy_options`) that the add-on created. + +* **MIME Types (`src/MimeTypes.php`):** + * This class (`WP2StaticCopy\MimeTypes`) provides a static method `guessMimeType(string $filename)` to determine the MIME type of a file. It first checks against a comprehensive internal list of known extensions and then falls back to using PHP's `finfo` functions if available. + * *Note: It's not immediately clear if this MimeTypes class is actively used within the Copy to Folder add-on's current functionality. It might be a utility intended for broader use within the WP2Static ecosystem or for future features.* + +### Key Files and Directories + +* `wp2static-addon-copy.php`: Main plugin file (bootstrap). +* `src/`: Contains the core PHP classes: + * `Controller.php`: Handles WordPress integration, admin UI, and option management. + * `Deployer.php`: Contains the logic for copying files. + * `CLI.php`: Implements WP-CLI command integration. + * `MimeTypes.php`: Utility for guessing file MIME types. +* `views/`: + * `copy-page.php`: PHP template for the admin options page. +* `vendor/`: (Typically created by Composer) Contains third-party libraries. This plugin has no specific PHP library dependencies in its `composer.json` `require` section for runtime, but `autoload.php` from Composer is used. +* `composer.json`: Defines project metadata, PHP version requirements (>=7.3), development dependencies, and scripts for development tasks (testing, linting, building). +* `LICENSE.txt`: Contains the Unlicense text. +* `CHANGELOG.md`: **Note:** The current `CHANGELOG.md` in the repository appears to be for the "WP2Static S3 Add-on", not this "Copy to Folder" add-on. This is likely an error. +* `.github/workflows/codequality.yml`: Defines a GitHub Actions workflow that runs automated checks (Composer validation, linting, PHPStan) on pushes and pull requests to the `master` branch, testing against PHP 7.3 and 7.4. +* `tools/`: Contains utility scripts and configuration for development: + * `build_release.sh`: Shell script to package the plugin into a distributable `.zip` file. It handles installing production-only Composer dependencies before packaging. + * `phpcs.xml`: Configuration file for PHP_CodeSniffer, defining the coding standards. + * `update_version.sh`: A shell script to find and replace version strings across the project. +* `tests/`: Contains files related to testing: + * `phpstan/`: Configuration and bootstrap files for PHPStan static analysis. + * `unit/`: Bootstrap for PHPUnit tests (current unit test suite seems minimal). +* `uninstall.php`: Script executed upon plugin uninstallation to clean up resources (like the custom options database table). + +### Coding Conventions and Standards + +* The project uses **PHP_CodeSniffer (`phpcs`)** for enforcing coding standards. The specific ruleset is defined in `tools/phpcs.xml`. It is largely based on the `WordPress` coding standard but includes several customizations and excluded rules (e.g., regarding line length, indentation, and specific WordPress sniffs). +* **PHPStan** is used for static analysis to detect potential bugs and type errors. Its configuration is in `phpstan.neon`, set to `level: max`. +* PHP Compatibility checks are performed using `PHPCompatibilityWP` standard via Composer scripts to ensure compatibility with specified PHP versions (currently targeting >=7.3, tested against 7.3 & 7.4 in CI). +* Composer scripts (`"lint"`, `"phpcs"`, `"phpstan"`, `"test"`) are provided for easy execution of these checks. + +### Contributing + +We welcome contributions to enhance the WP2Static Copy to Folder Add-on! + +* **Reporting Issues:** If you find a bug or have a feature request, please open an issue on the [GitHub repository's Issues page](https://github.com/twardoch/wp2static-addon-copy/issues). +* **Development Setup:** + 1. Clone the repository: `git clone https://github.com/twardoch/wp2static-addon-copy.git` + 2. Navigate into the cloned directory: `cd wp2static-addon-copy` + 3. Install development dependencies using Composer: `composer install` +* **Running Tests & Linters:** + * To run all checks (validation, linting, coding standards, PHPStan): `composer test` + * To run only PHP_CodeSniffer for coding standards: `composer phpcs` + * To attempt to automatically fix coding standards issues: `composer phpcbf` + * To run only PHPStan for static analysis: `composer phpstan` + * To run PHPUnit tests (if any are added): `composer phpunit` +* **Building a Release:** + * The `tools/build_release.sh` script is used to create a production-ready `.zip` file of the plugin. This can also be run via `composer build`. + * The script temporarily removes development dependencies, installs production dependencies, copies necessary files to a temporary directory, and then creates the zip archive. Afterwards, it restores development dependencies. +* **Pull Requests:** + 1. Fork the repository on GitHub. + 2. Create a new branch for your feature or bug fix (e.g., `feature/new-thing` or `fix/issue-123`). + 3. Make your changes and commit them with clear, descriptive messages. + 4. Ensure all tests and linters pass (`composer test`). + 5. Push your branch to your fork. + 6. Open a pull request against the `master` branch of the `twardoch/wp2static-addon-copy` repository. + +### Changelog + +For a list of changes and new features, please refer to the `CHANGELOG.md` file. +*(**Developer Note:** The current `CHANGELOG.md` in the repository root seems to be for a different add-on (S3). This needs to be corrected or a specific one for this add-on should be maintained.)* + +### License + +The WP2Static Copy to Folder Add-on is released under the **Unlicense**. See the `LICENSE.txt` file for more details. This means it is free and unencumbered software released into the public domain. diff --git a/composer.json b/composer.json old mode 100644 new mode 100755 index 265ce60..21edb32 --- a/composer.json +++ b/composer.json @@ -1,27 +1,23 @@ { - "name": "leonstafford/wp2static-addon-s3", - "description": "S3 deployment Add-on for WP2Static.", - "homepage": "https://wp2static.com", - "license": "UNLICENSE", - "authors": [ - { - "name": "Leon Stafford", - "email": "me@ljs.dev", - "homepage": "https://ljs.dev" - } - ], + "name": "twardoch/wp2static-addon-copy", + "description": "Copy to Folder Add-on for WP2Static.", + "homepage": "https://github.com/twardoch/wp2static-addon-copy", + "license": "UNLICENSE", + "authors": [{ + "name": "Adam Twardoch", + "email": "adam+github@twardoch.com", + "homepage": "https://twardoch.github.io" + }], "type": "wordpress-plugin", "support": { - "issues": "https://github.com/leonstafford/wp2static-addon-s3/issues", + "issues": "https://github.com/twardoch/wp2static-addon-copy/issues", "forum": "https://wp2static.com/community", "docs": "https://wp2static.com/documentation", - "source": "https://github.com/leonstafford/wp2static-addon-s3" + "source": "https://github.com/twardoch/wp2static-addon-copy" }, - "repositories": [ - ], + "repositories": [], "require": { - "php": ">=7.3", - "aws/aws-sdk-php": "^3.166.1" + "php": ">=7.3" }, "require-dev": { "phpstan/phpstan": "*", @@ -37,13 +33,13 @@ }, "autoload": { "psr-4": { - "WP2StaticS3\\": "src/" + "WP2StaticCopy\\": "src/" } }, "autoload-dev": { "psr-4": { "PHPStan\\WordPress\\": "tests/phpstan/", - "WP2StaticS3\\": "src/" + "WP2StaticCopy\\": "src/" } }, "config": { @@ -70,4 +66,4 @@ ], "build": "/bin/sh tools/build_release.sh" } -} +} \ No newline at end of file diff --git a/composer.lock b/composer.lock old mode 100644 new mode 100755 index 435f534..a1e73c5 --- a/composer.lock +++ b/composer.lock @@ -4,621 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9e3f0e9e0e32ac911b219b876a265782", - "packages": [ - { - "name": "aws/aws-sdk-php", - "version": "3.171.19", - "source": { - "type": "git", - "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "e786e4a8b2ec85b258833d0570ff6b61348cbdb6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/e786e4a8b2ec85b258833d0570ff6b61348cbdb6", - "reference": "e786e4a8b2ec85b258833d0570ff6b61348cbdb6", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-pcre": "*", - "ext-simplexml": "*", - "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4.1", - "mtdowling/jmespath.php": "^2.5", - "php": ">=5.5" - }, - "require-dev": { - "andrewsville/php-token-reflection": "^1.4", - "aws/aws-php-sns-message-validator": "~1.0", - "behat/behat": "~3.0", - "doctrine/cache": "~1.4", - "ext-dom": "*", - "ext-openssl": "*", - "ext-pcntl": "*", - "ext-sockets": "*", - "nette/neon": "^2.3", - "paragonie/random_compat": ">= 2", - "phpunit/phpunit": "^4.8.35|^5.4.3", - "psr/cache": "^1.0", - "psr/simple-cache": "^1.0", - "sebastian/comparator": "^1.2.3" - }, - "suggest": { - "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", - "doctrine/cache": "To use the DoctrineCacheAdapter", - "ext-curl": "To send requests using cURL", - "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", - "ext-sockets": "To use client-side monitoring" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "psr-4": { - "Aws\\": "src/" - }, - "files": [ - "src/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Amazon Web Services", - "homepage": "http://aws.amazon.com" - } - ], - "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", - "homepage": "http://aws.amazon.com/sdkforphp", - "keywords": [ - "amazon", - "aws", - "cloud", - "dynamodb", - "ec2", - "glacier", - "s3", - "sdk" - ], - "support": { - "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", - "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.171.19" - }, - "time": "2021-01-15T19:26:11+00:00" - }, - { - "name": "guzzlehttp/guzzle", - "version": "7.2.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0aa74dfb41ae110835923ef10a9d803a22d50e79", - "reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79", - "shasum": "" - }, - "require": { - "ext-json": "*", - "guzzlehttp/promises": "^1.4", - "guzzlehttp/psr7": "^1.7", - "php": "^7.2.5 || ^8.0", - "psr/http-client": "^1.0" - }, - "provide": { - "psr/http-client-implementation": "1.0" - }, - "require-dev": { - "ext-curl": "*", - "php-http/client-integration-tests": "^3.0", - "phpunit/phpunit": "^8.5.5 || ^9.3.5", - "psr/log": "^1.1" - }, - "suggest": { - "ext-curl": "Required for CURL handler support", - "ext-intl": "Required for Internationalized Domain Name (IDN) support", - "psr/log": "Required for using the Log middleware" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "7.1-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "psr-18", - "psr-7", - "rest", - "web service" - ], - "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.2.0" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://github.com/alexeyshockov", - "type": "github" - }, - { - "url": "https://github.com/gmponos", - "type": "github" - } - ], - "time": "2020-10-10T11:47:56+00:00" - }, - { - "name": "guzzlehttp/promises", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "60d379c243457e073cff02bc323a2a86cb355631" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", - "reference": "60d379c243457e073cff02bc323a2a86cb355631", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "symfony/phpunit-bridge": "^4.4 || ^5.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.4.0" - }, - "time": "2020-09-30T07:37:28+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "1.7.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3", - "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" - }, - "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Schultze", - "homepage": "https://github.com/Tobion" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], - "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.7.0" - }, - "time": "2020-09-30T07:37:11+00:00" - }, - { - "name": "mtdowling/jmespath.php", - "version": "2.6.0", - "source": { - "type": "git", - "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/42dae2cbd13154083ca6d70099692fef8ca84bfb", - "reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb", - "shasum": "" - }, - "require": { - "php": "^5.4 || ^7.0 || ^8.0", - "symfony/polyfill-mbstring": "^1.17" - }, - "require-dev": { - "composer/xdebug-handler": "^1.4", - "phpunit/phpunit": "^4.8.36 || ^7.5.15" - }, - "bin": [ - "bin/jp.php" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-4": { - "JmesPath\\": "src/" - }, - "files": [ - "src/JmesPath.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Declaratively specify how to extract elements from a JSON document", - "keywords": [ - "json", - "jsonpath" - ], - "support": { - "issues": "https://github.com/jmespath/jmespath.php/issues", - "source": "https://github.com/jmespath/jmespath.php/tree/2.6.0" - }, - "time": "2020-07-31T21:01:56+00:00" - }, - { - "name": "psr/http-client", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", - "shasum": "" - }, - "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", - "keywords": [ - "http", - "http-client", - "psr", - "psr-18" - ], - "support": { - "source": "https://github.com/php-fig/http-client/tree/master" - }, - "time": "2020-06-29T06:28:15+00:00" - }, - { - "name": "psr/http-message", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/master" - }, - "time": "2016-08-06T14:39:51+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, - "time": "2019-03-08T08:55:37+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.22.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", - "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.22-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-01-07T16:49:33+00:00" - } - ], + "content-hash": "906478c2cf4074fb937dc582a074bdce", + "packages": [], "packages-dev": [ { "name": "10up/wp_mock", @@ -667,16 +54,16 @@ }, { "name": "antecedent/patchwork", - "version": "2.1.12", + "version": "2.1.15", "source": { "type": "git", "url": "https://github.com/antecedent/patchwork.git", - "reference": "b98e046dd4c0acc34a0846604f06f6111654d9ea" + "reference": "0430ceaac7f447f1778c199ec19d7e4362a6f961" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antecedent/patchwork/zipball/b98e046dd4c0acc34a0846604f06f6111654d9ea", - "reference": "b98e046dd4c0acc34a0846604f06f6111654d9ea", + "url": "https://api.github.com/repos/antecedent/patchwork/zipball/0430ceaac7f447f1778c199ec19d7e4362a6f961", + "reference": "0430ceaac7f447f1778c199ec19d7e4362a6f961", "shasum": "" }, "require": { @@ -709,9 +96,9 @@ ], "support": { "issues": "https://github.com/antecedent/patchwork/issues", - "source": "https://github.com/antecedent/patchwork/tree/2.1.12" + "source": "https://github.com/antecedent/patchwork/tree/2.1.15" }, - "time": "2019-12-22T17:52:09+00:00" + "time": "2021-08-22T08:00:13+00:00" }, { "name": "dealerdirect/phpcodesniffer-composer-installer", @@ -905,16 +292,16 @@ }, { "name": "mockery/mockery", - "version": "1.4.2", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "20cab678faed06fac225193be281ea0fddb43b93" + "reference": "d1339f64479af1bee0e82a0413813fe5345a54ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/20cab678faed06fac225193be281ea0fddb43b93", - "reference": "20cab678faed06fac225193be281ea0fddb43b93", + "url": "https://api.github.com/repos/mockery/mockery/zipball/d1339f64479af1bee0e82a0413813fe5345a54ea", + "reference": "d1339f64479af1bee0e82a0413813fe5345a54ea", "shasum": "" }, "require": { @@ -971,9 +358,9 @@ ], "support": { "issues": "https://github.com/mockery/mockery/issues", - "source": "https://github.com/mockery/mockery/tree/master" + "source": "https://github.com/mockery/mockery/tree/1.4.3" }, - "time": "2020-08-11T18:10:13+00:00" + "time": "2021-02-24T09:51:49+00:00" }, { "name": "myclabs/deep-copy", @@ -1035,16 +422,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.10.4", + "version": "v4.12.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e" + "reference": "6608f01670c3cc5079e18c1dab1104e002579143" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", + "reference": "6608f01670c3cc5079e18c1dab1104e002579143", "shasum": "" }, "require": { @@ -1085,22 +472,22 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" }, - "time": "2020-12-20T10:01:03+00:00" + "time": "2021-07-21T10:44:31+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { @@ -1145,22 +532,22 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/master" + "source": "https://github.com/phar-io/manifest/tree/2.0.3" }, - "time": "2020-06-27T14:33:11+00:00" + "time": "2021-07-20T11:28:43+00:00" }, { "name": "phar-io/version", - "version": "3.0.4", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451" + "reference": "bae7c545bef187884426f042434e561ab1ddb182" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451", + "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", + "reference": "bae7c545bef187884426f042434e561ab1ddb182", "shasum": "" }, "require": { @@ -1196,27 +583,27 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.0.4" + "source": "https://github.com/phar-io/version/tree/3.1.0" }, - "time": "2020-12-13T23:18:30+00:00" + "time": "2021-02-23T14:00:09+00:00" }, { "name": "php-parallel-lint/php-parallel-lint", - "version": "v1.2.0", + "version": "v1.3.1", "source": { "type": "git", "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git", - "reference": "474f18bc6cc6aca61ca40bfab55139de614e51ca" + "reference": "761f3806e30239b5fcd90a0a45d41dc2138de192" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/474f18bc6cc6aca61ca40bfab55139de614e51ca", - "reference": "474f18bc6cc6aca61ca40bfab55139de614e51ca", + "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/761f3806e30239b5fcd90a0a45d41dc2138de192", + "reference": "761f3806e30239b5fcd90a0a45d41dc2138de192", "shasum": "" }, "require": { "ext-json": "*", - "php": ">=5.4.0" + "php": ">=5.3.0" }, "replace": { "grogy/php-parallel-lint": "*", @@ -1225,7 +612,7 @@ "require-dev": { "nette/tester": "^1.3 || ^2.0", "php-parallel-lint/php-console-highlighter": "~0.3", - "squizlabs/php_codesniffer": "~3.0" + "squizlabs/php_codesniffer": "^3.6" }, "suggest": { "php-parallel-lint/php-console-highlighter": "Highlight syntax in code snippet" @@ -1253,22 +640,22 @@ "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint", "support": { "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues", - "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/master" + "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.3.1" }, - "time": "2020-04-04T12:18:32+00:00" + "time": "2021-08-13T05:35:13+00:00" }, { "name": "php-stubs/wordpress-stubs", - "version": "v5.6.0", + "version": "v5.8.0", "source": { "type": "git", "url": "https://github.com/php-stubs/wordpress-stubs.git", - "reference": "ed446cce304cd49f13900274b3ed60d1b526297e" + "reference": "794e6eedfd5f2a334d581214c007fc398be588fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/ed446cce304cd49f13900274b3ed60d1b526297e", - "reference": "ed446cce304cd49f13900274b3ed60d1b526297e", + "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/794e6eedfd5f2a334d581214c007fc398be588fe", + "reference": "794e6eedfd5f2a334d581214c007fc398be588fe", "shasum": "" }, "replace": { @@ -1297,9 +684,9 @@ ], "support": { "issues": "https://github.com/php-stubs/wordpress-stubs/issues", - "source": "https://github.com/php-stubs/wordpress-stubs/tree/v5.6.0" + "source": "https://github.com/php-stubs/wordpress-stubs/tree/v5.8.0" }, - "time": "2020-12-09T00:38:16+00:00" + "time": "2021-07-21T02:34:37+00:00" }, { "name": "phpcompatibility/php-compatibility", @@ -1523,16 +910,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.12.2", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "245710e971a030f42e08f4912863805570f23d39" + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", - "reference": "245710e971a030f42e08f4912863805570f23d39", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", "shasum": "" }, "require": { @@ -1584,22 +971,22 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.12.2" + "source": "https://github.com/phpspec/prophecy/tree/1.13.0" }, - "time": "2020-12-19T10:15:11+00:00" + "time": "2021-03-17T13:42:18+00:00" }, { "name": "phpstan/phpstan", - "version": "0.12.68", + "version": "0.12.96", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "ddbe01af0706ee094c3f1ce9730b35aebb508d3d" + "reference": "a98bdc51318f20fcae8c953d266f81a70254917f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ddbe01af0706ee094c3f1ce9730b35aebb508d3d", - "reference": "ddbe01af0706ee094c3f1ce9730b35aebb508d3d", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a98bdc51318f20fcae8c953d266f81a70254917f", + "reference": "a98bdc51318f20fcae8c953d266f81a70254917f", "shasum": "" }, "require": { @@ -1630,13 +1017,17 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.68" + "source": "https://github.com/phpstan/phpstan/tree/0.12.96" }, "funding": [ { "url": "https://github.com/ondrejmirtes", "type": "github" }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, { "url": "https://www.patreon.com/phpstan", "type": "patreon" @@ -1646,20 +1037,20 @@ "type": "tidelift" } ], - "time": "2021-01-18T12:29:17+00:00" + "time": "2021-08-21T11:55:13+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.5", + "version": "9.2.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1" + "reference": "f6293e1b30a2354e8428e004689671b83871edde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f3e026641cc91909d421802dd3ac7827ebfd97e1", - "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", + "reference": "f6293e1b30a2354e8428e004689671b83871edde", "shasum": "" }, "require": { @@ -1715,7 +1106,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.5" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" }, "funding": [ { @@ -1723,7 +1114,7 @@ "type": "github" } ], - "time": "2020-11-28T06:44:49+00:00" + "time": "2021-03-28T07:26:59+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1968,16 +1359,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.1", + "version": "9.5.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360" + "reference": "191768ccd5c85513b4068bdbe99bb6390c7d54fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7bdf4085de85a825f4424eae52c99a1cec2f360", - "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/191768ccd5c85513b4068bdbe99bb6390c7d54fb", + "reference": "191768ccd5c85513b4068bdbe99bb6390c7d54fb", "shasum": "" }, "require": { @@ -1989,7 +1380,7 @@ "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", + "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", @@ -2007,7 +1398,7 @@ "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3", + "sebastian/type": "^2.3.4", "sebastian/version": "^3.0.2" }, "require-dev": { @@ -2055,7 +1446,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.1" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.8" }, "funding": [ { @@ -2067,7 +1458,7 @@ "type": "github" } ], - "time": "2021-01-17T07:42:25+00:00" + "time": "2021-07-31T15:17:34+00:00" }, { "name": "sebastian/cli-parser", @@ -2575,16 +1966,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.2", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455" + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", "shasum": "" }, "require": { @@ -2627,7 +2018,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" }, "funding": [ { @@ -2635,7 +2026,7 @@ "type": "github" } ], - "time": "2020-10-26T15:55:19+00:00" + "time": "2021-06-11T13:31:12+00:00" }, { "name": "sebastian/lines-of-code", @@ -2926,16 +2317,16 @@ }, { "name": "sebastian/type", - "version": "2.3.1", + "version": "2.3.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", "shasum": "" }, "require": { @@ -2970,7 +2361,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" + "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" }, "funding": [ { @@ -2978,7 +2369,7 @@ "type": "github" } ], - "time": "2020-10-26T13:18:59+00:00" + "time": "2021-06-15T12:49:02+00:00" }, { "name": "sebastian/version", @@ -3035,16 +2426,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.8", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625", + "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625", "shasum": "" }, "require": { @@ -3087,20 +2478,20 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2020-10-23T02:01:07+00:00" + "time": "2021-04-09T00:54:41+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.22.0", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", "shasum": "" }, "require": { @@ -3112,7 +2503,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3150,7 +2541,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" }, "funding": [ { @@ -3166,20 +2557,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.22.0", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", - "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", + "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", "shasum": "" }, "require": { @@ -3188,7 +2579,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3229,7 +2620,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" }, "funding": [ { @@ -3245,20 +2636,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "szepeviktor/phpstan-wordpress", - "version": "v0.7.2", + "version": "v0.7.7", "source": { "type": "git", "url": "https://github.com/szepeviktor/phpstan-wordpress.git", - "reference": "191eafa7283497645de920d262133cf17de5353f" + "reference": "bdbea69b2ba4a69998c3b6fe2b7106d78a23bd72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/191eafa7283497645de920d262133cf17de5353f", - "reference": "191eafa7283497645de920d262133cf17de5353f", + "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/bdbea69b2ba4a69998c3b6fe2b7106d78a23bd72", + "reference": "bdbea69b2ba4a69998c3b6fe2b7106d78a23bd72", "shasum": "" }, "require": { @@ -3268,11 +2659,11 @@ "symfony/polyfill-php73": "^1.12.0" }, "require-dev": { - "composer/composer": "^1.8.6", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "composer/composer": "^1.10.22", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", "php-parallel-lint/php-parallel-lint": "^1.1", "phpstan/phpstan-strict-rules": "^0.12", - "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^0.4.3" + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^0.6" }, "type": "phpstan-extension", "extra": { @@ -3284,7 +2675,7 @@ }, "autoload": { "psr-4": { - "PHPStan\\WordPress\\": "src/" + "SzepeViktor\\PHPStan\\WordPress\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -3301,7 +2692,7 @@ ], "support": { "issues": "https://github.com/szepeviktor/phpstan-wordpress/issues", - "source": "https://github.com/szepeviktor/phpstan-wordpress/tree/v0.7.2" + "source": "https://github.com/szepeviktor/phpstan-wordpress/tree/v0.7.7" }, "funding": [ { @@ -3309,7 +2700,7 @@ "type": "custom" } ], - "time": "2021-01-03T13:45:42+00:00" + "time": "2021-07-14T09:19:15+00:00" }, { "name": "thecodingmachine/phpstan-strict-rules", @@ -3368,16 +2759,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, "require": { @@ -3406,7 +2797,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/master" + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" }, "funding": [ { @@ -3414,34 +2805,39 @@ "type": "github" } ], - "time": "2020-07-12T23:59:07+00:00" + "time": "2021-07-28T10:34:58+00:00" }, { "name": "webmozart/assert", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", + "php": "^7.2 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" + "vimeo/psalm": "<4.6.1 || 4.6.2" }, "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" + "phpunit/phpunit": "^8.5.13" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -3464,10 +2860,10 @@ "validate" ], "support": { - "issues": "https://github.com/webmozart/assert/issues", - "source": "https://github.com/webmozart/assert/tree/master" + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" }, - "time": "2020-07-08T17:02:28+00:00" + "time": "2021-03-09T10:59:23+00:00" }, { "name": "wp-coding-standards/wpcs", @@ -3530,5 +2926,5 @@ "php": ">=7.3" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } diff --git a/phpstan.neon b/phpstan.neon old mode 100644 new mode 100755 index bf52026..80f386a --- a/phpstan.neon +++ b/phpstan.neon @@ -9,7 +9,7 @@ parameters: paths: - %currentWorkingDirectory%/src/ - %currentWorkingDirectory%/views/ - - %currentWorkingDirectory%/wp2static-addon-s3.php + - %currentWorkingDirectory%/wp2static-addon-copy.php scanFiles: - %currentWorkingDirectory%/tests/phpstan/bootstrap.php - %currentWorkingDirectory%/tests/phpstan/wp-cli-stubs-2.2.0.php diff --git a/release/wp2static-addon-copy.zip b/release/wp2static-addon-copy.zip new file mode 100644 index 0000000..e4111e6 Binary files /dev/null and b/release/wp2static-addon-copy.zip differ diff --git a/src/CLI.php b/src/CLI.php index fb71aa3..f248075 100755 --- a/src/CLI.php +++ b/src/CLI.php @@ -1,6 +1,6 @@ prefix . 'wp2static_addon_s3_options'; + $table_name = $wpdb->prefix . 'wp2static_addon_copy_options'; $rows = $wpdb->get_results( "SELECT * FROM $table_name" ); @@ -73,7 +73,7 @@ public static function getOptions() : array { public static function seedOptions() : void { global $wpdb; - $table_name = $wpdb->prefix . 'wp2static_addon_s3_options'; + $table_name = $wpdb->prefix . 'wp2static_addon_copy_options'; $query_string = "INSERT IGNORE INTO $table_name (name, value, label, description) " . @@ -81,59 +81,9 @@ public static function seedOptions() : void { $query = $wpdb->prepare( $query_string, - 'cfDistributionID', - '', - 'CloudFront Distribution ID', - 'If using CloudFront, set this to auto-invalidate cache' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 's3Bucket', - '', - 'Bucket name', - '' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 's3AccessKeyID', - '', - 'Access Key ID', - '' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 's3SecretAccessKey', - '', - 'Secret Access Key', - '' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 'cfAccessKeyID', - '', - 'Access Key ID', - '' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 'cfSecretAccessKey', - '', - 'Secret Access Key', + 'copyRemoveTarget', + '1', + 'Clean target folder before deployment', '' ); @@ -141,9 +91,9 @@ public static function seedOptions() : void { $query = $wpdb->prepare( $query_string, - 's3Region', + 'copyTargetFolder', '', - 'Region', + 'Target folder (absolute)', '' ); @@ -151,69 +101,9 @@ public static function seedOptions() : void { $query = $wpdb->prepare( $query_string, - 's3Profile', + 'copyExtraFolder', '', - 'Profile', - '' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 'cfRegion', - '', - 'Region', - '' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 'cfProfile', - '', - 'Profile', - '' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 's3RemotePath', - '', - 'Path prefix in bucket', - 'Optionally, deploy to a subdirectory within bucket' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 's3CacheControl', - 'public, max-age=900', - 'Cache-Control header value', - '' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 's3ObjectACL', - 'public-read', - 'Object ACL', - '' - ); - - $wpdb->query( $query ); - - $query = $wpdb->prepare( - $query_string, - 'cfMaxPathsToInvalidate', - '', - 'Maximum number of paths to invalidate before triggering a full invalidation', + 'Extra source folder (absolute)', '' ); @@ -228,7 +118,7 @@ public static function seedOptions() : void { public static function saveOption( string $name, $value ) : void { global $wpdb; - $table_name = $wpdb->prefix . 'wp2static_addon_s3_options'; + $table_name = $wpdb->prefix . 'wp2static_addon_copy_options'; $wpdb->update( $table_name, @@ -237,40 +127,40 @@ public static function saveOption( string $name, $value ) : void { ); } - public static function renderS3Page() : void { + public static function renderCopyPage() : void { self::createOptionsTable(); self::seedOptions(); $view = []; - $view['nonce_action'] = 'wp2static-s3-options'; + $view['nonce_action'] = 'wp2static-copy-options'; $view['uploads_path'] = \WP2Static\SiteInfo::getPath( 'uploads' ); - $s3_path = \WP2Static\SiteInfo::getPath( 'uploads' ) . 'wp2static-processed-site.s3'; + $copy_path = \WP2Static\SiteInfo::getPath( 'uploads' ) . 'wp2static-processed-site.copy'; $view['options'] = self::getOptions(); - $view['s3_url'] = - is_file( $s3_path ) ? - \WP2Static\SiteInfo::getUrl( 'uploads' ) . 'wp2static-processed-site.s3' : '#'; + $view['copy_url'] = + is_file( $copy_path ) ? + \WP2Static\SiteInfo::getUrl( 'uploads' ) . 'wp2static-processed-site.copy' : '#'; - require_once __DIR__ . '/../views/s3-page.php'; + require_once __DIR__ . '/../views/copy-page.php'; } public function deploy( string $processed_site_path, string $enabled_deployer ) : void { - if ( $enabled_deployer !== 'wp2static-addon-s3' ) { + if ( $enabled_deployer !== 'wp2static-addon-copy' ) { return; } - \WP2Static\WsLog::l( 'S3 Addon deploying' ); + \WP2Static\WsLog::l( 'Copy Addon deploying' ); - $s3_deployer = new Deployer(); - $s3_deployer->uploadFiles( $processed_site_path ); + $copy_deployer = new Deployer(); + $copy_deployer->uploadFiles( $processed_site_path ); } public static function createOptionsTable() : void { global $wpdb; - $table_name = $wpdb->prefix . 'wp2static_addon_s3_options'; + $table_name = $wpdb->prefix . 'wp2static_addon_copy_options'; $charset_collate = $wpdb->get_charset_collate(); @@ -361,117 +251,37 @@ public static function activate( bool $network_wide = null ) : void { * @return mixed[] array of submenu pages */ public static function addSubmenuPage( array $submenu_pages ) : array { - $submenu_pages['s3'] = [ 'WP2StaticS3\Controller', 'renderS3Page' ]; + $submenu_pages['copy'] = [ 'WP2StaticCopy\Controller', 'renderCopyPage' ]; return $submenu_pages; } public static function saveOptionsFromUI() : void { - check_admin_referer( 'wp2static-s3-options' ); + check_admin_referer( 'wp2static-copy-options' ); global $wpdb; - $table_name = $wpdb->prefix . 'wp2static_addon_s3_options'; - - $wpdb->update( - $table_name, - [ 'value' => sanitize_text_field( $_POST['cfDistributionID'] ) ], - [ 'name' => 'cfDistributionID' ] - ); - - $wpdb->update( - $table_name, - [ 'value' => sanitize_text_field( $_POST['s3Bucket'] ) ], - [ 'name' => 's3Bucket' ] - ); - - $wpdb->update( - $table_name, - [ 'value' => sanitize_text_field( $_POST['s3AccessKeyID'] ) ], - [ 'name' => 's3AccessKeyID' ] - ); - - $secret_access_key = - $_POST['s3SecretAccessKey'] ? - \WP2Static\CoreOptions::encrypt_decrypt( - 'encrypt', - sanitize_text_field( $_POST['s3SecretAccessKey'] ) - ) : ''; - - $wpdb->update( - $table_name, - [ 'value' => $secret_access_key ], - [ 'name' => 's3SecretAccessKey' ] - ); - - $wpdb->update( - $table_name, - [ 'value' => sanitize_text_field( $_POST['cfAccessKeyID'] ) ], - [ 'name' => 'cfAccessKeyID' ] - ); - - $secret_access_key = - $_POST['cfSecretAccessKey'] ? - \WP2Static\CoreOptions::encrypt_decrypt( - 'encrypt', - sanitize_text_field( $_POST['cfSecretAccessKey'] ) - ) : ''; - - $wpdb->update( - $table_name, - [ 'value' => $secret_access_key ], - [ 'name' => 'cfSecretAccessKey' ] - ); - - $wpdb->update( - $table_name, - [ 'value' => sanitize_text_field( $_POST['s3Region'] ) ], - [ 'name' => 's3Region' ] - ); - - $wpdb->update( - $table_name, - [ 'value' => sanitize_text_field( $_POST['cfRegion'] ) ], - [ 'name' => 'cfRegion' ] - ); - - $wpdb->update( - $table_name, - [ 'value' => sanitize_text_field( $_POST['s3Profile'] ) ], - [ 'name' => 's3Profile' ] - ); - - $wpdb->update( - $table_name, - [ 'value' => sanitize_text_field( $_POST['cfProfile'] ) ], - [ 'name' => 'cfProfile' ] - ); - - $wpdb->update( - $table_name, - [ 'value' => sanitize_text_field( $_POST['s3RemotePath'] ) ], - [ 'name' => 's3RemotePath' ] - ); + $table_name = $wpdb->prefix . 'wp2static_addon_copy_options'; $wpdb->update( $table_name, - [ 'value' => sanitize_text_field( $_POST['s3CacheControl'] ) ], - [ 'name' => 's3CacheControl' ] + [ 'value' => sanitize_text_field( $_POST['copyRemoveTarget'] ) ], + [ 'name' => 'copyRemoveTarget' ] ); $wpdb->update( $table_name, - [ 'value' => sanitize_text_field( $_POST['s3ObjectACL'] ) ], - [ 'name' => 's3ObjectACL' ] + [ 'value' => sanitize_text_field( $_POST['copyTargetFolder'] ) ], + [ 'name' => 'copyTargetFolder' ] ); $wpdb->update( $table_name, - [ 'value' => sanitize_text_field( $_POST['cfMaxPathsToInvalidate'] ) ], - [ 'name' => 'cfMaxPathsToInvalidate' ] + [ 'value' => sanitize_text_field( $_POST['copyExtraFolder'] ) ], + [ 'name' => 'copyExtraFolder' ] ); - wp_safe_redirect( admin_url( 'admin.php?page=wp2static-addon-s3' ) ); + wp_safe_redirect( admin_url( 'admin.php?page=wp2static-addon-copy' ) ); exit; } @@ -483,7 +293,7 @@ public static function saveOptionsFromUI() : void { public static function getValue( string $name ) : string { global $wpdb; - $table_name = $wpdb->prefix . 'wp2static_addon_s3_options'; + $table_name = $wpdb->prefix . 'wp2static_addon_copy_options'; $sql = $wpdb->prepare( "SELECT value FROM $table_name WHERE" . ' name = %s LIMIT 1', @@ -502,11 +312,11 @@ public static function getValue( string $name ) : string { public function addOptionsPage() : void { add_submenu_page( '', - 'S3 Deployment Options', - 'S3 Deployment Options', + 'Copy Deployment Options', + 'Copy Deployment Options', 'manage_options', - 'wp2static-addon-s3', - [ $this, 'renderS3Page' ] + 'wp2static-addon-copy', + [ $this, 'renderCopyPage' ] ); } } diff --git a/src/Deployer.php b/src/Deployer.php index 5636d5e..0f9c328 100755 --- a/src/Deployer.php +++ b/src/Deployer.php @@ -1,306 +1,137 @@ prepareDeploy(); +function rrmdir( string $path ) : void +{ - // options - load from addon's static methods + if( trim( pathinfo( $path, PATHINFO_BASENAME ), '.' ) === '' ) + return; - public function __construct() {} + if( is_dir( $path ) ) + { + array_map( 'rrmdir', glob( $path . DIRECTORY_SEPARATOR . '{,.}*', GLOB_BRACE | GLOB_NOSORT ) ); + @rmdir( $path ); + } - public function uploadFiles( string $processed_site_path ) : void { - // check if dir exists - if ( ! is_dir( $processed_site_path ) ) { - return; - } + else + @unlink( $path ); - $namespace = self::DEFAULT_NAMESPACE; +} - // instantiate S3 client - $s3 = self::s3Client(); +function xcopy($source, $dest, $permissions = 0755) +{ + $sourceHash = hashDirectory($source); + // Check for symlinks + if (is_link($source)) { + return symlink(readlink($source), $dest); + } - // iterate each file in ProcessedSite - $iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( - $processed_site_path, - RecursiveDirectoryIterator::SKIP_DOTS - ) - ); + // Simple copy for a file + if (is_file($source)) { + return copy($source, $dest); + } - $object_acl = Controller::getValue( 's3ObjectACL' ); - $put_data = [ - 'Bucket' => Controller::getValue( 's3Bucket' ), - 'ACL' => $object_acl === '' ? 'public-read' : $object_acl, - ]; + // Make destination directory + if (!is_dir($dest)) { + mkdir($dest, $permissions); + } - $cache_control = Controller::getValue( 's3CacheControl' ); - if ( $cache_control ) { - $put_data['CacheControl'] = $cache_control; + // Loop through the folder + $dir = dir($source); + while (false !== $entry = $dir->read()) { + // Skip pointers + if ($entry == '.' || $entry == '..') { + continue; } - $base_put_data = $put_data; - - $cf_max_paths = Controller::getValue( 'cfMaxPathsToInvalidate' ); - $cf_max_paths = $cf_max_paths ? intval( $cf_max_paths ) : 0; - $cf_stale_paths = []; - - foreach ( $iterator as $filename => $file_object ) { - $base_name = basename( $filename ); - if ( $base_name != '.' && $base_name != '..' ) { - $real_filepath = realpath( $filename ); - - // TODO: do filepaths differ when running from WP-CLI (non-chroot)? - - $cache_key = str_replace( $processed_site_path, '', $filename ); - - if ( ! $real_filepath ) { - $err = 'Trying to deploy unknown file to S3: ' . $filename; - \WP2Static\WsLog::l( $err ); - continue; - } - - // Standardise all paths to use / (Windows support) - $filename = str_replace( '\\', '/', $filename ); - - if ( ! is_string( $filename ) ) { - continue; - } - - $s3_key = - Controller::getValue( 's3RemotePath' ) ? - Controller::getValue( 's3RemotePath' ) . '/' . - ltrim( $cache_key, '/' ) : - ltrim( $cache_key, '/' ); - - $mime_type = MimeTypes::guessMimeType( $filename ); - if ( 'text/' === substr( $mime_type, 0, 5 ) ) { - $mime_type = $mime_type . '; charset=UTF-8'; - } - - $put_data['Key'] = $s3_key; - $put_data['ContentType'] = $mime_type; - $put_data_hash = md5( (string) json_encode( $put_data ) ); - $put_data['Body'] = file_get_contents( $filename ); - $body_hash = md5( (string) $put_data['Body'] ); - $hash = md5( $put_data_hash . $body_hash ); + // Deep copy directories + if($sourceHash != hashDirectory($source."/".$entry)){ + xcopy("$source/$entry", "$dest/$entry", $permissions); + } + } - $is_cached = \WP2Static\DeployCache::fileisCached( - $cache_key, - $namespace, - $hash, - ); + // Clean up + $dir->close(); + return true; +} - if ( $is_cached ) { - continue; - } +// In case of coping a directory inside itself, there is a need to hash check the directory otherwise and infinite loop of coping is generated - $result = $s3->putObject( $put_data ); +function hashDirectory($directory){ + if (! is_dir($directory)){ return false; } - if ( $result['@metadata']['statusCode'] === 200 ) { - \WP2Static\DeployCache::addFile( $cache_key, $namespace, $hash ); + $files = array(); + $dir = dir($directory); - if ( $cf_max_paths >= count( $cf_stale_paths ) ) { - $cf_key = $cache_key; - if ( 0 === substr_compare( $cf_key, '/index.html', -11 ) ) { - $cf_key = substr( $cf_key, 0, -10 ); - } - $cf_key = str_replace( ' ', '%20', $cf_key ); - array_push( $cf_stale_paths, $cf_key ); - } - } - } + while (false !== ($file = $dir->read())){ + if ($file != '.' and $file != '..') { + if (is_dir($directory . '/' . $file)) { $files[] = hashDirectory($directory . '/' . $file); } + else { $files[] = md5_file($directory . '/' . $file); } } + } - // Deploy 301 redirects. - - $put_data = $base_put_data; - $redirects = apply_filters( 'wp2static_list_redirects', [] ); - - foreach ( $redirects as $redirect ) { - $cache_key = $redirect['url']; - - if ( mb_substr( $cache_key, -1 ) === '/' ) { - $cache_key = $cache_key . 'index.html'; - } + $dir->close(); - $s3_key = - Controller::getValue( 's3RemotePath' ) ? - Controller::getValue( 's3RemotePath' ) . '/' . - ltrim( $cache_key, '/' ) : - ltrim( $cache_key, '/' ); + return md5(implode('', $files)); +} - $put_data['Key'] = $s3_key; - $put_data['WebsiteRedirectLocation'] = $redirect['redirect_to']; - $hash = md5( (string) json_encode( $put_data ) ); +class Deployer { - $is_cached = \WP2Static\DeployCache::fileisCached( - $cache_key, - $namespace, - $hash, - ); + const DEFAULT_NAMESPACE = 'wp2static-addon-copy/default'; - if ( $is_cached ) { - continue; - } + // prepare deploy, if modifies URL structure, should be an action + // $this->prepareDeploy(); - $result = $s3->putObject( $put_data ); + // options - load from addon's static methods - if ( $result['@metadata']['statusCode'] === 200 ) { - \WP2Static\DeployCache::addFile( $cache_key, $namespace, $hash ); + public function __construct() {} - if ( $cf_max_paths >= count( $cf_stale_paths ) ) { - $cf_key = $cache_key; - if ( 0 === substr_compare( $cf_key, '/index.html', -11 ) ) { - $cf_key = substr( $cf_key, 0, -10 ); - } - $cf_key = str_replace( ' ', '%20', $cf_key ); - array_push( $cf_stale_paths, $cf_key ); - } - } + public function uploadFiles( string $processed_site_path ) : void { + // check if dir exists + if ( ! is_dir( $processed_site_path ) ) { + $err = 'Processed folder does not exist: ' . $processed_site_path; + \WP2Static\WsLog::l( $err ); + return; } - $distribution_id = Controller::getValue( 'cfDistributionID' ); - $num_stale = count( $cf_stale_paths ); - if ( $distribution_id && $num_stale > 0 ) { - if ( $num_stale > $cf_max_paths ) { - WsLog::l( 'Invalidating all CloudFront paths' ); - self::invalidateItems( $distribution_id, [ '/*' ] ); - } else { - $path_text = ( $num_stale === 1 ) ? 'path' : 'paths'; - WsLog::l( "Invalidating $num_stale CloudFront $path_text" ); - self::invalidateItems( $distribution_id, $cf_stale_paths ); - } + $targetFolder = Controller::getValue( 'copyTargetFolder' ); + if (empty($targetFolder)) { + $err = 'You must specify the target folder in WP2Static > Addons > Copy Deployment > Configure'; + \WP2Static\WsLog::l( $err ); + return; } - } - - public static function s3Client() : \Aws\S3\S3Client { - $client_options = [ - 'version' => 'latest', - 'region' => Controller::getValue( 's3Region' ), - ]; - - /* - If no credentials option, SDK attempts to load credentials from - your environment in the following order: - - - environment variables. - - a credentials .ini file. - - an IAM role. - */ - if ( - Controller::getValue( 's3AccessKeyID' ) && - Controller::getValue( 's3SecretAccessKey' ) - ) { - $client_options['credentials'] = [ - 'key' => Controller::getValue( 's3AccessKeyID' ), - 'secret' => \WP2Static\CoreOptions::encrypt_decrypt( - 'decrypt', - Controller::getValue( 's3SecretAccessKey' ) - ), - ]; - } elseif ( Controller::getValue( 's3Profile' ) ) { - $client_options['profile'] = Controller::getValue( 's3Profile' ); + if ( ! is_dir( $targetFolder ) ) { + $err = 'Target folder does not exist: ' . $targetFolder; + \WP2Static\WsLog::l( $err ); + return; } - return new \Aws\S3\S3Client( $client_options ); - } - - public static function cloudfrontClient() : \Aws\CloudFront\CloudFrontClient { - /* - If no credentials option, SDK attempts to load credentials from - your environment in the following order: - - environment variables. - - a credentials .ini file. - - an IAM role. - */ - if ( - Controller::getValue( 'cfAccessKeyID' ) && - Controller::getValue( 'cfSecretAccessKey' ) - ) { - // Use the supplied access keys. - $credentials = new \Aws\Credentials\Credentials( - Controller::getValue( 'cfAccessKeyID' ), - \WP2Static\CoreOptions::encrypt_decrypt( - 'decrypt', - Controller::getValue( 'cfSecretAccessKey' ) - ) - ); - $client = \Aws\CloudFront\CloudFrontClient::factory( - [ - 'region' => Controller::getValue( 'cfRegion' ), - 'version' => 'latest', - 'credentials' => $credentials, - ] - ); - } elseif ( Controller::getValue( 'cfProfile' ) ) { - // Use the specified profile. - $client = \Aws\CloudFront\CloudFrontClient::factory( - [ - 'profile' => Controller::getValue( 'cfProfile' ), - 'region' => Controller::getValue( 'cfRegion' ), - 'version' => 'latest', - ] - ); - } else { - // Use the IAM role. - $client = \Aws\CloudFront\CloudFrontClient::factory( - [ - 'region' => Controller::getValue( 'cfRegion' ), - 'version' => 'latest', - ] - ); + $cleanTarget = intval( Controller::getValue( 'copyRemoveTarget' ) ) !== 0; + if ($cleanTarget) { + $err = 'Cleaning '. $targetFolder; + \WP2Static\WsLog::l( $err ); + rrmdir($targetFolder); + mkdir($targetFolder); } - return $client; - } - - /** - * Create invalidation in CloudFront - * - * @param mixed[] $items mixed array - */ - public static function createInvalidation( string $distribution_id, array $items ) : string { - $client = self::cloudfrontClient(); - - return $client->createInvalidation( - [ - 'DistributionId' => $distribution_id, - 'InvalidationBatch' => [ - 'CallerReference' => 'WP2Static S3 Add-on ' . time(), - 'Paths' => [ - 'Items' => $items, - 'Quantity' => count( $items ), - ], - ], - ] - ); - } - - /** - * Invalidate paths in CloudFront, catching and logging exceptions. - * - * @param mixed[] $items mixed array - */ - public static function invalidateItems( string $distribution_id, array $items ) : ?string { - try { - return self::createInvalidation( $distribution_id, $items ); - } catch ( AwsException $e ) { - WsLog::l( 'Error creating CloudFront invalidation: ' . $e->getMessage() ); - return null; + $err = 'Copying '. $processed_site_path . ' to ' . $targetFolder; + \WP2Static\WsLog::l( $err ); + xcopy($processed_site_path, $targetFolder); + $extraFolder = Controller::getValue( 'copyExtraFolder' ); + if (!empty($extraFolder)) { + if ( ! is_dir( $extraFolder ) ) { + $err = 'Extra folder does not exist: ' . $extraFolder; + \WP2Static\WsLog::l( $err ); + return; + } + $err = 'Copying '. $extraFolder . ' to ' . $targetFolder; + \WP2Static\WsLog::l( $err ); + xcopy($extraFolder, $targetFolder); } } - } diff --git a/src/MimeTypes.php b/src/MimeTypes.php index 68de5d8..86f536e 100755 --- a/src/MimeTypes.php +++ b/src/MimeTypes.php @@ -1,6 +1,6 @@ prefix . 'wp2static_addon_s3_options'; +$table_name = $wpdb->prefix . 'wp2static_addon_copy_options'; $wpdb->query( "DROP TABLE IF EXISTS $table_name" ); diff --git a/views/copy-page.php b/views/copy-page.php new file mode 100755 index 0000000..55eabf4 --- /dev/null +++ b/views/copy-page.php @@ -0,0 +1,83 @@ + + +

Copy to Folder Options

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + value === 1 ? 'checked' : ''; ?> + type="checkbox" + /> +
+ + + +
+ + + + +
+ + +
+ diff --git a/views/s3-page.php b/views/s3-page.php deleted file mode 100755 index d530879..0000000 --- a/views/s3-page.php +++ /dev/null @@ -1,275 +0,0 @@ - - -

S3 Deployment Options

- -

S3

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - -
- - - -
- - - -
- - - -
- - - -
- - - -
- - - -
- - -

CloudFront

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- - - -
- - - -
- - - -
- - - -
- - - -
- -
- - -
- diff --git a/wp2static-addon-copy.php b/wp2static-addon-copy.php new file mode 100755 index 0000000..23f6bd1 --- /dev/null +++ b/wp2static-addon-copy.php @@ -0,0 +1,42 @@ +run(); +} + +register_activation_hook( + __FILE__, + [ 'WP2StaticCopy\Controller', 'activate' ] +); + +register_deactivation_hook( + __FILE__, + [ 'WP2StaticCopy\Controller', 'deactivate' ] +); + +run_wp2static_addon_copy(); + diff --git a/wp2static-addon-s3.php b/wp2static-addon-s3.php deleted file mode 100644 index 912f129..0000000 --- a/wp2static-addon-s3.php +++ /dev/null @@ -1,42 +0,0 @@ -run(); -} - -register_activation_hook( - __FILE__, - [ 'WP2StaticS3\Controller', 'activate' ] -); - -register_deactivation_hook( - __FILE__, - [ 'WP2StaticS3\Controller', 'deactivate' ] -); - -run_wp2static_addon_s3(); -