Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
5t111111 committed Feb 8, 2024
0 parents commit 6915e70
Show file tree
Hide file tree
Showing 15 changed files with 1,647 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
vendor/
composer.lock

### PHPUnit ###
# Covers PHPUnit
# Reference: https://phpunit.de/

# Generated files
.phpunit.result.cache
.phpunit.cache

# PHPUnit
/app/phpunit.xml
/phpunit.xml

# Build data
/build/
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# WACK Cloudinary

**WACK Cloudinary** is a WordPress plugin to upload the media files to Cloudinary.

It hooks into the WordPress [`wp_handle_upload`](https://developer.wordpress.org/reference/hooks/wp_handle_upload/)
and when a media file is uploaded, it also uploads the file to Cloudinary.

It is created with the intention of being used with the WACK Stack, but it can also be used with other WordPress installations.

> [!IMPORTANT]
> This plugin does **NOT** replaces neither the media URLs in the content nor the URLs in the media library. This means you have to manually replace the URLs when displaying the media to users.
## Installation

- Requires PHP 8.1 or later
- Requires WordPress 6.0 or later
- Requires Composer

### Using Composer

```bash
composer require kodansha/wack-cloudinary
```

> [!NOTE]
> This plugin is not available on the WordPress.org plugin repository.
> For the moment, the only way to install it is to use Composer.
## How to use

### Pre-requisites

You need to set up the Cloudinary account and [set the credentials in the environment variables](https://cloudinary.com/documentation/php_integration#setting_the_cloudinary_url_environment_variable).

```shell
export CLOUDINARY_URL=cloudinary://<api_key>:<api_secret>@<cloud_name>
```

> [!TIP]
> It strongly recommended to use the `.env` file to set the environment variables, especially in the local development environment.
### Configuration

You might want to define settings through the `WACK_CLOUDINARY_SETTINGS` constant:

```php
define('WACK_CLOUDINARY_SETTINGS', [
// Optional: The type of the Cloudinary media access. Possible values are 'authenticated', 'upload', 'private'
// Default: 'upload'
'type' => 'private',

// Optional: The Cloudinary root folder to upload the media files.
// Default: none
'root_folder' => 'my-root-folder',

// Optional: The notification URL endpoint to receive the Cloudinary notifications.
// Default: none
'notification_url' => 'https://example.com/cloudinary-notification',

// Optional: The username and password for the basic authentication.
// If your WordPress is behind the basic authentication, you need to set this to work the async requests.
// Default: none
'basic_auth' => [
'username' => 'example-user',
'password' => 'example-password',
]
]);
```

### Upload media files

After setting the above pre-requisites and configuration, when you upload a media file to the WordPres, the file is also uploaded to Cloudinary.

## TODO

- Support video upload
- Support eager transformation
- Support upload presets
39 changes: 39 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "kodansha/wack-cloudinary",
"description": "Uploads the uploaded media files to Cloudinary",
"keywords": [
"wordpress",
"plugin"
],
"type": "wordpress-plugin",
"authors": [
{
"name": "KODANSHA Ltd.",
"homepage": "https://github.com/kodansha"
},
{
"name": "Hirofumi Wakasugi",
"homepage": "https://github.com/5t111111"
}
],
"homepage": "https://github.com/kodansha/wack-cloudinary",
"license": "GPL-3.0-or-later",
"require": {
"php": ">=8.1",
"cloudinary/cloudinary_php": "^2.12"
},
"require-dev": {
"10up/wp_mock": "^0.5.0",
"phpunit/phpunit": "^9.6",
"squizlabs/php_codesniffer": "^3.8"
},
"autoload": {
"psr-4": {
"WackCloudinary\\": "src"
}
},
"config": {
"sort-packages": true,
"optimize-autoloader": true
}
}
31 changes: 31 additions & 0 deletions phpcs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0"?>
<ruleset name="WPStandard">
<description>WP Standard Coding Standards</description>

<!-- Scan all files in directory -->
<file>.</file>

<!-- Scan only PHP files -->
<arg name="extensions" value="php"/>

<!-- Ignore Composer dependencies -->
<exclude-pattern>vendor/</exclude-pattern>

<!-- Show colors in console -->
<arg value="-colors"/>

<!-- Show sniff codes in all reports -->
<arg value="ns"/>

<!-- Use PSR-12 as a base -->
<rule ref="PSR12"/>

<!-- Custom Rules -->
<rule ref="Generic.Arrays.ArrayIndent"/>
<rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
<rule ref="Generic.PHP.DeprecatedFunctions"/>
<rule ref="Generic.Commenting.DocComment"/>
<rule ref="Squiz.Strings.DoubleQuoteUsage"/>
<rule ref="Squiz.WhiteSpace.SemicolonSpacing"/>
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace"/>
</ruleset>
10 changes: 10 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<phpunit bootstrap="tests/bootstrap.php" colors="true">
<testsuites>
<testsuite name="Wack Cloudinary Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<php>
<const name="PHPUNIT" value="true"/>
</php>
</phpunit>
42 changes: 42 additions & 0 deletions src/BasicAuthHook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace WackCloudinary;

/**
* Class BasicAuthHook
*
* See: https://github.com/deliciousbrains/wp-background-processing?tab=readme-ov-file#basicauth
*
* @package WackCloudinary
*/
final class BasicAuthHook
{
/**
* Initialize the hooks
*/
public function init()
{
add_filter('http_request_args', [$this, 'httpRequestArgs'], 10, 2);
}

/**
* Add basic auth to the HTTP request
*
* @param array $parsed_args An array of HTTP request arguments.
* @param string $url The request URL.
*
* @return array The modified array of HTTP request arguments.
*/
public function httpRequestArgs(array $parsed_args, string $url)
{
$basicAuth = PluginSettings::get()->basicAuth();

if (!$basicAuth) {
return $parsed_args;
}

$parsed_args['headers']['Authorization'] = 'Basic ' . base64_encode($basicAuth['username'] . ':' . $basicAuth['password']);

return $parsed_args;
}
}
91 changes: 91 additions & 0 deletions src/CloudinaryUploadJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace WackCloudinary;

use Cloudinary\Api\Upload\UploadApi;

/**
* Class CloudinaryUploadJob
*
* This class is responsible for async uploading files to Cloudinary.
*
* @package WackCloudinary
*/
final class CloudinaryUploadJob extends WP_Async_Request
{
protected $prefix = 'wack-cloudinary';
protected $action = 'cloudinary-upload-job';

/**
* Handle a dispatched request.
*
* It retrieves the file_path, public_id, folder, resource_type, type, eager and notification_url from the $_POST array and uploads the file to Cloudinary.
*
* - file_path: The path to the file to be uploaded
* - public_id: The public ID of the file in Cloudinary
* - folder: The folder in Cloudinary where the file will be uploaded
* - resource_type: The type of resource to be uploaded. Possible values are 'image', 'raw', 'video', 'auto'
* - type: The type of the file to be uploaded. Possible values are 'authenticated', 'upload', 'private'
* - eager: The eager transformations to be performed on the file after upload
* - notification_url: The URL to be notified when the upload and the eager-transformation is complete
*/
protected function handle()
{
logger('CloudinaryUploadJob is running... 1');

// sleep(10);

logger('CloudinaryUploadJob is running... 2');

$file_path = $_POST['file_path'];
$public_id = $_POST['public_id'];
$folder = $_POST['folder'];
$resource_type = $_POST['resource_type'];
$type = $_POST['type'];
$eager = $_POST['eager'];
$notification_url = $_POST['notification_url'];

if (empty($file_path) || empty($public_id)) {
return;
}

if (empty($folder)) {
$folder = PluginSettings::get()->rootFolder();
} else {
$folder = PluginSettings::get()->rootFolder() . '/' . $folder;
}

if (empty($resource_type)) {
$resource_type = 'auto';
}

if (empty($type)) {
$type = 'upload';
}

if (empty($eager)) {
$eager = [];
}

if (empty($notification_url)) {
$notification_url = null;
}

logger('CloudinaryUploadJob is running... 3');

(new UploadApi())->upload($file_path, [
'public_id' => $public_id,
'folder' => $folder,
'type' => $type,
'resource_type' => $resource_type,
'eager' => $eager,
'eager_async' => true,
'overwrite' => true,
'invalidate' => true,
'notification_url' => $notification_url,
'eager_notification_url' => empty($eager) ? null : $notification_url
]);

logger('CloudinaryUploadJob is running... 4');
}
}
28 changes: 28 additions & 0 deletions src/Constants.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace WackCloudinary;

/**
* Class Constant
*
* @package WackCloudinary
*/
final class Constants
{
/**
* Get the settings from the 'WACK_CLOUDINARY_SETTINGS' constant.
*
* This method checks if the 'WACK_CLOUDINARY_SETTINGS' constant is defined.
* If it is, it returns the value of the constant. If it's not, it returns an empty array.
*
* @return array The settings from the 'WACK_CLOUDINARY_SETTINGS' constant, or an empty array if the constant is not defined.
*/
public static function settingsConstant(): array
{
if (defined('WACK_CLOUDINARY_SETTINGS')) {
return constant('WACK_CLOUDINARY_SETTINGS');
} else {
return [];
}
}
}
Loading

0 comments on commit 6915e70

Please sign in to comment.