mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 18:16:38 +08:00
init
This commit is contained in:
parent
ba97d7143d
commit
779eb31e4e
53 changed files with 8475 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
||||||
/vendor/
|
/vendor/
|
||||||
|
/modules/
|
||||||
|
node_modules
|
||||||
phpunit.xml
|
phpunit.xml
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
composer.lock
|
composer.lock
|
||||||
|
|
|
@ -11,7 +11,33 @@
|
||||||
"role": "Company"
|
"role": "Company"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"url": "modules.local/ppcp-button"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"url": "modules.local/ppcp-api-client"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"url": "modules.local/ppcp-wc-gateway"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"url": "modules.local/ppcp-session"
|
||||||
|
}
|
||||||
|
],
|
||||||
"require": {
|
"require": {
|
||||||
|
"dhii/module-interface": "0.2.x-dev",
|
||||||
|
"psr/container": "^1.0",
|
||||||
|
"inpsyde/ppcp-button": "dev-master",
|
||||||
|
"inpsyde/ppcp-wc-gateway": "dev-master",
|
||||||
|
"oomphinc/composer-installers-extender": "^1.1",
|
||||||
|
"container-interop/service-provider": "^0.4.0",
|
||||||
|
"dhii/containers": "dev-develop",
|
||||||
|
"dhii/wp-containers": "^0.1.0@alpha"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"inpsyde/php-coding-standards": "@stable"
|
"inpsyde/php-coding-standards": "@stable"
|
||||||
|
@ -27,5 +53,20 @@
|
||||||
"ci": [
|
"ci": [
|
||||||
"vendor/bin/phpcs"
|
"vendor/bin/phpcs"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"installer-types": [
|
||||||
|
"inpsyde-module"
|
||||||
|
],
|
||||||
|
"installer-paths": {
|
||||||
|
"modules/{$name}/": [
|
||||||
|
"type:inpsyde-module"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hooks": {
|
||||||
|
"pre-commit": [
|
||||||
|
"vendor/bin/phpcbf"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
modules.local/ppcp-api-client/composer.json
Normal file
13
modules.local/ppcp-api-client/composer.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "inpsyde/ppcp-api-client",
|
||||||
|
"type": "inpsyde-module",
|
||||||
|
"require": {
|
||||||
|
"dhii/module-interface": "0.2.x-dev",
|
||||||
|
"inpsyde/ppcp-session": "dev-master"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Inpsyde\\PayPalCommerce\\ApiClient\\": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
modules.local/ppcp-api-client/extensions.php
Normal file
8
modules.local/ppcp-api-client/extensions.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
];
|
11
modules.local/ppcp-api-client/module.php
Normal file
11
modules.local/ppcp-api-client/module.php
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient;
|
||||||
|
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
|
||||||
|
return function (): ModuleInterface {
|
||||||
|
return new ApiModule();
|
||||||
|
};
|
46
modules.local/ppcp-api-client/services.php
Normal file
46
modules.local/ppcp-api-client/services.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient;
|
||||||
|
|
||||||
|
use Dhii\Data\Container\ContainerInterface;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Factory\LineItemFactory;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
'api.host' => function(ContainerInterface $container) : string {
|
||||||
|
return 'https://api.sandbox.paypal.com';
|
||||||
|
},
|
||||||
|
'api.key' => function(ContainerInterface $container) : string {
|
||||||
|
return 'AQB97CzMsd58-It1vxbcDAGvMuXNCXRD9le_XUaMlHB_U7XsU9IiItBwGQOtZv9sEeD6xs2vlIrL4NiD';
|
||||||
|
},
|
||||||
|
'api.secret' => function(ContainerInterface $container) : string {
|
||||||
|
return 'EILGMYK_0iiSbja8hT-nCBGl0BvKxEB4riHgyEO7QWDeUzCJ5r42JUEvrI7gpGyw0Qww8AIXxSdCIAny';
|
||||||
|
},
|
||||||
|
'api.bearer' => function(ContainerInterface $container) : Bearer {
|
||||||
|
return new Bearer(
|
||||||
|
$container->get('api.host'),
|
||||||
|
$container->get('api.key'),
|
||||||
|
$container->get('api.secret')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
'api.endpoint.order' => function(ContainerInterface $container) : OrderEndpoint {
|
||||||
|
$sessionHandler = $container->get('session.handler');
|
||||||
|
return new OrderEndpoint(
|
||||||
|
$container->get('api.host'),
|
||||||
|
$container->get('api.bearer'),
|
||||||
|
$sessionHandler
|
||||||
|
);
|
||||||
|
},
|
||||||
|
'api.cart-repository' => function(ContainerInterface $container) : CartRepository {
|
||||||
|
$cart = WC()->cart;
|
||||||
|
$factory = $container->get('api.line-item-factory');
|
||||||
|
return new CartRepository($cart, $factory);
|
||||||
|
},
|
||||||
|
'api.line-item-factory' => function(ContainerInterface $container) : LineItemFactory {
|
||||||
|
return new LineItemFactory();
|
||||||
|
},
|
||||||
|
];
|
28
modules.local/ppcp-api-client/src/ApiModule.php
Normal file
28
modules.local/ppcp-api-client/src/ApiModule.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient;
|
||||||
|
|
||||||
|
|
||||||
|
use Dhii\Container\ServiceProvider;
|
||||||
|
use Dhii\Modular\Module\Exception\ModuleExceptionInterface;
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
use Interop\Container\ServiceProviderInterface;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
class ApiModule implements ModuleInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function setup(): ServiceProviderInterface
|
||||||
|
{
|
||||||
|
return new ServiceProvider(
|
||||||
|
require __DIR__.'/../services.php',
|
||||||
|
require __DIR__.'/../extensions.php'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(ContainerInterface $c)
|
||||||
|
{
|
||||||
|
// TODO: Implement run() method.
|
||||||
|
}
|
||||||
|
}
|
57
modules.local/ppcp-api-client/src/Authentication/Bearer.php
Normal file
57
modules.local/ppcp-api-client/src/Authentication/Bearer.php
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient\Authentication;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
|
|
||||||
|
class Bearer
|
||||||
|
{
|
||||||
|
private const CACHE_KEY = 'ppcp-bearer';
|
||||||
|
private $host;
|
||||||
|
private $key;
|
||||||
|
private $secret;
|
||||||
|
public function __construct(string $host, string $key, string $secret)
|
||||||
|
{
|
||||||
|
$this->host = $host;
|
||||||
|
$this->key = $key;
|
||||||
|
$this->secret = $secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bearer() : string
|
||||||
|
{
|
||||||
|
//ToDo: Do not store with wp_cache_get but as transient.
|
||||||
|
$bearer = wp_cache_get(self::CACHE_KEY);
|
||||||
|
if ( ! $bearer) {
|
||||||
|
return $this->newBearer();
|
||||||
|
}
|
||||||
|
return (string) $bearer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newBearer() : string
|
||||||
|
{
|
||||||
|
$url = trailingslashit($this->host) . 'v1/oauth2/token?grant_type=client_credentials';
|
||||||
|
$args = [
|
||||||
|
'headers' => [
|
||||||
|
'Authorization' => 'Basic ' . base64_encode($this->key . ':' . $this->secret),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$response = wp_remote_post(
|
||||||
|
$url,
|
||||||
|
$args
|
||||||
|
);
|
||||||
|
|
||||||
|
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
|
||||||
|
throw new RuntimeException(__('Could not create token.', 'woocommerce-paypal-commerce-gateway'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = json_decode($response['body']);
|
||||||
|
if (! isset($json->access_token) || ! isset($json->expires_in)) {
|
||||||
|
throw new RuntimeException(__('Could not find token.', 'woocommerce-paypal-commerce-gateway'));
|
||||||
|
}
|
||||||
|
$token = (string) $json->access_token;
|
||||||
|
wp_cache_set(self::CACHE_KEY, $token, $json->expires_in);
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
}
|
79
modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php
Normal file
79
modules.local/ppcp-api-client/src/Endpoint/OrderEndpoint.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient\Endpoint;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\LineItem;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
|
use Inpsyde\PayPalCommerce\Session\SessionHandler;
|
||||||
|
|
||||||
|
class OrderEndpoint
|
||||||
|
{
|
||||||
|
|
||||||
|
private $host;
|
||||||
|
private $bearer;
|
||||||
|
private $sessionHandler;
|
||||||
|
public function __construct(string $host, Bearer $bearer, SessionHandler $sessionHandler)
|
||||||
|
{
|
||||||
|
$this->host = $host;
|
||||||
|
$this->bearer = $bearer;
|
||||||
|
$this->sessionHandler = $sessionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createForLineItems(LineItem ...$items) : ?Order {
|
||||||
|
|
||||||
|
$bearer = $this->bearer->bearer();
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'intent' => 'CAPTURE',
|
||||||
|
'purchase_units' => array_map(
|
||||||
|
function(LineItem $item) : array {
|
||||||
|
return $item->toArray();
|
||||||
|
},
|
||||||
|
$items
|
||||||
|
),
|
||||||
|
];
|
||||||
|
$url = trailingslashit($this->host) . 'v2/checkout/orders';
|
||||||
|
$args = [
|
||||||
|
'headers' => [
|
||||||
|
'Authorization' => 'Bearer ' . $bearer,
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'Prefer' => 'return=representation',
|
||||||
|
],
|
||||||
|
'body' => json_encode($data),
|
||||||
|
];
|
||||||
|
$response = wp_remote_post($url, $args);
|
||||||
|
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 201) {
|
||||||
|
throw new RuntimeException(__('Could not create order.', 'woocommerce-paypal-commerce-gateway'));
|
||||||
|
}
|
||||||
|
$json = json_decode($response['body']);
|
||||||
|
$order = new Order($json);
|
||||||
|
$this->sessionHandler->setOrder($order);
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function capture(Order $order) : Order
|
||||||
|
{
|
||||||
|
|
||||||
|
$bearer = $this->bearer->bearer();
|
||||||
|
$url = trailingslashit($this->host) . 'v2/checkout/orders/' . $order->id() . '/capture';
|
||||||
|
$args = [
|
||||||
|
'headers' => [
|
||||||
|
'Authorization' => 'Bearer ' . $bearer,
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'Prefer' => 'return=representation',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$response = wp_remote_post($url, $args);
|
||||||
|
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 201) {
|
||||||
|
throw new RuntimeException(__('Could not capture order.', 'woocommerce-paypal-commerce-gateway'));
|
||||||
|
}
|
||||||
|
$json = json_decode($response['body']);
|
||||||
|
$order = new Order($json);
|
||||||
|
$this->sessionHandler->setOrder($order);
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
}
|
46
modules.local/ppcp-api-client/src/Entity/LineItem.php
Normal file
46
modules.local/ppcp-api-client/src/Entity/LineItem.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
|
||||||
|
|
||||||
|
|
||||||
|
class LineItem
|
||||||
|
{
|
||||||
|
|
||||||
|
private $data;
|
||||||
|
public function __construct(\stdClass $data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function referenceId() : int {
|
||||||
|
return $this->data->reference_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function description() : string {
|
||||||
|
return $this->data->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function quantity() : float {
|
||||||
|
return $this->data->quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalAmount() : float {
|
||||||
|
return $this->data->total_amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function currencyCode() : string {
|
||||||
|
return $this->data->currency_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray() : array {
|
||||||
|
return [
|
||||||
|
'reference_id' => $this->referenceId(),
|
||||||
|
'description' => $this->quantity() . '× ' . $this->description(),
|
||||||
|
'amount' => [
|
||||||
|
'value' => $this->totalAmount(),
|
||||||
|
'currency_code' => $this->currencyCode(),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
43
modules.local/ppcp-api-client/src/Entity/Order.php
Normal file
43
modules.local/ppcp-api-client/src/Entity/Order.php
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient\Entity;
|
||||||
|
|
||||||
|
|
||||||
|
class Order
|
||||||
|
{
|
||||||
|
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Order constructor.
|
||||||
|
*
|
||||||
|
* @param \stdClass $data $data is formed like the PayPal create order response.
|
||||||
|
*
|
||||||
|
* @see https://developer.paypal.com/docs/api/orders/v2/#orders-create-response
|
||||||
|
*/
|
||||||
|
public function __construct(\stdClass $data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function id() : string {
|
||||||
|
return $this->data->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isApproved() : bool {
|
||||||
|
return $this->data->status === 'APPROVED';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isCompleted() : bool {
|
||||||
|
return $this->data->status === 'COMPLETED';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isCreated() : bool {
|
||||||
|
return $this->data->status === 'CREATED';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray() : array {
|
||||||
|
return (array) $this->data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class RuntimeException extends \RuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient\Factory;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\LineItem;
|
||||||
|
|
||||||
|
class LineItemFactory
|
||||||
|
{
|
||||||
|
|
||||||
|
public function fromWoocommerceLineItem(array $lineItem, string $currencyCode) : ?LineItem {
|
||||||
|
if (! $this->validateWoocommerceLineItem($lineItem)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$product = $lineItem['data'];
|
||||||
|
/**
|
||||||
|
* @var \WC_Product $product
|
||||||
|
*/
|
||||||
|
$data = (object) [
|
||||||
|
'reference_id' => $product->get_id(),
|
||||||
|
'quantity' => $lineItem['quantity'],
|
||||||
|
'description' => $product->get_name(),
|
||||||
|
'currency_code' => $currencyCode,
|
||||||
|
'total_amount' => $lineItem['line_subtotal'],
|
||||||
|
];
|
||||||
|
|
||||||
|
return new LineItem($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateWoocommerceLineItem(array $lineItem) : bool {
|
||||||
|
|
||||||
|
$validate = [
|
||||||
|
'data' => function($value) : bool {
|
||||||
|
return is_a($value, \WC_Product::class);
|
||||||
|
},
|
||||||
|
'quantity' => 'is_numeric',
|
||||||
|
'line_subtotal' => 'is_numeric',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($validate as $key => $validator) {
|
||||||
|
if (! isset($lineItem[$key]) || ! $validator($lineItem[$key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient\Repository;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\LineItem;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Factory\LineItemFactory;
|
||||||
|
|
||||||
|
class CartRepository implements LineItemRepositoryInterface
|
||||||
|
{
|
||||||
|
private $cart;
|
||||||
|
private $factory;
|
||||||
|
public function __construct(\WC_Cart $cart, LineItemFactory $factory)
|
||||||
|
{
|
||||||
|
$this->cart = $cart;
|
||||||
|
$this->factory = $factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all LineItem of the Woocommerce cart.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function all() : array {
|
||||||
|
|
||||||
|
return array_map(
|
||||||
|
function(array $lineItem) : LineItem {
|
||||||
|
return $this->factory->fromWoocommerceLineItem($lineItem, get_woocommerce_currency());
|
||||||
|
},
|
||||||
|
array_values($this->cart->get_cart())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\ApiClient\Repository;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\LineItem;
|
||||||
|
|
||||||
|
interface LineItemRepositoryInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return LineItem[]
|
||||||
|
*/
|
||||||
|
public function all() : array;
|
||||||
|
}
|
1
modules.local/ppcp-button/.gitignore
vendored
Normal file
1
modules.local/ppcp-button/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/node_modules/
|
414
modules.local/ppcp-button/assets/js/button.js
Normal file
414
modules.local/ppcp-button/assets/js/button.js
Normal file
|
@ -0,0 +1,414 @@
|
||||||
|
/******/ (function(modules) { // webpackBootstrap
|
||||||
|
/******/ // The module cache
|
||||||
|
/******/ var installedModules = {};
|
||||||
|
/******/
|
||||||
|
/******/ // The require function
|
||||||
|
/******/ function __webpack_require__(moduleId) {
|
||||||
|
/******/
|
||||||
|
/******/ // Check if module is in cache
|
||||||
|
/******/ if(installedModules[moduleId]) {
|
||||||
|
/******/ return installedModules[moduleId].exports;
|
||||||
|
/******/ }
|
||||||
|
/******/ // Create a new module (and put it into the cache)
|
||||||
|
/******/ var module = installedModules[moduleId] = {
|
||||||
|
/******/ i: moduleId,
|
||||||
|
/******/ l: false,
|
||||||
|
/******/ exports: {}
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Execute the module function
|
||||||
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||||
|
/******/
|
||||||
|
/******/ // Flag the module as loaded
|
||||||
|
/******/ module.l = true;
|
||||||
|
/******/
|
||||||
|
/******/ // Return the exports of the module
|
||||||
|
/******/ return module.exports;
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // expose the modules object (__webpack_modules__)
|
||||||
|
/******/ __webpack_require__.m = modules;
|
||||||
|
/******/
|
||||||
|
/******/ // expose the module cache
|
||||||
|
/******/ __webpack_require__.c = installedModules;
|
||||||
|
/******/
|
||||||
|
/******/ // define getter function for harmony exports
|
||||||
|
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||||
|
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||||
|
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // define __esModule on exports
|
||||||
|
/******/ __webpack_require__.r = function(exports) {
|
||||||
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||||
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||||
|
/******/ }
|
||||||
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // create a fake namespace object
|
||||||
|
/******/ // mode & 1: value is a module id, require it
|
||||||
|
/******/ // mode & 2: merge all properties of value into the ns
|
||||||
|
/******/ // mode & 4: return value when already ns object
|
||||||
|
/******/ // mode & 8|1: behave like require
|
||||||
|
/******/ __webpack_require__.t = function(value, mode) {
|
||||||
|
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||||
|
/******/ if(mode & 8) return value;
|
||||||
|
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||||
|
/******/ var ns = Object.create(null);
|
||||||
|
/******/ __webpack_require__.r(ns);
|
||||||
|
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||||
|
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||||
|
/******/ return ns;
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||||
|
/******/ __webpack_require__.n = function(module) {
|
||||||
|
/******/ var getter = module && module.__esModule ?
|
||||||
|
/******/ function getDefault() { return module['default']; } :
|
||||||
|
/******/ function getModuleExports() { return module; };
|
||||||
|
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||||
|
/******/ return getter;
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Object.prototype.hasOwnProperty.call
|
||||||
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||||
|
/******/
|
||||||
|
/******/ // __webpack_public_path__
|
||||||
|
/******/ __webpack_require__.p = "";
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // Load entry module and return exports
|
||||||
|
/******/ return __webpack_require__(__webpack_require__.s = "./resources/js/button.js");
|
||||||
|
/******/ })
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ ({
|
||||||
|
|
||||||
|
/***/ "./resources/js/button.js":
|
||||||
|
/*!********************************!*\
|
||||||
|
!*** ./resources/js/button.js ***!
|
||||||
|
\********************************/
|
||||||
|
/*! no exports provided */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
/* harmony import */ var _modules_Renderer__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./modules/Renderer */ "./resources/js/modules/Renderer.js");
|
||||||
|
/* harmony import */ var _modules_SingleProductConfig__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules/SingleProductConfig */ "./resources/js/modules/SingleProductConfig.js");
|
||||||
|
/* harmony import */ var _modules_UpdateCart__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./modules/UpdateCart */ "./resources/js/modules/UpdateCart.js");
|
||||||
|
/* harmony import */ var _modules_ErrorHandler__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./modules/ErrorHandler */ "./resources/js/modules/ErrorHandler.js");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
if (!typeof PayPalCommerceGateway) {
|
||||||
|
console.error('PayPal button could not be configured.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!document.querySelector(PayPalCommerceGateway.button.wrapper)) {
|
||||||
|
console.error('No wrapper for PayPal button found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const context = PayPalCommerceGateway.context;
|
||||||
|
if (context === 'product' && !document.querySelector('form.cart')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorHandler = new _modules_ErrorHandler__WEBPACK_IMPORTED_MODULE_3__["default"]();
|
||||||
|
const renderer = new _modules_Renderer__WEBPACK_IMPORTED_MODULE_0__["default"]({
|
||||||
|
url: PayPalCommerceGateway.button.url,
|
||||||
|
wrapper: PayPalCommerceGateway.button.wrapper
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateCart = new _modules_UpdateCart__WEBPACK_IMPORTED_MODULE_2__["default"](PayPalCommerceGateway.ajax.change_cart.endpoint, PayPalCommerceGateway.ajax.change_cart.nonce);
|
||||||
|
let configurator = null;
|
||||||
|
if (context === 'product') {
|
||||||
|
configurator = new _modules_SingleProductConfig__WEBPACK_IMPORTED_MODULE_1__["default"](PayPalCommerceGateway, updateCart, renderer.showButtons.bind(renderer), renderer.hideButtons.bind(renderer), document.querySelector('form.cart'), errorHandler);
|
||||||
|
}
|
||||||
|
if (!configurator) {
|
||||||
|
console.error('No context for button found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderer.render(configurator.configuration());
|
||||||
|
});
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./resources/js/modules/ButtonsToggleListener.js":
|
||||||
|
/*!*******************************************************!*\
|
||||||
|
!*** ./resources/js/modules/ButtonsToggleListener.js ***!
|
||||||
|
\*******************************************************/
|
||||||
|
/*! exports provided: default */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
/**
|
||||||
|
* When you can't add something to the cart, the PayPal buttons should not show.
|
||||||
|
* Therefore we listen for changes on the add to cart button and show/hide the buttons accordingly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ButtonsToggleListener {
|
||||||
|
constructor(element, showCallback, hideCallback) {
|
||||||
|
this.element = element;
|
||||||
|
this.showCallback = showCallback;
|
||||||
|
this.hideCallback = hideCallback;
|
||||||
|
this.observer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
const config = { attributes: true };
|
||||||
|
const callback = () => {
|
||||||
|
if (this.element.classList.contains('disabled')) {
|
||||||
|
this.hideCallback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.showCallback();
|
||||||
|
};
|
||||||
|
this.observer = new MutationObserver(callback);
|
||||||
|
this.observer.observe(this.element, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
this.observer.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (ButtonsToggleListener);
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./resources/js/modules/ErrorHandler.js":
|
||||||
|
/*!**********************************************!*\
|
||||||
|
!*** ./resources/js/modules/ErrorHandler.js ***!
|
||||||
|
\**********************************************/
|
||||||
|
/*! exports provided: default */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
class ErrorHandler {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.wrapper = document.querySelector('.woocommerce-notices-wrapper');
|
||||||
|
}
|
||||||
|
|
||||||
|
message(text) {
|
||||||
|
this.wrapper.classList.add('woocommerce-error');
|
||||||
|
this.wrapper.innerText = this.sanitize(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitize(text) {
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
textarea.innerHTML = text;
|
||||||
|
return textarea.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
if (!this.wrapper.classList.contains('woocommerce-error')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.wrapper.classList.remove('woocommerce-error');
|
||||||
|
this.wrapper.innerText = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (ErrorHandler);
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./resources/js/modules/Renderer.js":
|
||||||
|
/*!******************************************!*\
|
||||||
|
!*** ./resources/js/modules/Renderer.js ***!
|
||||||
|
\******************************************/
|
||||||
|
/*! exports provided: default */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
class Renderer {
|
||||||
|
|
||||||
|
constructor(config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(buttonConfig) {
|
||||||
|
|
||||||
|
const script = document.createElement('script');
|
||||||
|
|
||||||
|
if (typeof paypal !== 'object') {
|
||||||
|
script.setAttribute('src', this.config.url);
|
||||||
|
script.addEventListener('load', event => {
|
||||||
|
this.renderButtons(buttonConfig);
|
||||||
|
});
|
||||||
|
document.body.append(script);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderButtons(buttonConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderButtons(buttonConfig) {
|
||||||
|
|
||||||
|
paypal.Buttons(buttonConfig).render(this.config.wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideButtons() {
|
||||||
|
document.querySelector(this.config.wrapper).style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
showButtons() {
|
||||||
|
document.querySelector(this.config.wrapper).style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (Renderer);
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./resources/js/modules/SingleProductConfig.js":
|
||||||
|
/*!*****************************************************!*\
|
||||||
|
!*** ./resources/js/modules/SingleProductConfig.js ***!
|
||||||
|
\*****************************************************/
|
||||||
|
/*! exports provided: default */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
/* harmony import */ var _ButtonsToggleListener__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ButtonsToggleListener */ "./resources/js/modules/ButtonsToggleListener.js");
|
||||||
|
|
||||||
|
|
||||||
|
class SingleProductConfig {
|
||||||
|
|
||||||
|
constructor(config, updateCart, showButtonCallback, hideButtonCallback, formElement, errorHandler) {
|
||||||
|
this.config = config;
|
||||||
|
this.updateCart = updateCart;
|
||||||
|
this.showButtonCallback = showButtonCallback;
|
||||||
|
this.hideButtonCallback = hideButtonCallback;
|
||||||
|
this.formElement = formElement;
|
||||||
|
this.errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration() {
|
||||||
|
|
||||||
|
if (this.hasVariations()) {
|
||||||
|
const observer = new _ButtonsToggleListener__WEBPACK_IMPORTED_MODULE_0__["default"](this.formElement.querySelector('.single_add_to_cart_button'), this.showButtonCallback, this.hideButtonCallback);
|
||||||
|
observer.init();
|
||||||
|
}
|
||||||
|
const onApprove = (data, actions) => {
|
||||||
|
return actions.redirect(this.config.redirect);
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
createOrder: this.createOrder(),
|
||||||
|
onApprove,
|
||||||
|
onError: error => {
|
||||||
|
this.errorHandler.message(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
createOrder() {
|
||||||
|
const createOrder = (data, actions) => {
|
||||||
|
this.errorHandler.clear();
|
||||||
|
const product = document.querySelector('[name="add-to-cart"]').value;
|
||||||
|
const qty = document.querySelector('[name="quantity"]').value;
|
||||||
|
const variations = this.variations();
|
||||||
|
|
||||||
|
const onResolve = purchase_units => {
|
||||||
|
return fetch(this.config.ajax.create_order.endpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
nonce: this.config.ajax.create_order.nonce,
|
||||||
|
purchase_units
|
||||||
|
})
|
||||||
|
}).then(function (res) {
|
||||||
|
return res.json();
|
||||||
|
}).then(function (data) {
|
||||||
|
if (!data.success) {
|
||||||
|
//Todo: Error handling
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return data.data.id;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const promise = this.updateCart.update(onResolve, product, qty, variations);
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
return createOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
variations() {
|
||||||
|
|
||||||
|
if (!this.hasVariations()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const attributes = [...this.formElement.querySelectorAll("[name^='attribute_']")].map(element => {
|
||||||
|
return {
|
||||||
|
value: element.value,
|
||||||
|
name: element.name
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasVariations() {
|
||||||
|
return this.formElement.classList.contains('variations_form');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (SingleProductConfig);
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./resources/js/modules/UpdateCart.js":
|
||||||
|
/*!********************************************!*\
|
||||||
|
!*** ./resources/js/modules/UpdateCart.js ***!
|
||||||
|
\********************************************/
|
||||||
|
/*! exports provided: default */
|
||||||
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
class UpdateCart {
|
||||||
|
|
||||||
|
constructor(endpoint, nonce) {
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(onResolve, product, qty, variations) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fetch(this.endpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
nonce: this.nonce,
|
||||||
|
product,
|
||||||
|
qty,
|
||||||
|
variations
|
||||||
|
})
|
||||||
|
}).then(result => {
|
||||||
|
return result.json();
|
||||||
|
}).then(result => {
|
||||||
|
if (!result.success) {
|
||||||
|
reject(result.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolved = onResolve(result.data);
|
||||||
|
resolve(resolved);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* harmony default export */ __webpack_exports__["default"] = (UpdateCart);
|
||||||
|
|
||||||
|
/***/ })
|
||||||
|
|
||||||
|
/******/ });
|
||||||
|
//# sourceMappingURL=button.js.map
|
1
modules.local/ppcp-button/assets/js/button.js.map
Normal file
1
modules.local/ppcp-button/assets/js/button.js.map
Normal file
File diff suppressed because one or more lines are too long
13
modules.local/ppcp-button/composer.json
Normal file
13
modules.local/ppcp-button/composer.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "inpsyde/ppcp-button",
|
||||||
|
"type": "inpsyde-module",
|
||||||
|
"require": {
|
||||||
|
"dhii/module-interface": "0.2.x-dev",
|
||||||
|
"inpsyde/ppcp-api-client": "dev-master"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Inpsyde\\PayPalCommerce\\Button\\": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
modules.local/ppcp-button/extensions.php
Normal file
5
modules.local/ppcp-button/extensions.php
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
];
|
10
modules.local/ppcp-button/module.php
Normal file
10
modules.local/ppcp-button/module.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Button;
|
||||||
|
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
|
||||||
|
return function (): ModuleInterface {
|
||||||
|
return new ButtonModule();
|
||||||
|
};
|
6344
modules.local/ppcp-button/package-lock.json
generated
Normal file
6344
modules.local/ppcp-button/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
23
modules.local/ppcp-button/package.json
Normal file
23
modules.local/ppcp-button/package.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "ppc-button",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"main": "resources/js/button.js",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-core": "^6.25.0",
|
||||||
|
"babel-loader": "^7.1.1",
|
||||||
|
"babel-preset-env": "^1.6.0",
|
||||||
|
"cross-env": "^5.0.1",
|
||||||
|
"file-loader": "^4.2.0",
|
||||||
|
"node-sass": "^4.13.0",
|
||||||
|
"sass-loader": "^8.0.0",
|
||||||
|
"webpack": "^4.23.1",
|
||||||
|
"webpack-cli": "^3.1.2"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "cross-env BABEL_ENV=default NODE_ENV=production webpack",
|
||||||
|
"watch": "cross-env BABEL_ENV=default NODE_ENV=production webpack --watch",
|
||||||
|
"dev": "cross-env BABEL_ENV=default webpack --watch"
|
||||||
|
},
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
51
modules.local/ppcp-button/resources/js/button.js
Normal file
51
modules.local/ppcp-button/resources/js/button.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import Renderer from './modules/Renderer';
|
||||||
|
import SingleProductConfig from './modules/SingleProductConfig';
|
||||||
|
import UpdateCart from './modules/UpdateCart';
|
||||||
|
import ErrorHandler from './modules/ErrorHandler';
|
||||||
|
|
||||||
|
document.addEventListener(
|
||||||
|
'DOMContentLoaded',
|
||||||
|
() => {
|
||||||
|
if (! typeof(PayPalCommerceGateway)) {
|
||||||
|
console.error('PayPal button could not be configured.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (! document.querySelector(PayPalCommerceGateway.button.wrapper)) {
|
||||||
|
console.error('No wrapper for PayPal button found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const context = PayPalCommerceGateway.context;
|
||||||
|
if (context === 'product' && ! document.querySelector('form.cart') ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorHandler = new ErrorHandler();
|
||||||
|
const renderer = new Renderer({
|
||||||
|
url: PayPalCommerceGateway.button.url,
|
||||||
|
wrapper:PayPalCommerceGateway.button.wrapper
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const updateCart = new UpdateCart(
|
||||||
|
PayPalCommerceGateway.ajax.change_cart.endpoint,
|
||||||
|
PayPalCommerceGateway.ajax.change_cart.nonce
|
||||||
|
);
|
||||||
|
let configurator = null;
|
||||||
|
if (context === 'product') {
|
||||||
|
configurator = new SingleProductConfig(
|
||||||
|
PayPalCommerceGateway,
|
||||||
|
updateCart,
|
||||||
|
renderer.showButtons.bind(renderer),
|
||||||
|
renderer.hideButtons.bind(renderer),
|
||||||
|
document.querySelector('form.cart'),
|
||||||
|
errorHandler
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (! configurator) {
|
||||||
|
console.error('No context for button found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderer.render(configurator.configuration());
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* When you can't add something to the cart, the PayPal buttons should not show.
|
||||||
|
* Therefore we listen for changes on the add to cart button and show/hide the buttons accordingly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ButtonsToggleListener {
|
||||||
|
constructor(element, showCallback, hideCallback) {
|
||||||
|
this.element = element;
|
||||||
|
this.showCallback = showCallback;
|
||||||
|
this.hideCallback = hideCallback;
|
||||||
|
this.observer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
const config = { attributes : true };
|
||||||
|
const callback = () => {
|
||||||
|
if (this.element.classList.contains('disabled')) {
|
||||||
|
this.hideCallback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.showCallback();
|
||||||
|
}
|
||||||
|
this.observer = new MutationObserver(callback);
|
||||||
|
this.observer.observe(this.element, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
this.observer.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ButtonsToggleListener;
|
|
@ -0,0 +1,27 @@
|
||||||
|
class ErrorHandler {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.wrapper = document.querySelector('.woocommerce-notices-wrapper');
|
||||||
|
}
|
||||||
|
|
||||||
|
message(text) {
|
||||||
|
this.wrapper.classList.add('woocommerce-error');
|
||||||
|
this.wrapper.innerText = this.sanitize(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitize(text) {
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
textarea.innerHTML = text;
|
||||||
|
return textarea.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
if (! this.wrapper.classList.contains('woocommerce-error')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.wrapper.classList.remove('woocommerce-error');
|
||||||
|
this.wrapper.innerText = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ErrorHandler;
|
39
modules.local/ppcp-button/resources/js/modules/Renderer.js
Normal file
39
modules.local/ppcp-button/resources/js/modules/Renderer.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
class Renderer {
|
||||||
|
|
||||||
|
constructor(config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(buttonConfig) {
|
||||||
|
|
||||||
|
const script = document.createElement('script');
|
||||||
|
|
||||||
|
if (typeof paypal !== 'object') {
|
||||||
|
script.setAttribute('src', this.config.url);
|
||||||
|
script.addEventListener('load', (event) => {
|
||||||
|
this.renderButtons(buttonConfig);
|
||||||
|
})
|
||||||
|
document.body.append(script);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderButtons(buttonConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderButtons(buttonConfig) {
|
||||||
|
|
||||||
|
paypal.Buttons(
|
||||||
|
buttonConfig
|
||||||
|
).render(this.config.wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideButtons() {
|
||||||
|
document.querySelector(this.config.wrapper).style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
showButtons() {
|
||||||
|
document.querySelector(this.config.wrapper).style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Renderer;
|
|
@ -0,0 +1,95 @@
|
||||||
|
import ButtonsToggleListener from "./ButtonsToggleListener";
|
||||||
|
|
||||||
|
class SingleProductConfig {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
config,
|
||||||
|
updateCart,
|
||||||
|
showButtonCallback,
|
||||||
|
hideButtonCallback,
|
||||||
|
formElement,
|
||||||
|
errorHandler
|
||||||
|
) {
|
||||||
|
this.config = config;
|
||||||
|
this.updateCart = updateCart;
|
||||||
|
this.showButtonCallback = showButtonCallback;
|
||||||
|
this.hideButtonCallback = hideButtonCallback;
|
||||||
|
this.formElement = formElement;
|
||||||
|
this.errorHandler = errorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration() {
|
||||||
|
|
||||||
|
if ( this.hasVariations() ) {
|
||||||
|
const observer = new ButtonsToggleListener(
|
||||||
|
this.formElement.querySelector('.single_add_to_cart_button'),
|
||||||
|
this.showButtonCallback,
|
||||||
|
this.hideButtonCallback
|
||||||
|
);
|
||||||
|
observer.init();
|
||||||
|
}
|
||||||
|
const onApprove = (data, actions) => {
|
||||||
|
return actions.redirect(this.config.redirect);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
createOrder: this.createOrder(),
|
||||||
|
onApprove,
|
||||||
|
onError: (error) => {
|
||||||
|
this.errorHandler.message(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createOrder() {
|
||||||
|
const createOrder = (data, actions) => {
|
||||||
|
this.errorHandler.clear();
|
||||||
|
const product = document.querySelector('[name="add-to-cart"]').value;
|
||||||
|
const qty = document.querySelector('[name="quantity"]').value;
|
||||||
|
const variations = this.variations();
|
||||||
|
|
||||||
|
const onResolve = (purchase_units) => {
|
||||||
|
return fetch(this.config.ajax.create_order.endpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
nonce:this.config.ajax.create_order.nonce,
|
||||||
|
purchase_units
|
||||||
|
})
|
||||||
|
}).then(function(res) {
|
||||||
|
return res.json();
|
||||||
|
}).then(function(data) {
|
||||||
|
if (! data.success) {
|
||||||
|
//Todo: Error handling
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return data.data.id;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const promise = this.updateCart.update(onResolve, product, qty, variations);
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
return createOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
variations() {
|
||||||
|
|
||||||
|
if (! this.hasVariations()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const attributes = [...this.formElement.querySelectorAll("[name^='attribute_']")].map(
|
||||||
|
(element) => {
|
||||||
|
return {
|
||||||
|
value:element.value,
|
||||||
|
name:element.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasVariations() {
|
||||||
|
return this.formElement.classList.contains('variations_form');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SingleProductConfig;
|
39
modules.local/ppcp-button/resources/js/modules/UpdateCart.js
Normal file
39
modules.local/ppcp-button/resources/js/modules/UpdateCart.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
class UpdateCart {
|
||||||
|
|
||||||
|
constructor(endpoint, nonce) {
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
this.nonce = nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(onResolve, product, qty, variations) {
|
||||||
|
return new Promise( (resolve, reject) => {
|
||||||
|
fetch(
|
||||||
|
this.endpoint,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
nonce: this.nonce,
|
||||||
|
product,
|
||||||
|
qty,
|
||||||
|
variations
|
||||||
|
})
|
||||||
|
}
|
||||||
|
).then(
|
||||||
|
(result) => {
|
||||||
|
return result.json();
|
||||||
|
}
|
||||||
|
).then( (result) => {
|
||||||
|
if (! result.success) {
|
||||||
|
reject(result.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolved = onResolve(result.data);
|
||||||
|
resolve(resolved);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UpdateCart;
|
40
modules.local/ppcp-button/services.php
Normal file
40
modules.local/ppcp-button/services.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Button;
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Assets\SmartButton;
|
||||||
|
use Dhii\Data\Container\ContainerInterface;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'button.smart-button' => function(ContainerInterface $container) {
|
||||||
|
$isSandbox = true;
|
||||||
|
return new SmartButton($container->get('button.url'), $isSandbox);
|
||||||
|
},
|
||||||
|
'button.url' => function(ContainerInterface $container) : string {
|
||||||
|
return plugins_url('/modules/ppcp-button/', dirname(__FILE__, 3) . '/woocommerce-paypal-commerce-gateway.php');
|
||||||
|
},
|
||||||
|
'button.request-data' => function(ContainerInterface $container) : RequestData {
|
||||||
|
return new RequestData();
|
||||||
|
},
|
||||||
|
'button.endpoint.change-cart' => function(ContainerInterface $container) : ChangeCartEndpoint {
|
||||||
|
if (! \WC()->cart) {
|
||||||
|
throw new RuntimeException('cant initialize endpoint at this moment');
|
||||||
|
}
|
||||||
|
$cart = WC()->cart;
|
||||||
|
$shipping = WC()->shipping();
|
||||||
|
$requestData = $container->get('button.request-data');
|
||||||
|
$repository = $container->get('api.cart-repository');
|
||||||
|
return new ChangeCartEndpoint($cart, $shipping, $requestData, $repository);
|
||||||
|
},
|
||||||
|
'button.endpoint.create-order' => function(ContainerInterface $container) : CreateOrderEndpoint {
|
||||||
|
$requestData = $container->get('button.request-data');
|
||||||
|
$repository = $container->get('api.cart-repository');
|
||||||
|
$apiClient = $container->get('api.endpoint.order');
|
||||||
|
return new CreateOrderEndpoint($requestData, $repository, $apiClient);
|
||||||
|
}
|
||||||
|
];
|
99
modules.local/ppcp-button/src/Assets/SmartButton.php
Normal file
99
modules.local/ppcp-button/src/Assets/SmartButton.php
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Button\Assets;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
|
||||||
|
|
||||||
|
class SmartButton
|
||||||
|
{
|
||||||
|
|
||||||
|
private $moduleUrl;
|
||||||
|
private $isSandbox;
|
||||||
|
public function __construct(
|
||||||
|
string $moduleUrl,
|
||||||
|
bool $isSandbox
|
||||||
|
) {
|
||||||
|
$this->moduleUrl = $moduleUrl;
|
||||||
|
$this->isSandbox = $isSandbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderWrapper() : bool
|
||||||
|
{
|
||||||
|
$renderer = function() {
|
||||||
|
echo '<div id="ppc-button"></div>';
|
||||||
|
};
|
||||||
|
if (is_product()) {
|
||||||
|
add_action(
|
||||||
|
'woocommerce_single_product_summary',
|
||||||
|
$renderer,
|
||||||
|
31
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (is_checkout()) {
|
||||||
|
add_action(
|
||||||
|
'wp_footer',
|
||||||
|
$renderer,
|
||||||
|
31
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enqueue() : bool
|
||||||
|
{
|
||||||
|
wp_enqueue_script(
|
||||||
|
'paypal-smart-button',
|
||||||
|
$this->moduleUrl . '/assets/js/button.js'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
$params = [
|
||||||
|
'client-id' => 'AcVzowpNCpTxFzLG7onQI4JD0sVcA0BkZv-D42qRZPv_gZ8cNfX9zGL_8bXmSu7cbJ5B2DH7sot8vDpw',
|
||||||
|
];
|
||||||
|
$smartButtonUrl = add_query_arg($params, 'https://www.paypal.com/sdk/js');
|
||||||
|
|
||||||
|
$localize = [
|
||||||
|
'redirect' => wc_get_checkout_url(),
|
||||||
|
'context' => $this->context(),
|
||||||
|
'ajax' => [
|
||||||
|
'change_cart' => [
|
||||||
|
'endpoint' => home_url(\WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT )),
|
||||||
|
'nonce' => wp_create_nonce(ChangeCartEndpoint::nonce()),
|
||||||
|
],
|
||||||
|
'create_order' => [
|
||||||
|
'endpoint' => home_url(\WC_AJAX::get_endpoint( CreateOrderEndpoint::ENDPOINT )),
|
||||||
|
'nonce' => wp_create_nonce(CreateOrderEndpoint::nonce()),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'button' => [
|
||||||
|
'wrapper' => '#ppc-button',
|
||||||
|
'url' =>$smartButtonUrl,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
wp_localize_script(
|
||||||
|
'paypal-smart-button',
|
||||||
|
'PayPalCommerceGateway',
|
||||||
|
$localize
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function context() : string {
|
||||||
|
$context = 'mini-cart';
|
||||||
|
if (is_product()) {
|
||||||
|
$context = 'product';
|
||||||
|
}
|
||||||
|
if (is_cart()) {
|
||||||
|
$context = 'cart';
|
||||||
|
}
|
||||||
|
if (is_checkout()) {
|
||||||
|
$context = 'checkout';
|
||||||
|
}
|
||||||
|
return $context;
|
||||||
|
}
|
||||||
|
}
|
71
modules.local/ppcp-button/src/ButtonModule.php
Normal file
71
modules.local/ppcp-button/src/ButtonModule.php
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Button;
|
||||||
|
|
||||||
|
|
||||||
|
use Dhii\Container\ServiceProvider;
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Assets\SmartButton;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
|
||||||
|
use Interop\Container\ServiceProviderInterface;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
class ButtonModule implements ModuleInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function setup(): ServiceProviderInterface
|
||||||
|
{
|
||||||
|
return new ServiceProvider(
|
||||||
|
require __DIR__.'/../services.php',
|
||||||
|
require __DIR__.'/../extensions.php'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function run(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
$smartButton = $container->get('button.smart-button');
|
||||||
|
/**
|
||||||
|
* @var SmartButton $smartButton
|
||||||
|
*/
|
||||||
|
add_action(
|
||||||
|
'wp',
|
||||||
|
function() use ($smartButton) {
|
||||||
|
if (is_admin()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$smartButton->renderWrapper();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
add_action('wp_enqueue_scripts', function() use ($smartButton) {
|
||||||
|
$smartButton->enqueue();
|
||||||
|
});
|
||||||
|
|
||||||
|
add_action(
|
||||||
|
'wc_ajax_' . ChangeCartEndpoint::ENDPOINT,
|
||||||
|
function() use ($container) {
|
||||||
|
$endpoint = $container->get('button.endpoint.change-cart');
|
||||||
|
/**
|
||||||
|
* @var ChangeCartEndpoint $endpoint
|
||||||
|
*/
|
||||||
|
$endpoint->handleRequest();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
add_action(
|
||||||
|
'wc_ajax_' . CreateOrderEndpoint::ENDPOINT,
|
||||||
|
function() use ($container) {
|
||||||
|
$endpoint = $container->get('button.endpoint.create-order');
|
||||||
|
/**
|
||||||
|
* @var ChangeCartEndpoint $endpoint
|
||||||
|
*/
|
||||||
|
$endpoint->handleRequest();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
123
modules.local/ppcp-button/src/Endpoint/ChangeCartEndpoint.php
Normal file
123
modules.local/ppcp-button/src/Endpoint/ChangeCartEndpoint.php
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\LineItem;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
|
||||||
|
|
||||||
|
class ChangeCartEndpoint implements EndpointInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
const ENDPOINT = 'ppc-change-cart';
|
||||||
|
|
||||||
|
private $cart;
|
||||||
|
private $shipping;
|
||||||
|
private $requestData;
|
||||||
|
private $repository;
|
||||||
|
public function __construct(
|
||||||
|
\WC_Cart $cart,
|
||||||
|
\WC_Shipping $shipping,
|
||||||
|
RequestData $requestData,
|
||||||
|
CartRepository $repository
|
||||||
|
) {
|
||||||
|
$this->cart = $cart;
|
||||||
|
$this->shipping = $shipping;
|
||||||
|
$this->requestData = $requestData;
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function nonce() : string
|
||||||
|
{
|
||||||
|
return self::ENDPOINT . get_current_user_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest() : bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $this->requestData->readRequest($this->nonce());
|
||||||
|
|
||||||
|
if (
|
||||||
|
! isset($data['product'])
|
||||||
|
|| ! isset($data['qty'])
|
||||||
|
) {
|
||||||
|
wp_send_json_error(__('Necessary fields not defined. Action aborted.', 'woocommerce-paypal-commerce-gateway'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$product = wc_get_product((int) $data['product']);
|
||||||
|
if (! $product) {
|
||||||
|
wp_send_json_error(__('No product defined. Action aborted.', 'woocommerce-paypal-commerce-gateway'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$quantity = (int) $data['qty'];
|
||||||
|
$this->shipping->reset_shipping();
|
||||||
|
$this->cart->empty_cart(false);
|
||||||
|
$success = (! $product->is_type('variable')) ?
|
||||||
|
$success = $this->addProduct($product, $quantity)
|
||||||
|
: $this->addVariableProduct($product, $quantity, $data['variations']);
|
||||||
|
if (! $success) {
|
||||||
|
|
||||||
|
$message = __('Something went wrong. Action aborted', 'woocommerce-paypal-commerce-gateway');
|
||||||
|
$errors = wc_get_notices('error');
|
||||||
|
if (count($errors)) {
|
||||||
|
$message = array_reduce(
|
||||||
|
$errors,
|
||||||
|
function(string $add, $error) : string {
|
||||||
|
return $add . $error['notice'] . ' ';
|
||||||
|
},
|
||||||
|
''
|
||||||
|
);
|
||||||
|
wc_clear_notices();
|
||||||
|
}
|
||||||
|
wp_send_json_error($message);
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success($this->generatePurchaseUnits());
|
||||||
|
return $success;
|
||||||
|
} catch (RuntimeException $error) {
|
||||||
|
wp_send_json_error($error->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addProduct(\WC_Product $product, int $quantity) : bool {
|
||||||
|
|
||||||
|
return false !== $this->cart->add_to_cart($product->get_id(), $quantity);
|
||||||
|
}
|
||||||
|
private function addVariableProduct(\WC_Product $product, int $quantity, array $postVariations) : bool {
|
||||||
|
|
||||||
|
foreach ($postVariations as $key => $value) {
|
||||||
|
$variations[$value['name']] = $value['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$dataStore = \WC_Data_Store::load( 'product' );
|
||||||
|
$variationId = $dataStore->find_matching_product_variation( $product, $variations );
|
||||||
|
|
||||||
|
//ToDo: Check stock status for variation.
|
||||||
|
return false !== WC()->cart->add_to_cart( $product->get_id(), $quantity, $variationId, $variations );
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generatePurchaseUnits() : array {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToDo: Somewhere we need to add shipping costs. Total costs can change later on, but we should
|
||||||
|
* get a good estimate, about the total amount.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToDo: Currently, although an array, only one purchase_unit is supported!
|
||||||
|
*
|
||||||
|
* @see https://developer.paypal.com/docs/api/orders/v2/#orders-create-request-body
|
||||||
|
*/
|
||||||
|
return array_map(
|
||||||
|
function(LineItem $lineItem) : array {
|
||||||
|
return $lineItem->toArray();
|
||||||
|
},
|
||||||
|
$this->repository->all()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Repository\CartRepository;
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||||
|
|
||||||
|
class CreateOrderEndpoint implements EndpointInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
const ENDPOINT = 'ppc-create-order';
|
||||||
|
|
||||||
|
private $requestData;
|
||||||
|
private $repository;
|
||||||
|
private $apiEndpoint;
|
||||||
|
public function __construct(
|
||||||
|
RequestData $requestData,
|
||||||
|
CartRepository $repository,
|
||||||
|
OrderEndpoint $apiEndpoint
|
||||||
|
) {
|
||||||
|
$this->requestData = $requestData;
|
||||||
|
$this->repository = $repository;
|
||||||
|
$this->apiEndpoint = $apiEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function nonce() : string
|
||||||
|
{
|
||||||
|
return self::ENDPOINT . get_current_user_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest() : bool
|
||||||
|
{
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->requestData->readRequest($this->nonce());
|
||||||
|
$lineItems = $this->repository->all();
|
||||||
|
$order = $this->apiEndpoint->createForLineItems(
|
||||||
|
...$lineItems
|
||||||
|
);
|
||||||
|
wp_send_json_success($order->toArray());
|
||||||
|
return false;
|
||||||
|
} catch (RuntimeException $error ) {
|
||||||
|
wp_send_json_error($error->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
14
modules.local/ppcp-button/src/Endpoint/EndpointInterface.php
Normal file
14
modules.local/ppcp-button/src/Endpoint/EndpointInterface.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||||
|
|
||||||
|
|
||||||
|
interface EndpointInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public static function nonce() : string;
|
||||||
|
|
||||||
|
public function handleRequest() : bool;
|
||||||
|
|
||||||
|
}
|
41
modules.local/ppcp-button/src/Endpoint/RequestData.php
Normal file
41
modules.local/ppcp-button/src/Endpoint/RequestData.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
|
||||||
|
|
||||||
|
class RequestData
|
||||||
|
{
|
||||||
|
|
||||||
|
public function readRequest(string $nonce) : array
|
||||||
|
{
|
||||||
|
|
||||||
|
$stream = file_get_contents('php://input');
|
||||||
|
$json = json_decode($stream, true);
|
||||||
|
if (
|
||||||
|
! isset($json['nonce'])
|
||||||
|
|| !wp_verify_nonce($json['nonce'], $nonce)
|
||||||
|
) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
__('Could not validate nonce.', 'woocommerce-paypal-commerce-gateway')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->sanitize($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sanitize(array $assocArray) : array {
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
foreach ((array) $assocArray as $rawKey => $rawValue) {
|
||||||
|
if (! is_array($rawValue)) {
|
||||||
|
$data[sanitize_text_field($rawKey)] = sanitize_text_field($rawValue);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$data[sanitize_text_field($rawKey)] = $this->sanitize($rawValue);
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
10
modules.local/ppcp-button/src/Exception/RuntimeException.php
Normal file
10
modules.local/ppcp-button/src/Exception/RuntimeException.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Button\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class RuntimeException extends \RuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
35
modules.local/ppcp-button/webpack.config.js
Normal file
35
modules.local/ppcp-button/webpack.config.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
const path = require( 'path' );
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
devtool: 'sourcemap',
|
||||||
|
mode: isProduction ? 'production' : 'development',
|
||||||
|
target: 'web',
|
||||||
|
entry: {
|
||||||
|
button: path.resolve( './resources/js/button.js' ),
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.resolve( __dirname, 'assets/' ),
|
||||||
|
filename: 'js/[name].js',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
test: /\.js?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: 'css/[name].css',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{loader:'sass-loader'}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
13
modules.local/ppcp-session/composer.json
Normal file
13
modules.local/ppcp-session/composer.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "inpsyde/ppcp-session",
|
||||||
|
"type": "inpsyde-module",
|
||||||
|
"require": {
|
||||||
|
"dhii/module-interface": "0.2.x-dev",
|
||||||
|
"inpsyde/ppcp-api-client": "dev-master"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Inpsyde\\PayPalCommerce\\Session\\": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
modules.local/ppcp-session/extensions.php
Normal file
8
modules.local/ppcp-session/extensions.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Session;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
];
|
10
modules.local/ppcp-session/module.php
Normal file
10
modules.local/ppcp-session/module.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Session;
|
||||||
|
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
|
||||||
|
return function (): ModuleInterface {
|
||||||
|
return new SessionModule();
|
||||||
|
};
|
22
modules.local/ppcp-session/services.php
Normal file
22
modules.local/ppcp-session/services.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Session;
|
||||||
|
|
||||||
|
use Dhii\Data\Container\ContainerInterface;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'session.handler' => function(ContainerInterface $container) : SessionHandler {
|
||||||
|
|
||||||
|
if (is_admin()) {
|
||||||
|
return new SessionHandler();
|
||||||
|
}
|
||||||
|
$result = WC()->session->get(SessionHandler::ID);
|
||||||
|
if (is_a($result, SessionHandler::class)) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
$sessionHandler = new SessionHandler();
|
||||||
|
WC()->session->set(SessionHandler::ID, $sessionHandler);
|
||||||
|
return $sessionHandler;
|
||||||
|
}
|
||||||
|
];
|
27
modules.local/ppcp-session/src/SessionHandler.php
Normal file
27
modules.local/ppcp-session/src/SessionHandler.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Session;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Entity\Order;
|
||||||
|
|
||||||
|
class SessionHandler
|
||||||
|
{
|
||||||
|
const ID = 'ppcp';
|
||||||
|
|
||||||
|
private $order;
|
||||||
|
public function order() : ?Order {
|
||||||
|
return $this->order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOrder(Order $order) : SessionHandler {
|
||||||
|
$this->order = $order;
|
||||||
|
$this->storeSession();
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function storeSession() {
|
||||||
|
WC()->session->set(self::ID, $this);
|
||||||
|
}
|
||||||
|
}
|
32
modules.local/ppcp-session/src/SessionModule.php
Normal file
32
modules.local/ppcp-session/src/SessionModule.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\Session;
|
||||||
|
|
||||||
|
|
||||||
|
use Dhii\Container\ServiceProvider;
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
use Interop\Container\ServiceProviderInterface;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
class SessionModule implements ModuleInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function setup(): ServiceProviderInterface
|
||||||
|
{
|
||||||
|
return new ServiceProvider(
|
||||||
|
require __DIR__.'/../services.php',
|
||||||
|
require __DIR__.'/../extensions.php'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(ContainerInterface $c)
|
||||||
|
{
|
||||||
|
add_action(
|
||||||
|
'woocommerce_init',
|
||||||
|
function() use ($c) {
|
||||||
|
$c->get('session.handler');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
14
modules.local/ppcp-wc-gateway/composer.json
Normal file
14
modules.local/ppcp-wc-gateway/composer.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "inpsyde/ppcp-wc-gateway",
|
||||||
|
"type": "inpsyde-module",
|
||||||
|
"require": {
|
||||||
|
"dhii/module-interface": "0.2.x-dev",
|
||||||
|
"inpsyde/ppcp-session": "dev-master",
|
||||||
|
"inpsyde/ppcp-api-client": "dev-master"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Inpsyde\\PayPalCommerce\\WcGateway\\": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
modules.local/ppcp-wc-gateway/extensions.php
Normal file
8
modules.local/ppcp-wc-gateway/extensions.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\WcGateway;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
];
|
10
modules.local/ppcp-wc-gateway/module.php
Normal file
10
modules.local/ppcp-wc-gateway/module.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\WcGateway;
|
||||||
|
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
|
||||||
|
return function (): ModuleInterface {
|
||||||
|
return new WcGatewayModule();
|
||||||
|
};
|
20
modules.local/ppcp-wc-gateway/services.php
Normal file
20
modules.local/ppcp-wc-gateway/services.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\WcGateway;
|
||||||
|
|
||||||
|
use Dhii\Data\Container\ContainerInterface;
|
||||||
|
use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways;
|
||||||
|
use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'wcgateway.gateway' => function(ContainerInterface $container) : WcGateway {
|
||||||
|
$sessionHandler = $container->get('session.handler');
|
||||||
|
$endpoint = $container->get('api.endpoint.order');
|
||||||
|
return new WcGateway($sessionHandler, $endpoint);
|
||||||
|
},
|
||||||
|
'wcgateway.disabler' => function(ContainerInterface $container) : DisableGateways {
|
||||||
|
$sessionHandler = $container->get('session.handler');
|
||||||
|
return new DisableGateways($sessionHandler);
|
||||||
|
}
|
||||||
|
];
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\WcGateway\Checkout;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\Session\SessionHandler;
|
||||||
|
use Inpsyde\PayPalCommerce\WcGateway\Gateway\WcGateway;
|
||||||
|
|
||||||
|
class DisableGateways
|
||||||
|
{
|
||||||
|
|
||||||
|
private $sessionHandler;
|
||||||
|
public function __construct(SessionHandler $sessionHandler)
|
||||||
|
{
|
||||||
|
$this->sessionHandler = $sessionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handler(array $methods) : array
|
||||||
|
{
|
||||||
|
if (! $this->needsToDisableGateways()) {
|
||||||
|
return $methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [WcGateway::ID => $methods[WcGateway::ID]];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function needsToDisableGateways() : bool
|
||||||
|
{
|
||||||
|
return $this->sessionHandler->order() !== null;
|
||||||
|
}
|
||||||
|
}
|
88
modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php
Normal file
88
modules.local/ppcp-wc-gateway/src/Gateway/WcGateway.php
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\WcGateway\Gateway;
|
||||||
|
|
||||||
|
|
||||||
|
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||||
|
use Inpsyde\PayPalCommerce\Session\SessionHandler;
|
||||||
|
|
||||||
|
class WcGateway extends \WC_Payment_Gateway
|
||||||
|
{
|
||||||
|
|
||||||
|
const ID = 'ppcp-gateway';
|
||||||
|
|
||||||
|
private $isSandbox = true;
|
||||||
|
private $sessionHandler;
|
||||||
|
private $endpoint;
|
||||||
|
|
||||||
|
public function __construct(SessionHandler $sessionHandler, OrderEndpoint $endpoint)
|
||||||
|
{
|
||||||
|
$this->sessionHandler = $sessionHandler;
|
||||||
|
$this->endpoint = $endpoint;
|
||||||
|
$this->id = self::ID;
|
||||||
|
$this->method_title = __('PayPal Payments', 'woocommerce-paypal-gateway');
|
||||||
|
$this->method_description = __('Provide your customers with the PayPal payment system', 'woocommerce-paypal-gateway');
|
||||||
|
$this->init_form_fields();
|
||||||
|
$this->init_settings();
|
||||||
|
|
||||||
|
$this->isSandbox = $this->get_option( 'sandbox_on', 'yes' ) === 'yes';
|
||||||
|
|
||||||
|
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function init_form_fields()
|
||||||
|
{
|
||||||
|
$this->form_fields = [
|
||||||
|
'enabled' => array(
|
||||||
|
'title' => __( 'Enable/Disable', 'woocommerce-paypal-gateway' ),
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'label' => __( 'Enable PayPal Payments', 'woocommerce-paypal-gateway' ),
|
||||||
|
'default' => 'yes'
|
||||||
|
),
|
||||||
|
'sandbox_on' => array(
|
||||||
|
'title' => __( 'Enable Sandbox', 'woocommerce-paypal-gateway' ),
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'label' => __( 'For testing your integration, you can enable the sandbox.', 'woocommerce-paypal-gateway' ),
|
||||||
|
'default' => 'yes'
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function process_payment( $order_id ) : ?array
|
||||||
|
{
|
||||||
|
global $woocommerce;
|
||||||
|
$wcOrder = new \WC_Order( $order_id );
|
||||||
|
|
||||||
|
//ToDo: We need to fetch the order from paypal again to get it with the new status.
|
||||||
|
$order = $this->sessionHandler->order();
|
||||||
|
$errorMessage = null;
|
||||||
|
if (! $order || ! $order->isApproved()) {
|
||||||
|
$errorMessage = 'not approve yet';
|
||||||
|
|
||||||
|
}
|
||||||
|
$errorMessage = null;
|
||||||
|
if ($errorMessage) {
|
||||||
|
wc_add_notice( __('Payment error:', 'woocommerce-paypal-gateway') . $errorMessage, 'error' );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToDo: If shipping or something else changes, we need to patch the order!
|
||||||
|
* We should also handle the shipping address and update if needed
|
||||||
|
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_patch
|
||||||
|
**/
|
||||||
|
$order = $this->endpoint->capture($order);
|
||||||
|
|
||||||
|
$wcOrder->update_status('on-hold', __( 'Awaiting payment.', 'woocommerce-paypal-gateway' ));
|
||||||
|
if ($order->isCompleted()) {
|
||||||
|
$wcOrder->update_status('processing', __( 'Payment received.', 'woocommerce-paypal-gateway' ));
|
||||||
|
}
|
||||||
|
$woocommerce->cart->empty_cart();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'result' => 'success',
|
||||||
|
'redirect' => $this->get_return_url( $wcOrder )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
47
modules.local/ppcp-wc-gateway/src/WcGatewayModule.php
Normal file
47
modules.local/ppcp-wc-gateway/src/WcGatewayModule.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce\WcGateway;
|
||||||
|
|
||||||
|
|
||||||
|
use Dhii\Container\ServiceProvider;
|
||||||
|
use Dhii\Modular\Module\Exception\ModuleExceptionInterface;
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
use Inpsyde\PayPalCommerce\WcGateway\Checkout\DisableGateways;
|
||||||
|
use Interop\Container\ServiceProviderInterface;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
class WcGatewayModule implements ModuleInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function setup(): ServiceProviderInterface
|
||||||
|
{
|
||||||
|
return new ServiceProvider(
|
||||||
|
require __DIR__.'/../services.php',
|
||||||
|
require __DIR__.'/../extensions.php'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(ContainerInterface $c)
|
||||||
|
{
|
||||||
|
add_filter(
|
||||||
|
'woocommerce_payment_gateways',
|
||||||
|
function($methods) use ($c) : array {
|
||||||
|
|
||||||
|
$methods[] = $c->get('wcgateway.gateway');
|
||||||
|
return (array) $methods;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
add_filter(
|
||||||
|
'woocommerce_available_payment_gateways',
|
||||||
|
function($methods) use ($c) : array {
|
||||||
|
$disabler = $c->get('wcgateway.disabler');
|
||||||
|
/**
|
||||||
|
* @var DisableGateways $disabler
|
||||||
|
*/
|
||||||
|
return $disabler->handler((array) $methods);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
25
src/PluginModule.php
Normal file
25
src/PluginModule.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Inpsyde\PayPalCommerce;
|
||||||
|
|
||||||
|
|
||||||
|
use Dhii\Container\ServiceProvider;
|
||||||
|
use Dhii\Modular\Module\Exception\ModuleExceptionInterface;
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
use Interop\Container\ServiceProviderInterface;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
class PluginModule implements ModuleInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function setup(): ServiceProviderInterface
|
||||||
|
{
|
||||||
|
return new ServiceProvider([], []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(ContainerInterface $c)
|
||||||
|
{
|
||||||
|
// TODO: Implement run() method.
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,3 +15,63 @@ declare( strict_types = 1 );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Inpsyde\PayPalCommerce;
|
namespace Inpsyde\PayPalCommerce;
|
||||||
|
|
||||||
|
use Dhii\Container\CachingContainer;
|
||||||
|
use Dhii\Container\CompositeCachingServiceProvider;
|
||||||
|
use Dhii\Container\DelegatingContainer;
|
||||||
|
use Dhii\Container\ProxyContainer;
|
||||||
|
use Dhii\Modular\Module\ModuleInterface;
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
if (!class_exists(CompositeCachingServiceProvider::class)
|
||||||
|
&& file_exists(__DIR__.'/vendor/autoload.php')
|
||||||
|
) {
|
||||||
|
include_once __DIR__.'/vendor/autoload.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
static $initialized;
|
||||||
|
if (!$initialized) {
|
||||||
|
$modules = [new PluginModule(__DIR__)];
|
||||||
|
foreach (glob(plugin_dir_path(__FILE__).'modules/*/module.php') as $moduleFile) {
|
||||||
|
$modules[] = (@require $moduleFile)();
|
||||||
|
}
|
||||||
|
$providers = [];
|
||||||
|
foreach ($modules as $module) {
|
||||||
|
/* @var $module ModuleInterface */
|
||||||
|
$providers[] = $module->setup();
|
||||||
|
}
|
||||||
|
$proxy = new ProxyContainer();
|
||||||
|
$provider = new CompositeCachingServiceProvider($providers);
|
||||||
|
$container = new CachingContainer(new DelegatingContainer($provider));
|
||||||
|
$proxy->setInnerContainer($container);
|
||||||
|
foreach ($modules as $module) {
|
||||||
|
/* @var $module ModuleInterface */
|
||||||
|
$module->run($container);
|
||||||
|
}
|
||||||
|
$initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_action(
|
||||||
|
'plugins_loaded',
|
||||||
|
function () {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
register_activation_hook(
|
||||||
|
__FILE__,
|
||||||
|
function () {
|
||||||
|
init();
|
||||||
|
do_action('woocommerce-paypal-commerce-gateway.activate');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
register_deactivation_hook(
|
||||||
|
__FILE__,
|
||||||
|
function () {
|
||||||
|
init();
|
||||||
|
do_action('woocommerce-paypal-commerce-gateway.deactivate');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})();
|
Loading…
Add table
Add a link
Reference in a new issue