)". You can generate API keys from '
. 'the Stripe web interface. See https://stripe.com/api for '
. 'details, or email support@stripe.com if you have any questions.';
throw new Exception\Authentication_Exception( $msg );
}
// Clients can supply arbitrary additional keys to be included in the
// X-Stripe-Client-User-Agent header via the optional getUserAgentInfo()
// method
$clientUAInfo = null;
if ( method_exists( $this->httpClient(), 'getUserAgentInfo' ) ) {
$clientUAInfo = $this->httpClient()->getUserAgentInfo();
}
$absUrl = $this->_apiBase . $url;
$params = self::_encodeObjects( $params );
$defaultHeaders = $this->_defaultHeaders( $myApiKey, $clientUAInfo );
if ( Stripe::$apiVersion ) {
$defaultHeaders['Stripe-Version'] = Stripe::$apiVersion;
}
if ( Stripe::$accountId ) {
$defaultHeaders['Stripe-Account'] = Stripe::$accountId;
}
if ( Stripe::$enableTelemetry && self::$requestTelemetry != null ) {
$defaultHeaders['X-Stripe-Client-Telemetry'] = self::_telemetryJson( self::$requestTelemetry );
}
$hasFile = false;
foreach ( $params as $k => $v ) {
if ( is_resource( $v ) ) {
$hasFile = true;
$params[ $k ] = self::_processResourceParam( $v );
} elseif ( $v instanceof \CURLFile ) {
$hasFile = true;
}
}
if ( $hasFile ) {
$defaultHeaders['Content-Type'] = 'multipart/form-data';
} else {
$defaultHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
}
$combinedHeaders = array_merge( $defaultHeaders, $headers );
$rawHeaders = array();
foreach ( $combinedHeaders as $header => $value ) {
$rawHeaders[] = $header . ': ' . $value;
}
$requestStartMs = Util\Util::currentTimeMillis();
list($rbody, $rcode, $rheaders) = $this->httpClient()->request(
$method,
$absUrl,
$rawHeaders,
$params,
$hasFile
);
if ( isset( $rheaders['request-id'] ) && isset( $rheaders['request-id'][0] ) ) {
self::$requestTelemetry = new Request_Telemetry(
$rheaders['request-id'][0],
Util\Util::currentTimeMillis() - $requestStartMs
);
}
return array( $rbody, $rcode, $rheaders, $myApiKey );
}
/**
* @param resource $resource
*
* @return \CURLFile|string
*
* @throws Exception\InvalidArgumentException
*/
private function _processResourceParam( $resource ) {
if ( get_resource_type( $resource ) !== 'stream' ) {
throw new Exception\InvalidArgumentException(
'Attempted to upload a resource that is not a stream'
);
}
$metaData = stream_get_meta_data( $resource );
if ( $metaData['wrapper_type'] !== 'plainfile' ) {
throw new Exception\InvalidArgumentException(
'Only plainfile resource streams are supported'
);
}
// We don't have the filename or mimetype, but the API doesn't care
return new \CURLFile( $metaData['uri'] );
}
/**
* @param string $rbody
* @param int $rcode
* @param array $rheaders
*
* @return array
*
* @throws Exception\UnexpectedValueException
* @throws Exception\ApiErrorException
*/
private function _interpretResponse( $rbody, $rcode, $rheaders ) {
$resp = json_decode( $rbody, true );
$jsonError = json_last_error();
if ( $resp === null && $jsonError !== JSON_ERROR_NONE ) {
$msg = "Invalid response body from API: $rbody "
. "(HTTP response code was $rcode, json_last_error() was $jsonError)";
throw new Exception\UnexpectedValueException( $msg, $rcode );
}
if ( $rcode < 200 || $rcode >= 300 ) {
$this->handleErrorResponse( $rbody, $rcode, $rheaders, $resp );
}
return $resp;
}
/**
* @static
*
* @param HttpClient\ClientInterface $client
*/
public static function setHttpClient( $client ) {
self::$_httpClient = $client;
}
/**
* @static
*
* Resets any stateful telemetry data
*/
public static function resetTelemetry() {
self::$requestTelemetry = null;
}
/**
* @return HttpClient\ClientInterface
*/
private function httpClient() {
if ( ! self::$_httpClient ) {
self::$_httpClient = Http_Client\Curl_Client::instance();
}
return self::$_httpClient;
}
}
payments/stripe/lib/class-file-link.php 0000644 00000001056 14760004044 0014147 0 ustar 00 instanceUrl() . '/close';
list($response, $opts) = $this->_request( 'post', $url, null, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
}
payments/stripe/lib/class-tax-rate.php 0000644 00000001173 14760004044 0014022 0 ustar 00 instanceUrl() . '/discount';
list($response, $opts) = $this->_request( 'delete', $url, $params, $opts );
$this->refreshFrom( array( 'discount' => null ), $opts, true );
}
/**
* @param string $id The ID of the customer on which to create the source.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return Api_Resource
*/
public static function createSource( $id, $params = null, $opts = null ) {
return self::_createNestedResource( $id, static::PATH_SOURCES, $params, $opts );
}
/**
* @param string $id The ID of the customer to which the source belongs.
* @param string $sourceId The ID of the source to retrieve.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return Api_Resource
*/
public static function retrieveSource( $id, $sourceId, $params = null, $opts = null ) {
return self::_retrieveNestedResource( $id, static::PATH_SOURCES, $sourceId, $params, $opts );
}
/**
* @param string $id The ID of the customer to which the source belongs.
* @param string $sourceId The ID of the source to update.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return Api_Resource
*/
public static function updateSource( $id, $sourceId, $params = null, $opts = null ) {
return self::_updateNestedResource( $id, static::PATH_SOURCES, $sourceId, $params, $opts );
}
/**
* @param string $id The ID of the customer to which the source belongs.
* @param string $sourceId The ID of the source to delete.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return Api_Resource
*/
public static function deleteSource( $id, $sourceId, $params = null, $opts = null ) {
return self::_deleteNestedResource( $id, static::PATH_SOURCES, $sourceId, $params, $opts );
}
/**
* @param string $id The ID of the customer on which to retrieve the sources.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return Collection The list of sources.
*/
public static function allSources( $id, $params = null, $opts = null ) {
return self::_allNestedResources( $id, static::PATH_SOURCES, $params, $opts );
}
/**
* @param string $id The ID of the customer on which to create the tax id.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return TaxId
*/
public static function createTaxId( $id, $params = null, $opts = null ) {
return self::_createNestedResource( $id, static::PATH_TAX_IDS, $params, $opts );
}
/**
* @param string $id The ID of the customer to which the tax id belongs.
* @param string $taxIdId The ID of the tax id to retrieve.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return TaxId
*/
public static function retrieveTaxId( $id, $taxIdId, $params = null, $opts = null ) {
return self::_retrieveNestedResource( $id, static::PATH_TAX_IDS, $taxIdId, $params, $opts );
}
/**
* @param string $id The ID of the customer to which the tax id belongs.
* @param string $taxIdId The ID of the tax id to delete.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return TaxId
*/
public static function deleteTaxId( $id, $taxIdId, $params = null, $opts = null ) {
return self::_deleteNestedResource( $id, static::PATH_TAX_IDS, $taxIdId, $params, $opts );
}
/**
* @param string $id The ID of the customer on which to retrieve the tax ids.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return Collection The list of tax ids.
*/
public static function allTaxIds( $id, $params = null, $opts = null ) {
return self::_allNestedResources( $id, static::PATH_TAX_IDS, $params, $opts );
}
/**
* @param string $id The ID of the customer on which to create the balance transaction.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return BalanceTransaction
*/
public static function createBalanceTransaction( $id, $params = null, $opts = null ) {
return self::_createNestedResource( $id, static::PATH_BALANCE_TRANSACTIONS, $params, $opts );
}
/**
* @param string $id The ID of the customer to which the balance transaction belongs.
* @param string $balanceTransactionId The ID of the balance transaction to retrieve.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return BalanceTransaction
*/
public static function retrieveBalanceTransaction( $id, $balanceTransactionId, $params = null, $opts = null ) {
return self::_retrieveNestedResource( $id, static::PATH_BALANCE_TRANSACTIONS, $balanceTransactionId, $params, $opts );
}
/**
* @param string $id The ID of the customer to which the balance transaction belongs.
* @param string $balanceTransactionId The ID of the balance transaction to update.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return BalanceTransaction
*/
public static function updateBalanceTransaction( $id, $balanceTransactionId, $params = null, $opts = null ) {
return self::_updateNestedResource( $id, static::PATH_BALANCE_TRANSACTIONS, $balanceTransactionId, $params, $opts );
}
/**
* @param string $id The ID of the customer on which to retrieve the balance transactions.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Api_Error_Exception if the request fails
*
* @return Collection The list of balance transactions.
*/
public static function allBalanceTransactions( $id, $params = null, $opts = null ) {
return self::_allNestedResources( $id, static::PATH_BALANCE_TRANSACTIONS, $params, $opts );
}
}
payments/stripe/lib/class-file.php 0000644 00000003062 14760004044 0013213 0 ustar 00 apiBase ) ) {
$opts->apiBase = Stripe::$apiUploadBase;
}
// Manually flatten params, otherwise curl's multipart encoder will
// choke on nested arrays.
$flatParams = array_column( \Stripe\Util\Util::flattenParams( $params ), 1, 0 );
return static::_create( $flatParams, $opts );
}
}
payments/stripe/lib/class-stripe.php 0000644 00000014422 14760004044 0013604 0 ustar 00 instanceUrl() . '/cancel';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
}
payments/stripe/lib/class-recipient.php 0000644 00000001470 14760004044 0014257 0 ustar 00 instanceUrl() . '/cancel';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Exception\Api_Error_Exception if the request fails
*
* @return PaymentIntent The captured payment intent.
*/
public function capture( $params = null, $opts = null ) {
$url = $this->instanceUrl() . '/capture';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Exception\Api_Error_Exception if the request fails
*
* @return PaymentIntent The confirmed payment intent.
*/
public function confirm( $params = null, $opts = null ) {
$url = $this->instanceUrl() . '/confirm';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
}
payments/stripe/lib/class-sku.php 0000644 00000001324 14760004044 0013075 0 ustar 00 instanceUrl() . '/verify';
list($response, $opts) = $this->_request('post', $url, $params, $opts);
$this->refreshFrom($response, $opts);
return $this;
}
}
payments/stripe/lib/class-tax-id.php 0000644 00000004355 14760004044 0013470 0 ustar 00 0 ) && ( abs( time() - $timestamp ) > $tolerance ) ) {
throw Exception\Signature_Verification_Exception::factory(
'Timestamp outside the tolerance zone',
$payload,
$header
);
}
return true;
}
/**
* Extracts the timestamp in a signature header.
*
* @param string $header the signature header
* @return int the timestamp contained in the header, or -1 if no valid
* timestamp is found
*/
private static function getTimestamp( $header ) {
$items = explode( ',', $header );
foreach ( $items as $item ) {
$itemParts = explode( '=', $item, 2 );
if ( $itemParts[0] == 't' ) {
if ( ! is_numeric( $itemParts[1] ) ) {
return -1;
}
return intval( $itemParts[1] );
}
}
return -1;
}
/**
* Extracts the signatures matching a given scheme in a signature header.
*
* @param string $header the signature header
* @param string $scheme the signature scheme to look for.
* @return array the list of signatures matching the provided scheme.
*/
private static function getSignatures( $header, $scheme ) {
$signatures = array();
$items = explode( ',', $header );
foreach ( $items as $item ) {
$itemParts = explode( '=', $item, 2 );
if ( $itemParts[0] == $scheme ) {
array_push( $signatures, $itemParts[1] );
}
}
return $signatures;
}
/**
* Computes the signature for a given payload and secret.
*
* The current scheme used by Stripe ("v1") is HMAC/SHA-256.
*
* @param string $payload the payload to sign.
* @param string $secret the secret used to generate the signature.
* @return string the signature as a string.
*/
private static function computeSignature( $payload, $secret ) {
return hash_hmac( 'sha256', $payload, $secret );
}
}
payments/stripe/lib/class-country-spec.php 0000644 00000001105 14760004044 0014723 0 ustar 00 instanceUrl() . '/capture';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
}
payments/stripe/lib/class-recipient-transfer.php 0000644 00000001660 14760004044 0016102 0 ustar 00 filters;
}
/**
* Sets the filters, removing paging options.
*
* @param array $filters The filters.
*/
public function setFilters( $filters ) {
$this->filters = $filters;
}
public function offsetGet( $k ) {
if ( is_string( $k ) ) {
return parent::offsetGet( $k );
} else {
$msg = "You tried to access the {$k} index, but Collection " .
'types only support string keys. (HINT: List calls ' .
'return an object with a `data` (which is the data ' .
"array). You likely want to call ->data[{$k}])";
throw new Exception\InvalidArgumentException( $msg );
}
}
public function all( $params = null, $opts = null ) {
self::_validateParams( $params );
list($url, $params) = $this->extractPathAndUpdateParams( $params );
list($response, $opts) = $this->_request( 'get', $url, $params, $opts );
$obj = Util\Util::convertToStripeObject( $response, $opts );
if ( ! ( $obj instanceof \Stripe\Collection ) ) {
throw new \Stripe\Exception\UnexpectedValueException(
'Expected type ' . self::class . ', got "' . get_class( $obj ) . '" instead.'
);
}
$obj->setFilters( $params );
return $obj;
}
public function create( $params = null, $opts = null ) {
self::_validateParams( $params );
list($url, $params) = $this->extractPathAndUpdateParams( $params );
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
return Util\Util::convertToStripeObject( $response, $opts );
}
public function retrieve( $id, $params = null, $opts = null ) {
self::_validateParams( $params );
list($url, $params) = $this->extractPathAndUpdateParams( $params );
$id = Util\Util::utf8( $id );
$extn = urlencode( $id );
list($response, $opts) = $this->_request(
'get',
"$url/$extn",
$params,
$opts
);
return Util\Util::convertToStripeObject( $response, $opts );
}
/**
* @return \ArrayIterator An iterator that can be used to iterate
* across objects in the current page.
*/
public function getIterator() {
return new \ArrayIterator( $this->data );
}
/**
* @return \ArrayIterator An iterator that can be used to iterate
* backwards across objects in the current page.
*/
public function getReverseIterator() {
return new \ArrayIterator( array_reverse( $this->data ) );
}
/**
* @return \Generator|StripeObject[] A generator that can be used to
* iterate across all objects across all pages. As page boundaries are
* encountered, the next page will be fetched automatically for
* continued iteration.
*/
public function autoPagingIterator() {
$page = $this;
while ( true ) {
$filters = $this->filters ?: array();
if ( array_key_exists( 'ending_before', $filters ) &&
! array_key_exists( 'starting_after', $filters ) ) {
foreach ( $page->getReverseIterator() as $item ) {
yield $item;
}
$page = $page->previousPage();
} else {
foreach ( $page as $item ) {
yield $item;
}
$page = $page->nextPage();
}
if ( $page->isEmpty() ) {
break;
}
}
}
/**
* Returns an empty collection. This is returned from {@see nextPage()}
* when we know that there isn't a next page in order to replicate the
* behavior of the API when it attempts to return a page beyond the last.
*
* @param array|string|null $opts
* @return Collection
*/
public static function emptyCollection( $opts = null ) {
return self::constructFrom( array( 'data' => array() ), $opts );
}
/**
* Returns true if the page object contains no element.
*
* @return boolean
*/
public function isEmpty() {
return empty( $this->data );
}
/**
* Fetches the next page in the resource list (if there is one).
*
* This method will try to respect the limit of the current page. If none
* was given, the default limit will be fetched again.
*
* @param array|null $params
* @param array|string|null $opts
* @return Collection
*/
public function nextPage( $params = null, $opts = null ) {
if ( ! $this->has_more ) {
return static::emptyCollection( $opts );
}
$lastId = end( $this->data )->id;
$params = array_merge(
$this->filters ?: array(),
array( 'starting_after' => $lastId ),
$params ?: array()
);
return $this->all( $params, $opts );
}
/**
* Fetches the previous page in the resource list (if there is one).
*
* This method will try to respect the limit of the current page. If none
* was given, the default limit will be fetched again.
*
* @param array|null $params
* @param array|string|null $opts
* @return Collection
*/
public function previousPage( $params = null, $opts = null ) {
if ( ! $this->has_more ) {
return static::emptyCollection( $opts );
}
$firstId = $this->data[0]->id;
$params = array_merge(
$this->filters ?: array(),
array( 'ending_before' => $firstId ),
$params ?: array()
);
return $this->all( $params, $opts );
}
private function extractPathAndUpdateParams( $params ) {
$url = parse_url( $this->url );
if ( ! isset( $url['path'] ) ) {
throw new Exception\UnexpectedValueException( "Could not parse list url into parts: $url" );
}
if ( isset( $url['query'] ) ) {
// If the URL contains a query param, parse it out into $params so they
// don't interact weirdly with each other.
$query = array();
parse_str( $url['query'], $query );
$params = array_merge( $params ?: array(), $query );
}
return array( $url['path'], $params );
}
}
payments/stripe/lib/class-login-link.php 0000644 00000000405 14760004044 0014335 0 ustar 00 Set up
* a subscription, create an invoice,
* and more about products
* and prices.
*
* @property string $id Unique identifier for the object.
* @property string $object String representing the object's type. Objects of the same type share the same value.
* @property bool $active Whether the price can be used for new purchases.
* @property string $billing_scheme Describes how to compute the price per period. Either per_unit
or tiered
. per_unit
indicates that the fixed amount (specified in unit_amount
or unit_amount_decimal
) will be charged per unit in quantity
(for prices with usage_type=licensed
), or per unit of total usage (for prices with usage_type=metered
). tiered
indicates that the unit pricing will be computed using a tiering strategy as defined using the tiers
and tiers_mode
attributes.
* @property int $created Time at which the object was created. Measured in seconds since the Unix epoch.
* @property string $currency Three-letter ISO currency code, in lowercase. Must be a supported currency.
* @property bool $livemode Has the value true
if the object exists in live mode or the value false
if the object exists in test mode.
* @property null|string $lookup_key A lookup key used to retrieve prices dynamically from a static string.
* @property \Stripe\StripeObject $metadata Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format.
* @property null|string $nickname A brief description of the plan, hidden from customers.
* @property string|\Stripe\Product $product The ID of the product this price is associated with.
* @property null|\Stripe\StripeObject $recurring The recurring components of a price such as interval
and usage_type
.
* @property null|\Stripe\StripeObject[] $tiers Each element represents a pricing tier. This parameter requires billing_scheme
to be set to tiered
. See also the documentation for billing_scheme
.
* @property null|string $tiers_mode Defines if the tiering price should be graduated
or volume
based. In volume
-based tiering, the maximum quantity within a period determines the per unit price. In graduated
tiering, pricing can change as the quantity grows.
* @property null|\Stripe\StripeObject $transform_quantity Apply a transformation to the reported usage or set quantity before computing the amount billed. Cannot be combined with tiers
.
* @property string $type One of one_time
or recurring
depending on whether the price is for a one-time purchase or a recurring (subscription) purchase.
* @property null|int $unit_amount The unit amount in %s to be charged, represented as a whole integer if possible.
* @property null|string $unit_amount_decimal The unit amount in %s to be charged, represented as a decimal string with at most 12 decimal places.
*/
class Price extends Api_Resource
{
const OBJECT_NAME = 'price';
use Api_Operations\All;
use Api_Operations\Create;
use Api_Operations\Delete;
use Api_Operations\Retrieve;
use Api_Operations\Update;
const BILLING_SCHEME_PER_UNIT = 'per_unit';
const BILLING_SCHEME_TIERED = 'tiered';
const TIERS_MODE_GRADUATED = 'graduated';
const TIERS_MODE_VOLUME = 'volume';
const TYPE_ONE_TIME = 'one_time';
const TYPE_RECURRING = 'recurring';
}
payments/stripe/lib/class-ephemeral-key.php 0000644 00000002022 14760004044 0015017 0 ustar 00 body = $body;
$this->code = $code;
$this->headers = $headers;
$this->json = $json;
}
}
payments/stripe/lib/class-mandate.php 0000644 00000001021 14760004044 0013676 0 ustar 00 null,
'error_description' => null,
),
$values
);
parent::refreshFrom( $values, $opts, $partial );
}
}
payments/stripe/lib/class-credit-note.php 0000644 00000006273 14760004044 0014520 0 ustar 00 json, $opts );
$obj->setLastResponse( $response );
return $obj;
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @throws Exception\Api_Error_Exception if the request fails
*
* @return CreditNote The voided credit note.
*/
public function voidCreditNote( $params = null, $opts = null ) {
$url = $this->instanceUrl() . '/void';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
/**
* @param string $id The ID of the credit note on which to retrieve the lines.
* @param array|null $params
* @param array|string|null $opts
*
* @throws Exception\Api_Error_Exception if the request fails
*
* @return Collection The list of lines (CreditNoteLineItem).
*/
public static function allLines( $id, $params = null, $opts = null ) {
return self::_allNestedResources( $id, static::PATH_LINES, $params, $opts );
}
}
payments/stripe/lib/class-bitcoin-transaction.php 0000644 00000000316 14760004044 0016245 0 ustar 00 _save($opts);
}
}
payments/stripe/lib/class-setup-intent.php 0000644 00000004660 14760004044 0014740 0 ustar 00 instanceUrl() . '/cancel';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Exception\Api_Error_Exception if the request fails
*
* @return SetupIntent The confirmed setup intent.
*/
public function confirm( $params = null, $opts = null ) {
$url = $this->instanceUrl() . '/confirm';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
}
payments/stripe/lib/class-stripe-object.php 0000644 00000040041 14760004044 0015044 0 ustar 00 "old_value"]
*
* If we update the object with `metadata[new]=new_value`, the server side
* object now has *both* fields:
*
* metadata = ["old" => "old_value", "new" => "new_value"]
*
* This is okay in itself because usually users will want to treat it as
* additive:
*
* $obj->metadata["new"] = "new_value";
* $obj->save();
*
* However, in other cases, they may want to replace the entire existing
* contents:
*
* $obj->metadata = ["new" => "new_value"];
* $obj->save();
*
* This is where things get a little bit tricky because in order to clear
* any old keys that may have existed, we actually have to send an explicit
* empty string to the server. So the operation above would have to send
* this form to get the intended behavior:
*
* metadata[old]=&metadata[new]=new_value
*
* This method allows us to track which parameters are considered additive,
* and lets us behave correctly where appropriate when serializing
* parameters to be sent.
*
* @return Util\Set Set of additive parameters
*/
public static function getAdditiveParams() {
static $additiveParams = null;
if ( $additiveParams === null ) {
// Set `metadata` as additive so that when it's set directly we remember
// to clear keys that may have been previously set by sending empty
// values for them.
//
// It's possible that not every object has `metadata`, but having this
// option set when there is no `metadata` field is not harmful.
$additiveParams = new Util\Set(
array(
'metadata',
)
);
}
return $additiveParams;
}
public function __construct( $id = null, $opts = null ) {
list($id, $this->_retrieveOptions) = Util\Util::normalizeId( $id );
$this->_opts = Util\Request_Options::parse( $opts );
$this->_originalValues = array();
$this->_values = array();
$this->_unsavedValues = new Util\Set();
$this->_transientValues = new Util\Set();
if ( $id !== null ) {
$this->_values['id'] = $id;
}
}
// Standard accessor magic methods
public function __set( $k, $v ) {
if ( static::getPermanentAttributes()->includes( $k ) ) {
throw new Exception\InvalidArgumentException(
"Cannot set $k on this object. HINT: you can't set: " .
join( ', ', static::getPermanentAttributes()->toArray() )
);
}
if ( $v === '' ) {
throw new Exception\InvalidArgumentException(
'You cannot set \'' . $k . '\'to an empty string. '
. 'We interpret empty strings as NULL in requests. '
. 'You may set obj->' . $k . ' = NULL to delete the property'
);
}
$this->_values[ $k ] = Util\Util::convertToStripeObject( $v, $this->_opts );
$this->dirtyValue( $this->_values[ $k ] );
$this->_unsavedValues->add( $k );
}
public function __isset( $k ) {
return isset( $this->_values[ $k ] );
}
public function __unset( $k ) {
unset( $this->_values[ $k ] );
$this->_transientValues->add( $k );
$this->_unsavedValues->discard( $k );
}
public function &__get( $k ) {
// function should return a reference, using $nullval to return a reference to null
$nullval = null;
if ( ! empty( $this->_values ) && array_key_exists( $k, $this->_values ) ) {
return $this->_values[ $k ];
} elseif ( ! empty( $this->_transientValues ) && $this->_transientValues->includes( $k ) ) {
$class = get_class( $this );
$attrs = join( ', ', array_keys( $this->_values ) );
$message = "Stripe Notice: Undefined property of $class instance: $k. "
. "HINT: The $k attribute was set in the past, however. "
. 'It was then wiped when refreshing the object '
. "with the result returned by Stripe's API, "
. 'probably as a result of a save(). The attributes currently '
. "available on this object are: $attrs";
Stripe::getLogger()->error( $message );
return $nullval;
} else {
$class = get_class( $this );
Stripe::getLogger()->error( "Stripe Notice: Undefined property of $class instance: $k" );
return $nullval;
}
}
// Magic method for var_dump output. Only works with PHP >= 5.6
public function __debugInfo() {
return $this->_values;
}
// ArrayAccess methods
public function offsetSet( $k, $v ) {
$this->$k = $v;
}
public function offsetExists( $k ) {
return array_key_exists( $k, $this->_values );
}
public function offsetUnset( $k ) {
unset( $this->$k );
}
public function offsetGet( $k ) {
return array_key_exists( $k, $this->_values ) ? $this->_values[ $k ] : null;
}
// Countable method
public function count() {
return count( $this->_values );
}
public function keys() {
return array_keys( $this->_values );
}
public function values() {
return array_values( $this->_values );
}
/**
* This unfortunately needs to be public to be used in Util\Util
*
* @param array $values
* @param null|string|array|Util\RequestOptions $opts
*
* @return static The object constructed from the given values.
*/
public static function constructFrom( $values, $opts = null ) {
$obj = new static( isset( $values['id'] ) ? $values['id'] : null );
$obj->refreshFrom( $values, $opts );
return $obj;
}
/**
* Refreshes this object using the provided values.
*
* @param array $values
* @param null|string|array|Util\Request_Options $opts
* @param boolean $partial Defaults to false.
*/
public function refreshFrom( $values, $opts, $partial = false ) {
$this->_opts = Request_Options::parse( $opts );
$this->_originalValues = self::deepCopy( $values );
if ( $values instanceof StripeObject ) {
$values = $values->toArray();
}
// Wipe old state before setting new. This is useful for e.g. updating a
// customer, where there is no persistent card parameter. Mark those values
// which don't persist as transient
if ( $partial ) {
$removed = new Util\Set();
} else {
$removed = new Util\Set( array_diff( array_keys( $this->_values ), array_keys( $values ) ) );
}
foreach ( $removed->toArray() as $k ) {
unset( $this->$k );
}
$this->updateAttributes( $values, $opts, false );
foreach ( $values as $k => $v ) {
$this->_transientValues->discard( $k );
$this->_unsavedValues->discard( $k );
}
}
/**
* Mass assigns attributes on the model.
*
* @param array $values
* @param null|string|array|Util\RequestOptions $opts
* @param boolean $dirty Defaults to true.
*/
public function updateAttributes( $values, $opts = null, $dirty = true ) {
foreach ( $values as $k => $v ) {
// Special-case metadata to always be cast as a StripeObject
// This is necessary in case metadata is empty, as PHP arrays do
// not differentiate between lists and hashes, and we consider
// empty arrays to be lists.
if ( ( $k === 'metadata' ) && ( is_array( $v ) ) ) {
$this->_values[ $k ] = Stripe_Object::constructFrom( $v, $opts );
} else {
$this->_values[ $k ] = Util\Util::convertToStripeObject( $v, $opts );
}
if ( $dirty ) {
$this->dirtyValue( $this->_values[ $k ] );
}
$this->_unsavedValues->add( $k );
}
}
/**
* @return array A recursive mapping of attributes to values for this object,
* including the proper value for deleted attributes.
*/
public function serializeParameters( $force = false ) {
$updateParams = array();
foreach ( $this->_values as $k => $v ) {
// There are a few reasons that we may want to add in a parameter for
// update:
//
// 1. The `$force` option has been set.
// 2. We know that it was modified.
// 3. Its value is a StripeObject. A StripeObject may contain modified
// values within in that its parent StripeObject doesn't know about.
//
$original = array_key_exists( $k, $this->_originalValues ) ? $this->_originalValues[ $k ] : null;
$unsaved = $this->_unsavedValues->includes( $k );
if ( $force || $unsaved || $v instanceof StripeObject ) {
$updateParams[ $k ] = $this->serializeParamsValue(
$this->_values[ $k ],
$original,
$unsaved,
$force,
$k
);
}
}
// a `null` that makes it out of `serializeParamsValue` signals an empty
// value that we shouldn't appear in the serialized form of the object
$updateParams = array_filter(
$updateParams,
function ( $v ) {
return $v !== null;
}
);
return $updateParams;
}
public function serializeParamsValue( $value, $original, $unsaved, $force, $key = null ) {
// The logic here is that essentially any object embedded in another
// object that had a `type` is actually an API resource of a different
// type that's been included in the response. These other resources must
// be updated from their proper endpoints, and therefore they are not
// included when serializing even if they've been modified.
//
// There are _some_ known exceptions though.
//
// For example, if the value is unsaved (meaning the user has set it), and
// it looks like the API resource is persisted with an ID, then we include
// the object so that parameters are serialized with a reference to its
// ID.
//
// Another example is that on save API calls it's sometimes desirable to
// update a customer's default source by setting a new card (or other)
// object with `->source=` and then saving the customer. The
// `saveWithParent` flag to override the default behavior allows us to
// handle these exceptions.
//
// We throw an error if a property was set explicitly but we can't do
// anything with it because the integration is probably not working as the
// user intended it to.
if ( $value === null ) {
return '';
} elseif ( ( $value instanceof ApiResource ) && ( ! $value->saveWithParent ) ) {
if ( ! $unsaved ) {
return null;
} elseif ( isset( $value->id ) ) {
return $value;
} else {
throw new Exception\InvalidArgumentException(
"Cannot save property `$key` containing an API resource of type " .
get_class( $value ) . ". It doesn't appear to be persisted and is " .
'not marked as `saveWithParent`.'
);
}
} elseif ( is_array( $value ) ) {
if ( Util\Util::isList( $value ) ) {
// Sequential array, i.e. a list
$update = array();
foreach ( $value as $v ) {
array_push( $update, $this->serializeParamsValue( $v, null, true, $force ) );
}
// This prevents an array that's unchanged from being resent.
if ( $update !== $this->serializeParamsValue( $original, null, true, $force, $key ) ) {
return $update;
}
} else {
// Associative array, i.e. a map
return Util\Util::convertToStripeObject( $value, $this->_opts )->serializeParameters();
}
} elseif ( $value instanceof StripeObject ) {
$update = $value->serializeParameters( $force );
if ( $original && $unsaved && $key && static::getAdditiveParams()->includes( $key ) ) {
$update = array_merge( self::emptyValues( $original ), $update );
}
return $update;
} else {
return $value;
}
}
public function jsonSerialize() {
return $this->toArray();
}
/**
* Returns an associative array with the key and values composing the
* Stripe object.
*
* @return array The associative array.
*/
public function toArray() {
$maybeToArray = function ( $value ) {
if ( is_null( $value ) ) {
return null;
}
return is_object( $value ) && method_exists( $value, 'toArray' ) ? $value->toArray() : $value;
};
return array_reduce(
array_keys( $this->_values ),
function ( $acc, $k ) use ( $maybeToArray ) {
if ( $k[0] == '_' ) {
return $acc;
}
$v = $this->_values[ $k ];
if ( Util\Util::isList( $v ) ) {
$acc[ $k ] = array_map( $maybeToArray, $v );
} else {
$acc[ $k ] = $maybeToArray( $v );
}
return $acc;
},
array()
);
}
/**
* Returns a pretty JSON representation of the Stripe object.
*
* @return string The JSON representation of the Stripe object.
*/
public function toJSON() {
return json_encode( $this->toArray(), JSON_PRETTY_PRINT );
}
public function __toString() {
$class = get_class( $this );
return $class . ' JSON: ' . $this->toJSON();
}
/**
* Sets all keys within the StripeObject as unsaved so that they will be
* included with an update when `serializeParameters` is called. This
* method is also recursive, so any StripeObjects contained as values or
* which are values in a tenant array are also marked as dirty.
*/
public function dirty() {
$this->_unsavedValues = new Util\Set( array_keys( $this->_values ) );
foreach ( $this->_values as $k => $v ) {
$this->dirtyValue( $v );
}
}
protected function dirtyValue( $value ) {
if ( is_array( $value ) ) {
foreach ( $value as $v ) {
$this->dirtyValue( $v );
}
} elseif ( $value instanceof StripeObject ) {
$value->dirty();
}
}
/**
* Produces a deep copy of the given object including support for arrays
* and StripeObjects.
*/
protected static function deepCopy( $obj ) {
if ( is_array( $obj ) ) {
$copy = array();
foreach ( $obj as $k => $v ) {
$copy[ $k ] = self::deepCopy( $v );
}
return $copy;
} elseif ( $obj instanceof StripeObject ) {
return $obj::constructFrom(
self::deepCopy( $obj->_values ),
clone $obj->_opts
);
} else {
return $obj;
}
}
/**
* Returns a hash of empty values for all the values that are in the given
* StripeObject.
*/
public static function emptyValues( $obj ) {
if ( is_array( $obj ) ) {
$values = $obj;
} elseif ( $obj instanceof StripeObject ) {
$values = $obj->_values;
} else {
throw new Exception\InvalidArgumentException(
'empty_values got unexpected object type: ' . get_class( $obj )
);
}
$update = array_fill_keys( array_keys( $values ), '' );
return $update;
}
/**
* @return object The last response from the Stripe API
*/
public function getLastResponse() {
return $this->_lastResponse;
}
/**
* Sets the last response from the Stripe API
*
* @param ApiResponse $resp
* @return void
*/
public function setLastResponse( $resp ) {
$this->_lastResponse = $resp;
}
/**
* Indicates whether or not the resource has been deleted on the server.
* Note that some, but not all, resources can indicate whether they have
* been deleted.
*
* @return bool Whether the resource is deleted.
*/
public function isDeleted() {
return isset( $this->_values['deleted'] ) ? $this->_values['deleted'] : false;
}
}
payments/stripe/lib/class-usage-record-summary.php 0000644 00000000631 14760004044 0016346 0 ustar 00 _save( $opts );
}
}
payments/stripe/lib/class-error-object.php 0000644 00000024073 14760004044 0014676 0 ustar 00 null,
'code' => null,
'decline_code' => null,
'doc_url' => null,
'message' => null,
'param' => null,
'payment_intent' => null,
'payment_method' => null,
'setup_intent' => null,
'source' => null,
'type' => null,
),
$values
);
parent::refreshFrom( $values, $opts, $partial );
}
}
payments/stripe/lib/class-subscription.php 0000644 00000006354 14760004044 0015027 0 ustar 00 _delete($params, $opts);
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Exception\Api_Error_Exception if the request fails
*
* @return Subscription The updated subscription.
*/
public function deleteDiscount($params = null, $opts = null)
{
$url = $this->instanceUrl() . '/discount';
list($response, $opts) = $this->_request('delete', $url, $params, $opts);
$this->refreshFrom(['discount' => null], $opts, true);
}
}
payments/stripe/lib/class-payment-method.php 0000644 00000003161 14760004044 0015227 0 ustar 00 instanceUrl() . '/attach';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Exception\Api_Error_Exception if the request fails
*
* @return PaymentMethod The detached payment method.
*/
public function detach( $params = null, $opts = null ) {
$url = $this->instanceUrl() . '/detach';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
}
payments/stripe/lib/class-request-telemetry.php 0000644 00000001053 14760004044 0015772 0 ustar 00 requestId = $requestId;
$this->requestDuration = $requestDuration;
}
}
payments/stripe/lib/class-card.php 0000644 00000010136 14760004044 0013205 0 ustar 00 instanceUrl() . '/cancel';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
/**
* @param string $id The ID of the transfer on which to create the transfer reversal.
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Stripe\Exception\ApiErrorException if the request fails
*
* @return TransferReversal
*/
public static function createReversal( $id, $params = null, $opts = null ) {
return self::_createNestedResource( $id, static::PATH_REVERSALS, $params, $opts );
}
/**
* @param string $id The ID of the transfer to which the transfer reversal belongs.
* @param string $reversalId The ID of the transfer reversal to retrieve.
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Stripe\Exception\ApiErrorException if the request fails
*
* @return TransferReversal
*/
public static function retrieveReversal( $id, $reversalId, $params = null, $opts = null ) {
return self::_retrieveNestedResource( $id, static::PATH_REVERSALS, $reversalId, $params, $opts );
}
/**
* @param string $id The ID of the transfer to which the transfer reversal belongs.
* @param string $reversalId The ID of the transfer reversal to update.
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Stripe\Exception\ApiErrorException if the request fails
*
* @return TransferReversal
*/
public static function updateReversal( $id, $reversalId, $params = null, $opts = null ) {
return self::_updateNestedResource( $id, static::PATH_REVERSALS, $reversalId, $params, $opts );
}
/**
* @param string $id The ID of the transfer on which to retrieve the transfer reversals.
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Stripe\Exception\ApiErrorException if the request fails
*
* @return Collection The list of transfer reversals.
*/
public static function allReversals( $id, $params = null, $opts = null ) {
return self::_allNestedResources( $id, static::PATH_REVERSALS, $params, $opts );
}
}
payments/stripe/lib/class-exchange-rate.php 0000644 00000000505 14760004044 0015006 0 ustar 00 instanceUrl() . '/pay';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Exception\Api_Error_Exception if the request fails
*
* @return OrderReturn The newly created return.
*/
public function returnOrder( $params = null, $opts = null ) {
$url = $this->instanceUrl() . '/returns';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
return Util\Util::convertToStripeObject( $response, $opts );
}
}
payments/stripe/lib/class-capability.php 0000644 00000004337 14760004044 0014423 0 ustar 00 instanceUrl() . '/cancel';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
}
payments/stripe/lib/class-source.php 0000644 00000011673 14760004044 0013603 0 ustar 00 _request( 'delete', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
} else {
$message = 'This source object does not appear to be currently attached '
. 'to a customer object.';
throw new Exception\UnexpectedValueException( $message );
}
}
/**
* @deprecated sourceTransactions is deprecated. Please use Source::allSourceTransactions instead.
*
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Exception\Api_Error_Exception if the request fails
*
* @return Collection The list of source transactions.
*/
public function sourceTransactions( $params = null, $opts = null ) {
$url = $this->instanceUrl() . '/source_transactions';
list($response, $opts) = $this->_request( 'get', $url, $params, $opts );
$obj = \Stripe\Util\Util::convertToStripeObject( $response, $opts );
$obj->setLastResponse( $response );
return $obj;
}
/**
* @param string $id
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Exception\Api_Error_Exception if the request fails
*
* @return Collection The list of source transactions.
*/
public static function allSourceTransactions( $id, $params = null, $opts = null ) {
return self::_allNestedResources( $id, '/source_transactions', $params, $opts );
}
/**
* @param array|null $params
* @param array|string|null $opts
*
* @throws \Exception\Api_Error_Exception if the request fails
*
* @return Source The verified source.
*/
public function verify( $params = null, $opts = null ) {
$url = $this->instanceUrl() . '/verify';
list($response, $opts) = $this->_request( 'post', $url, $params, $opts );
$this->refreshFrom( $response, $opts );
return $this;
}
}
payments/stripe/class-penci-stripe-sepa.php 0000644 00000012360 14760004044 0015057 0 ustar 00 id = 'stripepaywall_sepa';
$this->has_fields = true;
$this->GATEWAYNAME = 'Stripe Subscribe (SEPA Direct Debit)';
$this->method_title = 'Stripe Subscribe (SEPA Direct Debit)';
$this->method_description = esc_html__( 'Stripe Recurring Subscription settings for Penci Paywall', 'penci-paywall' );
$this->method_description .= sprintf( __( 'All other general Stripe Subscription settings can be adjusted here.', 'penci-paywall' ), admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=stripepaywall' ) );
$this->order_button_text = esc_html__( 'Place Order', 'penci-paywall' );
$this->init_form_fields();
$this->init_settings();
// The shop owner credentials
$stripe_settings = get_option( 'woocommerce_stripepaywall_settings' );
$this->api_credentials['webhook'] = $stripe_settings[ 'webhookkey' ];
$this->title = esc_html__( 'Stripe Subscription (SEPA Direct Debit)', 'penci-paywall' );
$this->testmode = $stripe_settings[ 'testmode' ];
if ( $this->testmode === 'yes' ) {
$this->description = sprintf( __( '(TEST MODE) Pay with your SEPA Direct Debit via Stripe. In test mode, you can use the card number DE89370400440532013000 or check the Testing Stripe documentation for more card numbers.', 'penci-paywall' ), 'https://stripe.com/docs/testing' );
$this->api_credentials['publishable'] = $stripe_settings[ 'publishabletestkey' ];
$this->api_credentials['secret'] = $stripe_settings[ 'secrettestkey' ];
} else {
$this->description = esc_html__( 'Pay with your SEPA Direct Debit via Stripe.', 'penci-paywall' );
$this->api_credentials['publishable'] = $stripe_settings[ 'publishablelivekey' ];
$this->api_credentials['secret'] = $stripe_settings[ 'secretlivekey' ];
}
// Hooks.
add_action( 'wp_enqueue_scripts', [ $this, 'payment_scripts' ] );
add_action(
'woocommerce_update_options_payment_gateways_' . $this->id,
[
$this,
'process_admin_options',
]
);
if ( $this->is_valid_for_use() ) {
$this->webhook_handler();
} else {
$this->enabled = 'no';
}
}
/**
* Initialise Gateway Settings Form Fields
*/
public function init_form_fields() {
$this->form_fields = apply_filters(
'woocommerce_stripepaywall_sepa_settings',
[
'enabled' => [
'title' => __( 'Enable/Disable', 'penci-paywall' ),
'label' => __( 'Enable Stripe Subscribe (SEPA Direct Debit)', 'penci-paywall' ),
'type' => 'checkbox',
'description' => '',
'default' => 'no',
],
]
);
}
/**
* Get Card Type Icons
*/
public function get_icon() {
$icons = apply_filters(
'pencipw_stripe_payment_icons',
[
'sepa' => '
',
]
);
$icons_str = '';
$icons_str .= isset( $icons['sepa'] ) ? $icons['sepa'] : '';
return apply_filters( 'woocommerce_gateway_icon', $icons_str, $this->id );
}
/**
* Check if this gateway is valid for use.
*
* @return bool
*/
public function is_valid_for_use() {
$supported_currencies = [ 'EUR' ];
// Not supported currency
if ( ! in_array( get_woocommerce_currency(), $supported_currencies ) ) {
return false;
}
// If no SSL in live mode.
if ( ! $this->testmode && ! is_ssl() ) {
return false;
}
// Keys are not set
if ( empty( $this->api_credentials['secret'] ) || empty( $this->api_credentials['publishable'] ) ) {
return false;
}
return true;
}
/**
* Payment Fields.
*
*/
public function payment_fields() {
ob_start();
print($this->description);
?>
setApiKey( $credentials['secret'] );
}
} payments/stripe/class-stripe-helper.php 0000644 00000010402 14760004044 0014305 0 ustar 00 code ) {
return esc_html__( 'Please try to re-input your card or use another card', 'penci-paywall' );
}
$messages = $this->get_messages();
$message = esc_html__( 'Unable to process your payment, please try again later', 'penci-paywall' );
if ( 'card_error' === $error->type ) {
$message = isset( $messages[ $error->code ] ) ? $messages[ $error->code ] : $error->message;
} else {
$message = isset( $messages[ $error->type ] ) ? $messages[ $error->type ] : $error->message;
}
return $message;
}
/**
* Get array error message.
*
* @return string
*/
public function get_messages() {
return [
'invalid_number' => esc_html__( 'The card number is not a valid credit card number.', 'penci-paywall' ),
'invalid_expiry_month' => esc_html__( 'The card\'s expiration month is invalid.', 'penci-paywall' ),
'invalid_expiry_year' => esc_html__( 'The card\'s expiration year is invalid.', 'penci-paywall' ),
'invalid_cvc' => esc_html__( 'The card\'s security code is invalid.', 'penci-paywall' ),
'incorrect_number' => esc_html__( 'The card number is incorrect.', 'penci-paywall' ),
'incomplete_number' => esc_html__( 'The card number is incomplete.', 'penci-paywall' ),
'incomplete_cvc' => esc_html__( 'The card\'s security code is incomplete.', 'penci-paywall' ),
'incomplete_expiry' => esc_html__( 'The card\'s expiration date is incomplete.', 'penci-paywall' ),
'expired_card' => esc_html__( 'The card has expired.', 'penci-paywall' ),
'incorrect_cvc' => esc_html__( 'The card\'s security code is incorrect.', 'penci-paywall' ),
'incorrect_zip' => esc_html__( 'The card\'s zip code failed validation.', 'penci-paywall' ),
'invalid_expiry_year_past' => esc_html__( 'The card\'s expiration year is in the past', 'penci-paywall' ),
'card_declined' => esc_html__( 'The card was declined.', 'penci-paywall' ),
'missing' => esc_html__( 'There is no card on a customer that is being charged.', 'penci-paywall' ),
'processing_error' => esc_html__( 'An error occurred while processing the card.', 'penci-paywall' ),
'invalid_request_error' => esc_html__( 'Unable to process this payment, please try again or use alternative method.', 'penci-paywall' ),
'invalid_sofort_country' => esc_html__( 'The billing country is not accepted by SOFORT. Please try another country.', 'penci-paywall' ),
'email_invalid' => esc_html__( 'Invalid email address, please correct and try again.', 'penci-paywall' ),
'default_card_error' => esc_html__( 'We are unable to authenticate your payment method. Please choose a different payment method and try again.', 'penci-paywall' ),
'parameter_invalid_empty' => esc_html__( 'Please make sure you have inputted billing detail required fields.', 'penci-paywall' ),
];
}
/**
* Zero decimal currencies.
*
* @return string
*/
public function zero_decimal( $currency ) {
$currencies = [
'bif', // Burundian Franc
'clp', // Chilean Peso
'djf', // Djiboutian Franc
'gnf', // Guinean Franc
'jpy', // Japanese Yen
'kmf', // Comorian Franc
'krw', // South Korean Won
'mga', // Malagasy Ariary
'pyg', // Paraguayan GuaranÃ
'rwf', // Rwandan Franc
'ugx', // Ugandan Shilling
'vnd', // Vietnamese Äồng
'vuv', // Vanuatu Vatu
'xaf', // Central African Cfa Franc
'xof', // West African Cfa Franc
'xpf', // Cfp Franc
];
return in_array( strtolower( $currency ), $currencies );
}
/**
* Sanitize statement descriptor text.
*
* @return string
*/
public static function statement_descriptor( $statement_descriptor = '' ) {
$disallowed_characters = array( '<', '>', '"', "'" );
$statement_descriptor = str_replace( $disallowed_characters, '', $statement_descriptor );
$statement_descriptor = substr( trim( $statement_descriptor ), 0, 22 );
return $statement_descriptor;
}
}
payments/stripe/class-stripe-api-request.php 0000644 00000006326 14760004044 0015277 0 ustar 00 error = false;
switch ( $request ) {
case 'create_price':
$this->response = Price::create( $args );
break;
case 'check_price':
$this->response = Price::retrieve( $args );
break;
case 'create_product':
$this->response = Product::create( $args );
break;
case 'check_product':
$this->response = Product::retrieve( $args );
break;
case 'update_product':
$this->response = Product::update( $args[0], $args[1] );
break;
case 'create_subscription':
$this->response = Subscription::create( $args );
break;
case 'check_subscription':
$this->response = Subscription::retrieve( $args );
break;
case 'cancel_subscription':
$this->response = Subscription::retrieve( $args )->delete();
break;
case 'update_subscription':
$this->response = Subscription::update( $args[0], $args[1] );
break;
case 'create_customer':
$this->response = Customer::create( $args );
break;
case 'check_customer':
$this->response = Customer::retrieve( $args );
break;
case 'update_customer':
$this->response = Customer::update( $args[0], $args[1] );
break;
case 'check_source':
$this->response = Customer::retrieveSource( $args, null );
break;
case 'delete_source':
$this->response = Customer::deleteSource( $args[0], $args[1] );
break;
case 'attach_source':
$this->response = Customer::createSource( $args[0], $args[1] );
break;
case 'create_webhook':
$this->response = Webhook_Endpoint::create( $args );
break;
case 'check_intent':
$this->response = Payment_Intent::retrieve( $args );
break;
case 'update_intent':
$this->response = Payment_Intent::update( $args[0], $args[1] );
break;
case 'confirm_intent':
$payment_intent = Payment_Intent::retrieve( $args[0] );
$this->response = $payment_intent->confirm( $args[1] );
break;
case 'check_intent':
$this->response = Payment_Intent::retrieve( $args );
break;
case 'delete_intent':
$this->response = Payment_Intent::delete( $args );
break;
case 'check_invoice':
$this->response = Invoice::retrieve( $args );
break;
case 'check_charge':
$this->response = Charge::retrieve( $args );
break;
case 'create_payment':
$this->response = Payment_Intent::create( $args );
break;
default:
break;
}
} catch( Exception $e ) {
$this->response = $e->getError();
$this->error = true;
}
}
function get_response() {
return $this->response;
}
function is_error() {
return $this->error;
}
}
payments/stripe/class-stripe-webhook.php 0000644 00000022172 14760004044 0014473 0 ustar 00 data->object;
// Return to Woocommerce if not Penci Paywall Subscribe
if( ( empty( $data->metadata->subscription_type ) || 'pencipw_subscribe' !== $data->metadata->subscription_type ) && ( empty( $data->metadata->unlock_type ) || 'pencipw_unlock' !== $data->metadata->unlock_type ) && ( 'charge.refunded' !== $event->type ) ) {
exit();
} else {
// Handle the notification
switch ( $event->type ) {
case 'customer.subscription.deleted':
$this->pencipw_process_subscription_deleted( $data );
break;
case 'customer.subscription.updated':
case 'customer.subscription.created':
$this->pencipw_process_subscription_updated( $data );
break;
case 'payment_intent.succeeded':
$this->pencipw_process_payment_succeded( $data );
break;
case 'payment_intent.payment_failed':
$this->pencipw_process_payment_failed( $data );
break;
case 'charge.refunded':
$this->pencipw_process_charge_refunded( $data );
break;
default:
break;
}
}
exit();
}
/**
* Get metadata
*
* @return array
*/
public function pencipw_get_metadata( $data ) {
if ( empty( $data->metadata->order_id ) ) {
header( 'HTTP/1.1 201' );
echo json_encode( esc_html__( 'Could not find order id in metadata', 'penci-paywall' ) );
return false;
}
$order_id = $data->metadata->order_id;
$order = wc_get_order( $order_id );
if ( ! $order ) {
header( 'HTTP/1.1 201' );
echo json_encode( sprintf( __( 'Could not find order id: $d', 'penci-paywall' ), $order_id ) );
return false;
}
$user_id = $order->get_user_id();
if ( ! $order_id ) {
header( 'HTTP/1.1 201' );
echo json_encode( sprintf( __( 'Could not find user via order id %d', 'penci-paywall' ), $order_id ) );
return false;
}
return [ $order_id, $order, $user_id ];
}
/**
* Handle subcription deleted event
*
* @return null
*/
public function pencipw_process_subscription_deleted( $data ) {
$subs_id = $data->id;
$metadata = $this->pencipw_get_metadata( $data );
if ( empty( $metadata ) ) {
return;
}
$order_id = $metadata[0];
$order = $metadata[1];
$user_id = $metadata[2];
if ( $subs_id !== get_user_option( 'pencipw_stripe_subs_id', $user_id ) ) {
header( 'HTTP/1.1 201' );
echo json_encode( sprintf( __( 'Could not find subscription %d in user %s', 'penci-paywall '), $subs_id, $user_id) );
return;
}
update_user_option( $user_id, 'pencipw_expired_date', false );
update_user_option( $user_id, 'pencipw_subscribe_status', false );
$product_name = $data->metadata->product;
$customer_name = get_user_option( 'billing_first_name', $user_id ) . ' ' . get_user_option( 'billing_last_name', $user_id );
header( 'HTTP/1.1 200' );
echo json_encode( sprintf( __( 'Subscription for %s by %s has been canceled', 'penci-paywall' ), $product_name, $customer_name) );
return;
}
/**
* Handle subcription created & updated event
*
* @return null
*/
public function pencipw_process_subscription_updated( $data ) {
$subs_id = $data->id;
$metadata = $this->pencipw_get_metadata( $data );
if ( empty( $metadata ) ) {
return;
}
$order_id = $metadata[0];
$order = $metadata[1];
$user_id = $metadata[2];
if ( $subs_id !== get_user_option( 'pencipw_stripe_subs_id', $user_id ) ) {
header( 'HTTP/1.1 201' );
echo json_encode( sprintf( __( 'Could not find subscription %d in user %s', 'penci-paywall' ), $subs_id, $user_id ) );
return;
}
if ( 'active' === $data->status ) {
$expired = new DateTime();
$expired = $expired->setTimestamp( $data->current_period_end );
$expired = $expired->setTimezone( new DateTimeZone( 'UTC' ) );
$expired = $expired->format( 'Y-m-d H:i:s' );
update_user_option( $user_id, 'pencipw_expired_date', $expired );
update_user_option( $user_id, 'pencipw_subscribe_status', 'ACTIVE' );
$order->update_status( 'completed' );
$product_name = $data->metadata->product;
$customer_name = get_user_option( 'billing_first_name', $user_id ) . ' ' . get_user_option( 'billing_last_name', $user_id );
header( 'HTTP/1.1 200' );
echo json_encode( sprintf( __( 'Subscription for %s by %s has been activated', 'penci-paywall' ), $product_name, $customer_name ) );
} else {
$this->pencipw_process_subscription_deleted( $data );
}
return;
}
/**
* Handle payment succeded event
*
* @return null
*/
public function pencipw_process_payment_succeded( $data ) {
$payment_id = $data->id;
$metadata = $this->pencipw_get_metadata( $data );
if ( empty( $metadata ) ) {
return;
}
$order_id = $metadata[0];
$order = $metadata[1];
$user_id = $metadata[2];
if ( ! $order->has_status( 'completed' ) ) {
$order->update_status( 'completed' );
}
$customer_name = get_user_option( 'billing_first_name', $user_id ) . ' ' . get_user_option( 'billing_last_name', $user_id );
header( 'HTTP/1.1 200' );
echo json_encode( sprintf( __( 'Order by %s has completed', 'penci-paywall' ), $customer_name ) );
return;
}
/**
* Handle payment failed event
*
* @return null
*/
public function pencipw_process_payment_failed( $data ) {
$payment_id = $data->id;
$metadata = $this->pencipw_get_metadata( $data );
if ( empty( $metadata ) ) {
return;
}
$order_id = $metadata[0];
$order = $metadata[1];
$user_id = $metadata[2];
$order->update_status( 'failed' );
$customer_name = get_user_option( 'billing_first_name', $user_id ) . ' ' . get_user_option( 'billing_last_name', $user_id );
header( 'HTTP/1.1 200' );
echo json_encode( sprintf( __( 'Order by %s has failed', 'penci-paywall' ), $customer_name) );
return;
}
/**
* Handle refund payment
*
* @return null
*/
public function pencipw_process_charge_refunded( $data ) {
$payment_id = $data->payment_intent;
$order_id = $this->get_order_id( $payment_id );
$order = wc_get_order( $order_id );
$user_id = $order->get_user_id();
$subs_id = get_user_option( 'pencipw_stripe_subs_id', $user_id );
// If subscription, cancel the subscription
if( $subs_id ) {
foreach ( $order->get_items() as $item_id => $item ) {
$product = wc_get_product( $item['product_id'] );
if ( $product->is_type( 'paywall_subscribe' ) ) {
Stripe_Api_Credentials::client( self::$credentials );
$stripe = new Stripe_Api_Request( 'cancel_subscription', $subs_id );
}
}
}
$order->update_status( 'refunded' );
$customer_name = get_user_option( 'billing_first_name', $user_id ) . ' ' . get_user_option( 'billing_last_name', $user_id );
header( 'HTTP/1.1 200' );
echo json_encode( sprintf( __( 'Payment for order by %s has refunded', 'penci-paywall' ), $customer_name) );
return;
}
/**
* Check for order id from subscription_id
*
* @param array $args Transaction Details.
* @param string $order_type
* @param string $meta_key
*
* @return bool
* @since 1.0.0
*/
public function get_order_id( $args, $order_type = 'shop_order', $meta_key = 'pencipw_stripe_payment_id' ) {
$order_id = '';
if ( isset( $args ) ) {
$payment_id = $args;
} else {
$payment_id = '';
}
// First try and get the order ID by the subscription ID.
if ( ! empty( $payment_id ) ) {
$posts = get_posts(
[
'numberposts' => 1,
'orderby' => 'ID',
'order' => 'ASC',
'meta_key' => $meta_key,
'meta_value' => $payment_id,
'post_type' => $order_type,
'post_status' => 'any',
'suppress_filters' => true,
]
);
if ( ! empty( $posts ) ) {
$order_id = $posts[0]->ID; // Order ID.
}
}
return $order_id;
}
}
payments/stripe/class-stripe-api.php 0000644 00000075735 14760004044 0013623 0 ustar 00 set_stripe_args();
$this->create_customer();
$this->create_payment();
break;
case 'update_payment':
$this->set_stripe_args();
$this->create_customer();
$this->update_payment();
break;
case 'create_subscription':
$this->set_stripe_args();
$this->create_customer();
$this->create_product( self::$stripe_args['item'] );
$this->create_price_recurring( self::$stripe_args['item'] );
$this->create_subscription();
break;
case 'update_subscription':
$this->set_stripe_args();
$this->create_customer();
$this->create_product( self::$stripe_args['item'] );
$this->create_price_recurring( self::$stripe_args['item'] );
$this->update_subscription();
break;
case 'check':
$this->check_subscription();
break;
case 'cancel':
$this->cancel_subscription();
break;
case 'update_intent':
$this->update_intent( $args );
break;
case 'confirm_intent':
$this->confirm_intent( $args );
break;
case 'check_charge':
$this->check_charge( $args );
break;
case 'check_intent':
$this->check_intent( $args );
break;
case 'check_source':
$this->check_source( $args );
break;
case 'delete_source':
$this->delete_source( $args );
break;
case 'default_source':
$this->default_source( $args );
break;
case 'add_source':
$this->add_source( $args );
break;
case 'update_default_source':
$this->update_default_source( $args );
break;
case 'send_email':
$this->send_email( $args );
break;
default:
break;
}
}
/**
* Set Stripe Args Values
*/
protected function set_stripe_args() {
self::$stripe_args = [];
self::$stripe_args['total_price'] = 0;
self::$customer = self::$order_data->get_user();
self::$customer_id = self::$order_data->get_user_id();
$return = new PenciPW_Stripe();
foreach ( self::$order_data->get_items() as $item ) {
$product = wc_get_product( $item['product_id'] );
if ( $product->is_type( 'paywall_subscribe' ) || $product->is_type( 'paywall_unlock' ) ) {
self::$stripe_args['item'] = $item['product_id'];
self::$stripe_args['name'] = $product->get_name();
self::$stripe_args['desc'] = 'no description';
self::$stripe_args['type'] = 'service';
self::$stripe_args['attributes'] = $product->get_attributes();
self::$stripe_args['price'] = $product->get_price();
self::$stripe_args['duration'] = $product->is_type( 'paywall_subscribe' ) ? $product->get_duration() : '';
self::$stripe_args['plan'] = get_post_meta( $item['product_id'], 'pencipw_stripe_plan_id', true );
self::$stripe_args['product'] = get_post_meta( $item['product_id'], 'pencipw_stripe_product_id', true );
self::$stripe_args['currency'] = get_woocommerce_currency();
self::$stripe_args['interval'] = $product->is_type( 'paywall_subscribe' ) ? strtolower( $product->get_interval() ) : '';
self::$stripe_args['customer'] = get_user_option( 'pencipw_stripe_customer_id', self::$customer_id );
self::$stripe_args['subscription'] = get_user_option( 'pencipw_stripe_subs_id', self::$customer_id );
self::$stripe_args['email'] = self::$customer->data->user_email;
}
if ( $product->is_type( 'paywall_unlock' ) ) {
$this->create_product( self::$stripe_args['item'] );
$this->create_price( self::$stripe_args['item'] );
}
self::$stripe_args['total_price'] = self::$stripe_args['total_price'] + ( self::$stripe_args['price'] * $item->get_quantity() );
}
}
/**
* Create a Customer for Stripe
*/
protected function create_customer() {
if ( self::$stripe_args['customer'] ) {
$this->check_customer();
return true;
}
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'create_customer', self::createCustomerRequest() );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
self::$stripe_args['customer'] = $response->id;
update_user_option( self::$customer->get( 'ID' ), 'pencipw_stripe_customer_id', $response->id );
}
/**
* Check a Customer for Stripe
*/
protected function check_customer() {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_customer', self::$stripe_args['customer'] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
if ( 'resource_missing' == $response->code ) {
// Customer not found. Need to input customer
self::$stripe_args['customer'] = false;
$this->create_customer();
} else {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
}
// Customer maybe need to update
$this->update_customer();
}
/**
* Update a Customer for Stripe
*/
protected function update_customer() {
Stripe_Api_Credentials::client( self::$api_credentials );
// Atach source to Customer
if ( ( is_pencipw_subscribe() || ( isset( $_POST[ 'pencipw-stripe-new-payment-method' ] ) && 'true' === $_POST[ 'pencipw-stripe-new-payment-method' ] ) ) && ( isset( $_POST[ 'pencipw-stripe-payment-source' ] ) && 'new' === $_POST[ 'pencipw-stripe-payment-source' ] ) ) {
$request = new Stripe_Api_Request( 'attach_source', [ self::$stripe_args['customer'], [ 'source' => self::$source ] ] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
}
// Update customer
$params = self::updateCustomerRequest();
// unlock doesn't default source
$product = wc_get_product( self::$stripe_args['item'] );
if ( $product->is_type( 'paywall_unlock' ) ) {
unset( $params['default_source'] );
}
$request = new Stripe_Api_Request( 'update_customer', [ self::$stripe_args['customer'], $params ] );
$response = $request->get_response();
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
}
/**
* Init a Customer for add source
*/
protected function init_customer() {
$user_id = get_current_user_id();
$customer = new \WC_Customer( $user_id );
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'create_customer', self::initCustomerRequest( $customer ) );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
self::$result = $response->id;
update_user_option( $user_id, 'pencipw_stripe_customer_id', $response->id );
}
/**
* Create Price Recurring for Stripe
*/
protected function create_price_recurring( $product_id ) {
if ( ! empty( self::$stripe_args['plan'] ) ) {
$this->check_price_recurring();
return true;
}
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'create_price', self::createPriceRecurringRequest() );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
self::$stripe_args['plan'] = $response->id;
update_post_meta( $product_id, 'pencipw_stripe_plan_id', $response->id );
}
/**
* Check Price Recurring for Stripe
*/
protected function check_price_recurring() {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_price', self::$stripe_args['plan'] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
if ( 'resource_missing' == $response->code ) {
// Plan not found. Need to input plan
self::$stripe_args['plan'] = false;
$this->create_price_recurring( self::$stripe_args['item'] );
return true;
} else {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
}
// Plan amount, currency, interval, interval_count can't be updated, check if params have changed
$this->update_price_recurring( $response );
}
/**
* Price Recurring update
*/
protected function update_price_recurring( $response ) {
$amount = self::$helper->zero_decimal( self::$stripe_args['currency'] ) ? self::$stripe_args['price'] : self::$stripe_args['price'] * 100;
if ( ( $response->unit_amount !== $amount )
|| ( $response->currency != strtolower( self::$stripe_args['currency'] ) )
|| ( $response->recurring->interval != self::$stripe_args['interval'] )
|| ( $response->recurring->interval_count != self::$stripe_args['duration'] ) ) {
// create a new plan
self::$stripe_args['plan'] = false;
$this->create_price_recurring( self::$stripe_args['item'] );
}
}
/**
* Create a Price for Stripe
*/
protected function create_price( $product_id ) {
if ( ! empty( self::$stripe_args['plan'] ) ) {
$this->check_price();
return true;
}
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'create_price', self::createPriceRequest() );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
self::$stripe_args['plan'] = $response->id;
update_post_meta( $product_id, 'pencipw_stripe_plan_id', $response->id );
}
/**
* Check a Price for Stripe
*/
protected function check_price() {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_price', self::$stripe_args['plan'] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
if ( 'resource_missing' == $response->code ) {
// Plan not found. Need to input plan
self::$stripe_args['plan'] = false;
$this->create_price( self::$stripe_args['item'] );
return true;
} else {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
}
// Plan amount, currency, interval, interval_count can't be updated, check if params have changed
$this->update_price( $response );
}
/**
* Plan update
*/
protected function update_price( $response ) {
$amount = self::$helper->zero_decimal( self::$stripe_args['currency'] ) ? self::$stripe_args['price'] : self::$stripe_args['price'] * 100;
if ( ( $response->unit_amount !== $amount )
|| ( $response->currency !== strtolower( self::$stripe_args['currency'] ) ) ) {
// create a new plan
self::$stripe_args['plan'] = false;
$this->create_price( self::$stripe_args['item'] );
}
}
/**
* Create a Product for Stripe
*/
protected function create_product( $product_id ) {
if ( ! empty( self::$stripe_args['product'] ) ) {
$this->check_product();
return true;
}
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'create_product', self::createProductRequest() );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
self::$stripe_args['product'] = $response->id;
update_post_meta( $product_id, 'pencipw_stripe_product_id', $response->id );
}
/**
* Check a Product for Stripe
*/
protected function check_product() {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_product', self::$stripe_args['product'] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
if ( 'resource_missing' == $response->code ) {
// Product not found. Need to input plan
self::$stripe_args['product'] = false;
$this->create_product( self::$stripe_args['item'] );
return true;
} else {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
}
$this->update_product( $response );
}
/**
* Product update
*/
protected function update_product( $response ) {
if ( $response->name !== self::$stripe_args['name'] ) {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'update_product', [ $response->id, self::createProductRequest() ] );
}
}
/**
* Create a Subscription for Stripe
*/
protected function create_subscription() {
Stripe_Api_Credentials::client( self::$api_credentials );
$this->check_subscription();
if ( 'empty' != self::$result ) {
$this->check_invoice();
}
$request = new Stripe_Api_Request( 'create_subscription', self::createSubscribeRequest() );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
self::$stripe_args['subscription'] = $response->id;
update_user_option( self::$order_data->get_user_id(), 'pencipw_stripe_subs_id', $response->id );
update_user_option( self::$order_data->get_user_id(), 'pencipw_subs_type', 'stripe' );
update_user_option( self::$order_data->get_user_id(), 'pencipw_expired_date', Date( 'F d, Y', $response->current_period_end ) );
self::$result = $response;
}
/**
* Update a Subscription for Stripe
*/
protected function update_subscription() {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_subscription', self::$stripe_args['subscription'] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( self::$stripe_args['plan'] !== $response->plan->id ) {
$request = new Stripe_Api_Request( 'update_subscription', [ self::$stripe_args['subscription'], self::updateSubscribeRequest() ] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
}
self::$stripe_args['subscription'] = $response->id;
update_user_option( self::$order_data->get_user_id(), 'pencipw_stripe_subs_id', $response->id );
update_user_option( self::$order_data->get_user_id(), 'pencipw_subs_type', 'stripe' );
update_user_option( self::$order_data->get_user_id(), 'pencipw_expired_date', Date( 'F d, Y', $response->current_period_end ) );
self::$result = $response;
}
/**
* Create a PaymentIntent for Stripe
*/
protected function create_payment() {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'create_payment', self::createPaymentRequest() );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
update_post_meta( self::$order_id, 'pencipw_stripe_payment_id', $response->id );
self::$order_data->update_meta_data( 'pencipw_stripe_payment_id', $response->id );
self::$order_data->save();
self::$result = $response;
}
/**
* Update PaymentIntent for Stripe
*/
protected function update_payment() {
$payment_id = self::$order_data->get_meta( 'pencipw_stripe_payment_id' );
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'update_intent', [ $payment_id, self::createPaymentRequest() ] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
update_post_meta( self::$order_id, 'pencipw_stripe_payment_id', $response->id );
self::$order_data->update_meta_data( 'pencipw_stripe_payment_id', $response->id );
self::$order_data->save();
self::$result = $response;
}
/**
* Check Subscription
*
* @return mixed
*/
protected function check_subscription() {
$subscription_id = self::$stripe_args['subscription'];
if ( ! empty( $subscription_id ) ) {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_subscription', $subscription_id );
self::$result = $request->get_response();
if ( $request->is_error() ) {
self::$result = 'empty';
}
} else {
self::$result = 'empty';
}
}
/**
* Check Invoice
*/
protected function check_invoice() {
$subscription = self::$result;
$subscription = json_decode( json_encode( $subscription ), false );
$intent = null;
if ( ! empty( $subscription->latest_invoice ) ) {
$request = new Stripe_Api_Request( 'check_invoice', $subscription->latest_invoice );
$invoice = $request->get_response();
$invoice = json_decode( json_encode( $invoice ), false );
}
if ( $request->is_error() ) {
return false;
}
if ( ( 'active' == $subscription->status ) && ( 'paid' == $invoice->status ) ) {
throw new \Exception( __( 'You still have an active subscription', 'penci-paywall' ) );
}
$this->cancel_subscription( $subscription->id );
return;
}
/**
* Update Intent Source
*/
protected function update_intent( $id ) {
Stripe_Api_Credentials::client( self::$api_credentials );
$intent = new Stripe_Api_Request(
'update_intent',
[
$id,
self::updateIntentRequest(),
]
);
$response = $intent->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $intent->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
update_post_meta( self::$order_id, 'pencipw_stripe_payment_id', $response->id );
self::$order_data->update_meta_data( 'pencipw_stripe_payment_id', $id );
self::$order_data->save();
self::$result = $response;
}
/**
* Check a Charge for Stripe
*/
protected function check_charge( $id ) {
if ( $id == false ) {
return false;
}
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_charge', $id );
self::$result = json_decode( json_encode( $request->get_response() ), false );
}
/**
* Check a Intent for Stripe
*/
protected function check_intent( $id ) {
if ( $id == false ) {
return false;
}
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_intent', $id );
self::$result = json_decode( json_encode( $request->get_response() ), false );
}
/**
* Retrieve customer sources
*/
protected function check_source( $id ) {
if ( $id == false ) {
self::$result = false;
return false;
}
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_source', $id );
if( $request->is_error() ) {
self::$result = false;
return false;
}
self::$result = json_decode( json_encode( $request->get_response() ), false );
}
/**
* Delete customer sources
*/
protected function delete_source( $args ) {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'delete_source', $args );
self::$result = json_decode( json_encode( $request->get_response() ), false );
}
/**
* Update customer default source
*/
protected function update_default_source( $args ) {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'update_customer', $args );
self::$result = json_decode( json_encode( $request->get_response() ), false );
}
/**
* Check Customer default source
*/
protected function default_source( $id ) {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'check_customer', $id );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if( $request->is_error() ) {
self::$result = false;
return false;
}
self::$result = $response->default_source;
}
/**
* Add new source to Customer
*/
protected function add_source( $source ) {
Stripe_Api_Credentials::client( self::$api_credentials );
$customer_id = get_user_option( 'pencipw_stripe_customer_id', get_current_user_id() );
$request = new Stripe_Api_Request( 'check_customer', $customer_id );
if ( $request->is_error() ) {
$this->init_customer();
$customer_id = self::$result;
// Check again to make sure customer has inputted
if( ! $customer_id ) {
self::$result = false;
return false;
}
}
$request = new Stripe_Api_Request( 'attach_source', [ $customer_id, [ 'source' => $source ] ] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if( $request->is_error() ) {
self::$result = false;
return false;
}
self::$result = $response;
}
/**
* Confirm PaymentIntent for Stripe
*/
protected function confirm_intent( $id ) {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'confirm_intent', [ $id, self::confirmIntentRequest() ] );
$response = $request->get_response();
$response = json_decode( json_encode( $response ), false );
if ( $request->is_error() ) {
$error_message = self::$helper->get_error_message( $response );
throw new \Exception( $error_message );
}
self::$result = $response;
}
/**
* Cancel Subscription
*
* @return mixed
*/
protected function cancel_subscription( $id = null ) {
$subscription_id = empty( $id ) ? get_user_option( 'pencipw_stripe_subs_id', get_current_user_id() ) : $id;
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'cancel_subscription', $subscription_id );
self::$result = $request->get_response();
if ( $request->is_error() ) {
self::$result = [
'status' => 'error'
];
}
}
/**
* Send receipt to customer email when payment succeded
*
* @return mixed
*/
protected function send_email( $args ) {
Stripe_Api_Credentials::client( self::$api_credentials );
$request = new Stripe_Api_Request( 'update_intent', [ $args['id'], [ 'receipt_email' => $args['email'] ] ] );
}
/**
* Create Customer Request Parameters
*
* @return array
*/
private static function createCustomerRequest() {
return [
'name' => self::$order_data->get_billing_first_name() . ' ' . self::$order_data->get_billing_last_name(),
'address' => [
'line1' => self::$order_data->get_billing_address_1(),
'line2' => self::$order_data->get_billing_address_2(),
'city' => self::$order_data->get_billing_city(),
'country' => self::$order_data->get_billing_country(),
'postal_code' => self::$order_data->get_billing_postcode(),
'state' => self::$order_data->get_billing_state(),
],
'description' => sprintf( __( 'Paywall Customer, Name: %s', 'penci-paywall' ), self::$order_data->get_billing_first_name() . ' ' . self::$order_data->get_billing_last_name() ),
'email' => self::$order_data->get_billing_email(),
'phone' => self::$order_data->get_billing_phone(),
'source' => self::$source,
];
}
/**
* Init Customer for add a source
*
* @return array
*/
private static function initCustomerRequest( $customer ) {
return [
'name' => $customer->get_billing_first_name() . ' ' . $customer->get_billing_last_name(),
'address' => [
'line1' => $customer->get_billing_address_1(),
'line2' => $customer->get_billing_address_2(),
'city' => $customer->get_billing_city(),
'country' => $customer->get_billing_country(),
'postal_code' => $customer->get_billing_postcode(),
'state' => $customer->get_billing_state(),
],
'description' => sprintf( __( 'Paywall Customer, Name: %s', 'penci-paywall' ), $customer->get_billing_first_name() . ' ' . $customer->get_billing_last_name() ),
'email' => $customer->get_billing_email(),
'phone' => $customer->get_billing_phone(),
];
}
/**
* Update Customer Request Parameters
*
* @return array
*/
private static function updateCustomerRequest() {
return [
'name' => self::$order_data->get_billing_first_name() . ' ' . self::$order_data->get_billing_last_name(),
'address' => [
'line1' => self::$order_data->get_billing_address_1(),
'line2' => self::$order_data->get_billing_address_2(),
'city' => self::$order_data->get_billing_city(),
'country' => self::$order_data->get_billing_country(),
'postal_code' => self::$order_data->get_billing_postcode(),
'state' => self::$order_data->get_billing_state(),
],
'description' => sprintf( __( 'Paywall Customer, Name: %s', 'penci-paywall' ), self::$order_data->get_billing_first_name() . ' ' . self::$order_data->get_billing_last_name() ),
'email' => self::$order_data->get_billing_email(),
'phone' => self::$order_data->get_billing_phone(),
'default_source' => self::$source,
];
}
/**
* Create Plan Request Parameters
*
* @return array
*/
private static function createPriceRecurringRequest() {
return [
'unit_amount' => self::$helper->zero_decimal( self::$stripe_args['currency'] ) ? self::$stripe_args['price'] : self::$stripe_args['price'] * 100,
'currency' => self::$stripe_args['currency'],
'recurring' => [
'interval' => self::$stripe_args['interval'],
'interval_count' => self::$stripe_args['duration'],
],
'product' => self::$stripe_args['product']
];
}
/**
* Create Price for Unlock Request Parameters
*
* @return array
*/
private static function createPriceRequest() {
return [
'unit_amount' => self::$helper->zero_decimal( self::$stripe_args['currency'] ) ? self::$stripe_args['price'] : self::$stripe_args['price'] * 100,
'currency' => self::$stripe_args['currency'],
'billing_scheme' => 'per_unit',
'product' => self::$stripe_args['product'],
'expand' => [
'tiers',
]
];
}
/**
* Create Product Request Parameters
*
* @return array
*/
private static function createProductRequest() {
return [
'name' => self::$stripe_args['name'],
];
}
/**
* Create Payment Request Parameters
*
* @return array
*/
private static function createPaymentRequest() {
return [
'amount' => self::$helper->zero_decimal( self::$stripe_args['currency'] ) ? self::$stripe_args['total_price'] : self::$stripe_args['total_price'] * 100,
'currency' => self::$stripe_args['currency'],
'customer' => self::$stripe_args['customer'],
'description' => sprintf( __( '%s - Unlock %s', 'penci-paywall' ), get_bloginfo( 'name' ), self::$order_data->get_id() ),
'source' => self::$source,
'receipt_email' => self::$stripe_args['email'],
'metadata' => [
'order_id' => self::$order_id,
'unlock_type' => 'pencipw_unlock',
],
];
}
/**
* Update Intent Request Parameters
*
* @return array
*/
private static function updateIntentRequest() {
if ( empty( self::$source ) ) {
return [
'description' => sprintf( __( '%s - Subscription %s', 'penci-paywall' ), get_bloginfo( 'name' ), self::$order_data->get_id() ),
'receipt_email' => self::$stripe_args['email'],
];
}
return [
'source' => self::$source,
];
}
/**
* Create Subscribe Request Parameters
*
* @return array
*/
private static function createSubscribeRequest() {
return [
'customer' => self::$stripe_args['customer'],
'items' => [
[
'price' => self::$stripe_args['plan'],
],
],
'expand' => [
'latest_invoice.payment_intent',
],
'metadata' => [
'order_id' => self::$order_id,
'product' => self::$stripe_args['name'],
'subscription_type' => 'pencipw_subscribe',
],
];
}
/**
* Update Subscribe Request Parameters
*
* @return array
*/
private static function updateSubscribeRequest() {
return [
'items' => [
[
'price' => self::$stripe_args['plan'],
],
],
'metadata' => [
'order_id' => self::$order_id,
'product' => self::$stripe_args['name'],
'subscription_type' => 'pencipw_subscribe',
],
];
}
/**
* Confirm Intent Request Parameters
*
* @return array
*/
private static function confirmIntentRequest() {
return [
'source' => self::$source,
];
}
/**
* Check Subscribe Request Parameters
*
* @return array
*/
private static function checkSubscribeRequest() {
return [];
}
/**
* Cancel Subscribe Request Parameters
*
* @return array
*/
private static function cancelSubscribeRequest() {
return [
'reason' => '-',
];
}
public function get_response_message() {
return self::$result;
}
}
payments/stripe/class-penci-stripe.php 0000644 00000047170 14760004044 0014140 0 ustar 00 id = 'stripepaywall';
$this->has_fields = true;
$this->GATEWAYNAME = 'Stripe (Credit Card)';
$this->method_title = 'Stripe (Credit Card)';
$this->method_description = esc_html__( 'Stripe Payment settings for Penci Paywall', 'penci-paywall' );
$this->order_button_text = esc_html__( 'Place Order', 'penci-paywall' );
$this->supports = [
'tokenization',
'add_payment_method',
];
$this->init_form_fields();
$this->init_settings();
// The shop owner credentials
$this->api_credentials['webhook'] = $this->get_option( 'webhookkey' );
$this->helper = new Stripe_Helper();
$this->title = esc_html__( 'Stripe (Credit Card)', 'penci-paywall' );
$this->testmode = $this->get_option( 'testmode' );
$this->statement_descriptor = $this->helper->statement_descriptor( $this->get_option( 'statement_descriptor' ) );
if ( $this->testmode === 'yes' ) {
$this->description = sprintf( __( '(TEST MODE) Pay with your credit card via Stripe. In test mode, you can use the card number 4242424242424242 with any CVC and a valid expiration date or check the Testing Stripe documentation for more card numbers.', 'penci-paywall' ), 'https://stripe.com/docs/testing' );
$this->api_credentials['publishable'] = $this->get_option( 'publishabletestkey' );
$this->api_credentials['secret'] = $this->get_option( 'secrettestkey' );
} else {
$this->description = esc_html__( 'Pay with your credit card via Stripe.', 'penci-paywall' );
$this->api_credentials['publishable'] = $this->get_option( 'publishablelivekey' );
$this->api_credentials['secret'] = $this->get_option( 'secretlivekey' );
}
// Hooks.
add_action( 'wp_enqueue_scripts', [ $this, 'payment_scripts' ] );
add_action(
'woocommerce_update_options_payment_gateways_' . $this->id,
[
$this,
'process_admin_options',
]
);
if ( $this->is_valid_for_use() ) {
$this->webhook_handler();
} else {
$this->enabled = 'no';
}
}
/**
* Setup webhook
*
* @return array
*/
public function webhook_handler() {
include_once dirname( __FILE__ ) . '/class-stripe-webhook.php';
new Stripe_Webhook( $this->get_api_credential() );
}
/**
* Initialise Gateway Settings Form Fields
*/
public function init_form_fields() {
$this->form_fields = apply_filters(
'woocommerce_stripepaywall_settings',
[
'testmode' => [
'title' => esc_html__( 'Test Mode', 'penci-paywall' ),
'type' => 'checkbox',
'description' => esc_html__( 'Are you using Stripe Test Mode? Check this option if you using Stripe Test Mode.', 'penci-paywall' ),
'default' => 'no',
],
'publishabletestkey' => [
'title' => esc_html__( 'Test Publishable Key', 'penci-paywall' ),
'type' => 'text',
'description' => esc_html__( 'Your Test Mode Publishable Key.', 'penci-paywall' ),
'default' => '',
],
'secrettestkey' => [
'title' => esc_html__( 'Test Secret Key', 'penci-paywall' ),
'type' => 'text',
'description' => esc_html__( 'Your Test Mode Secret Key.', 'penci-paywall' ),
'default' => '',
],
'publishablelivekey' => [
'title' => esc_html__( 'Live Publishable Key', 'penci-paywall' ),
'type' => 'text',
'description' => esc_html__( 'Your Live Mode Publishable Key.', 'penci-paywall' ),
'default' => '',
],
'secretlivekey' => [
'title' => esc_html__( 'Live Secret Key', 'penci-paywall' ),
'type' => 'text',
'description' => esc_html__( 'Your Live Mode Secret Key.', 'penci-paywall' ),
'default' => '',
],
'webhookkey' => [
'title' => esc_html__( 'Webhook Key', 'penci-paywall' ),
'type' => 'text',
'description' => sprintf( __( 'Your Webhook Key. You must add the following webhook endpoint %s to your Stripe account settings.', 'penci-paywall' ), home_url( '/?penci-paywall=stripe_webhook' ) ),
'default' => '',
],
'statement_descriptor' => [
'title' => esc_html__( 'Statement Descriptor', 'penci-paywall' ),
'type' => 'text',
'description' => esc_html__( 'Your Statement Descriptor. Statement descriptors are limited to 22 characters, cannot use the special characters >, <, ", \, \', *, and must not consist solely of numbers. This will appear on your customer\'s statement in capital letters.', 'penci-paywall' ),
'default' => '',
],
]
);
}
/**
* Get Card Type Icons
*/
public function get_icon() {
$icons = apply_filters(
'pencipw_stripe_payment_icons',
[
'visa' => '
',
'amex' => '
',
'mastercard' => '
',
'discover' => '
',
'diners' => '
',
'jcb' => '
',
]
);
$icons_str = '';
$icons_str .= isset( $icons['visa'] ) ? $icons['visa'] : '';
$icons_str .= isset( $icons['amex'] ) ? $icons['amex'] : '';
$icons_str .= isset( $icons['mastercard'] ) ? $icons['mastercard'] : '';
if ( 'USD' === get_woocommerce_currency() ) {
$icons_str .= isset( $icons['discover'] ) ? $icons['discover'] : '';
$icons_str .= isset( $icons['jcb'] ) ? $icons['jcb'] : '';
$icons_str .= isset( $icons['diners'] ) ? $icons['diners'] : '';
}
return apply_filters( 'woocommerce_gateway_icon', $icons_str, $this->id );
}
/**
* Check if this gateway is valid for use.
*
* @return bool
*/
public function is_valid_for_use() {
$supported_currencies = [
'USD',
'AED',
'AFN',
'ALL',
'AMD',
'ANG',
'AOA',
'ARS',
'AUD',
'AWG',
'AZN',
'BAM',
'BBD',
'BDT',
'BGN',
'BIF',
'BMD',
'BND',
'BOB',
'BRL',
'BSD',
'BWP',
'BZD',
'CAD',
'CDF',
'CHF',
'CLP',
'CNY',
'COP',
'CRC',
'CVE',
'CZK',
'DJF',
'DKK',
'DOP',
'DZD',
'EGP',
'ETB',
'EUR',
'FJD',
'FKP',
'GBP',
'GEL',
'GIP',
'GMD',
'GNF',
'GTQ',
'GYD',
'HKD',
'HNL',
'HRK',
'HTG',
'HUF',
'IDR',
'ILS',
'INR',
'ISK',
'JMD',
'JPY',
'KES',
'KGS',
'KHR',
'KMF',
'KRW',
'KYD',
'KZT',
'LAK',
'LBP',
'LKR',
'LRD',
'LSL',
'MAD',
'MDL',
'MGA',
'MKD',
'MMK',
'MNT',
'MOP',
'MRO',
'MUR',
'MVR',
'MWK',
'MXN',
'MYR',
'MZN',
'NAD',
'NGN',
'NIO',
'NOK',
'NPR',
'NZD',
'PAB',
'PEN',
'PGK',
'PHP',
'PKR',
'PLN',
'PYG',
'QAR',
'RON',
'RSD',
'RUB',
'RWF',
'SAR',
'SBD',
'SCR',
'SEK',
'SGD',
'SHP',
'SLL',
'SOS',
'SRD',
'STD',
'SZL',
'THB',
'TJS',
'TOP',
'TRY',
'TTD',
'TWD',
'TZS',
'UAH',
'UGX',
'UYU',
'UZS',
'VND',
'VUV',
'WST',
'XAF',
'XCD',
'XOF',
'XPF',
'YER',
'ZAR',
'ZMW'
];
// Not supported currency
if ( ! in_array( get_woocommerce_currency(), $supported_currencies ) ) {
return false;
}
// If no SSL in live mode.
if ( ! $this->testmode && ! is_ssl() ) {
return false;
}
// Keys are not set
if ( empty( $this->api_credentials['secret'] ) || empty( $this->api_credentials['publishable'] ) ) {
return false;
}
return true;
}
/**
* Get api credentials
*
* @return array
*/
public function get_api_credential() {
$api_credentials = [
'publishable' => $this->api_credentials['publishable'],
'secret' => $this->api_credentials['secret'],
'webhook' => $this->api_credentials['webhook']
];
return $api_credentials;
}
/**
* Check if payment is enabled.
*
* @return boolean
*/
public function is_enabled() {
return 'yes' === $this->enabled;
}
/**
* Register Stripe JS.
*
* @since 1.0.0
* @version 1.0.0
*/
public function payment_scripts() {
// If not checkout page
if ( ! is_checkout() && ! is_wc_endpoint_url( 'add-paywall-method' ) ) {
return;
}
// If not valid.
if ( ! $this->is_valid_for_use() ) {
return;
}
wp_register_script( 'stripe', 'https://js.stripe.com/v3/', '', '3.0', true );
wp_enqueue_script( 'stripe' );
wp_register_script( 'pencipw_stripe', PENCI_PAYWALL_URL . '/assets/js/stripe.js', '', PENCI_PAYWALL, true );
wp_enqueue_script( 'pencipw_stripe' );
wp_register_style( 'pencipw_stripe_styles', PENCI_PAYWALL_URL . '/assets/css/stripe-styles.css', array(), PENCI_PAYWALL );
wp_enqueue_style( 'pencipw_stripe_styles' );
$stripe_params = [
'key' => $this->api_credentials['publishable'],
'is_checkout' => ( is_checkout() && empty( $_GET['pay_for_order'] ) ) ? 'yes' : 'no',
'is_add_paywall_payment' => is_wc_endpoint_url( 'add-paywall-method' ),
'country' => WC()->countries->get_base_country(),
'currency' => strtolower( get_woocommerce_currency() ),
'sepa_mandate_notification' => apply_filters( 'pencipw_mandate_sepa', 'email' ),
'file_path' => PENCI_PAYWALL_URL . '/class/gateways/stripe/class-penci-stripe.php',
'paywall_method_url' => wc_get_endpoint_url( 'paywall-method' ),
'statement_descriptor' => $this->statement_descriptor,
];
if ( isset( $_GET['pay_for_order'] ) && isset( $_GET['key'] ) ) {
$order_id = wc_get_order_id_by_order_key( wc_clean( wp_unslash( (int) sanitize_text_field( $_GET['key'] ) ) ) );
$order = wc_get_order( $order_id );
if ( is_a( $order, 'WC_Order' ) ) {
$stripe_params = array_merge( $stripe_params, [
'billing_first_name' => $order->get_billing_first_name(),
'billing_last_name' => $order->get_billing_last_name(),
'billing_address_1' => $order->get_billing_address_1(),
'billing_address_2' => $order->get_billing_address_2(),
'billing_state' => $order->get_billing_state(),
'billing_city' => $order->get_billing_city(),
'billing_postcode' => $order->get_billing_postcode(),
'billing_country' => $order->get_billing_country(),
'billing_email' => $order->get_billing_email(),
'billing_phone' => $order->get_billing_phone(),
] );
}
}
if ( is_wc_endpoint_url( 'add-paywall-method' ) ) {
$customer = new WC_Customer( get_current_user_id() );
$stripe_params = array_merge( $stripe_params, [
'billing_first_name' => $customer->get_billing_first_name(),
'billing_last_name' => $customer->get_billing_last_name(),
'billing_address_1' => $customer->get_billing_address_1(),
'billing_address_2' => $customer->get_billing_address_2(),
'billing_state' => $customer->get_billing_state(),
'billing_city' => $customer->get_billing_city(),
'billing_postcode' => $customer->get_billing_postcode(),
'billing_country' => $customer->get_billing_country(),
'billing_email' => $customer->get_billing_email(),
'billing_phone' => $customer->get_billing_phone(),
] );
}
$stripe_params = array_merge( $stripe_params, $this->helper->get_messages() );
wp_localize_script( 'pencipw_stripe', 'pencipw_stripe_vars', apply_filters( 'pencipw_stripe_vars', $stripe_params ) );
}
/**
* Payment Fields.
*
*/
public function payment_fields() {
ob_start();
print( $this->description );
$cards = null;
if ( get_user_option( 'pencipw_stripe_customer_id', get_current_user_id() ) ) {
$cards = new Stripe_Api( 'check_source', $this->get_api_credential(), null, null, get_user_option( 'pencipw_stripe_customer_id', get_current_user_id() ) );
$cards = $cards->get_response_message();
}
$count_cards = 0;
if ( $cards ) {
$count_cards = count( $cards->data );
}
?>
get_meta( 'pencipw_stripe_payment_id' ) ) {
$subscription = new Stripe_Api( 'create_subscription', $this->get_api_credential(), $order_id, $source, null );
$subscription = $subscription->get_response_message();
if ( ! empty( $subscription->latest_invoice->payment_intent->id ) ) {
$intent = new Stripe_Api( 'update_intent', $this->get_api_credential(), $order_id, null, $subscription->latest_invoice->payment_intent->id );
$intent = $intent->get_response_message();
}
} else {
$subscription = new Stripe_Api( 'update_subscription', $this->get_api_credential(), $order_id, $source, null );
$subscription = $subscription->get_response_message();
$intent = new Stripe_Api( 'update_intent', $this->get_api_credential(), $order_id, $source, $order->get_meta( 'pencipw_stripe_payment_id' ) );
$intent = $intent->get_response_message();
}
} elseif ( pencipw_is_unlock() ) {
// Check if payment has setup
if ( ! $order->get_meta( 'pencipw_stripe_payment_id' ) ) {
$intent = new Stripe_Api( 'create_payment', $this->get_api_credential(), $order_id, $source, null );
$intent = $intent->get_response_message();
} else {
$intent = new Stripe_Api( 'update_payment', $this->get_api_credential(), $order_id, $source, null );
$intent = $intent->get_response_message();
}
} else {
throw new \Exception( esc_html__( 'Invalid payment gateway', 'penci-paywall' ) );
}
if ( ! empty( $intent ) ) {
if ( 'requires_confirmation' === $intent->status ) {
$intent = new Stripe_Api( 'confirm_intent', $this->get_api_credential(), $order_id, $source, $intent->id );
$intent = $intent->get_response_message();
}
if ( 'requires_action' === $intent->status ) {
return [
'result' => 'success',
'redirect' => wc_get_checkout_url() . '#pencipw-stripe-confirm-pi-' . $intent->client_secret . ':' . $this->get_return_url( $order ),
];
}
}
// Check final payment
$charges = new Stripe_Api( 'check_charge', $this->get_api_credential(), $order_id, $source, $intent->charges->data[0]->id );
$charges = $charges->get_response_message();
if ( 'failed' === $charges->status ) {
throw new \Exception( esc_html__( 'Payment failed. Please try again later or use another card', 'penci-paywall' ) );
}
if ( 'pending' === $charges->status ) {
$order->update_status( 'on-hold', sprintf( __( 'Stripe charge awaiting payment: %s.', 'penci-paywall' ), $charges->id ) );
}
if ( 'succeeded' === $charges->status ) {
$order->payment_complete();
// Trigger send email
if ( ! empty( $intent->id ) && ! empty( $intent->receipt_email ) ) {
new Stripe_Api( 'send_email', $this->get_api_credential(), null, null, [
'id' => $intent->id,
'email' => $intent->receipt_email
] );
}
}
// Remove cart.
WC()->cart->empty_cart();
// Return thank you page redirect.
return [
'result' => 'success',
'redirect' => $this->get_return_url( $order ),
];
} catch ( Exception $e ) {
$order->update_status( 'failed' );
/* translators: error message */
throw new Exception( $e->getMessage() );
}
}
/**
* Add payment method
*
* @return array
*/
public function add_payment_method() {
try {
$success = true;
$source = sanitize_text_field( $_POST['stripe_source'] );
if ( $source ) {
$request = new Stripe_Api( 'add_source', $this->get_api_credential(), null, null, $source );
$response = $request->get_response_message();
if ( ! $response ) {
$success = false;
}
} else {
$success = false;
}
if ( $success ) {
return [
'result' => 'success',
'redirect' => wc_get_endpoint_url( 'paywall-method' ),
];
} else {
throw new \Exception( 'failure' );
}
} catch ( Exception $e ) {
return [
'result' => 'failure',
'redirect' => '',
];
}
}
}
payments/autoload.php 0000644 00000001471 14760004044 0010727 0 ustar 00 setup_endpoint();
add_action( 'plugins_loaded', [ $this, 'gateway_handler' ], 99 );
add_action( 'init', [ $this, 'add_endpoint' ], 0 );
add_filter( 'query_vars', [ $this, 'add_query_vars' ], 0 );
add_action( 'parse_request', [ $this, 'handle_api_requests' ], 0 );
// Disable sale price for subscription.
add_filter( 'woocommerce_product_get_price', [ $this, 'disable_sale_price_subscription' ], null, 2 );
add_filter( 'woocommerce_product_get_sale_price', [ $this, 'disable_sale_price_subscription' ], null, 2 );
}
/**
* @return PenciPW_Gateways
*/
public static function instance() {
if ( null === static::$instance ) {
static::$instance = new static();
}
return static::$instance;
}
/**
* API request - Trigger any API requests.
*
* @since 1.0.0
*/
public function handle_api_requests() {
global $wp;
if ( ! empty( $_GET[ $this->endpoint ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$wp->query_vars[ $this->endpoint ] = sanitize_key( wp_unslash( $_GET[ $this->endpoint ] ) ); // phpcs:ignore WordPress.Security.NonceVerification
}
// endpoint requests.
if ( ! empty( $wp->query_vars[ $this->endpoint ] ) ) {
// Buffer, we won't want any output here.
ob_start();
// No cache headers.
wc_nocache_headers();
// Clean the API request.
$api_request = strtolower( wc_clean( $wp->query_vars[ $this->endpoint ] ) );
if ( class_exists( 'WC_Payment_Gateway' ) ) {
WC()->payment_gateways();
}
// Trigger generic action before request hook.
do_action( 'penci_paywall_api_request', $api_request );
// Is there actually something hooked into this API request? If not trigger 400 - Bad request.
status_header( has_action( 'penci_paywall_api_' . $api_request ) ? 200 : 400 );
// Trigger an action which plugins can hook into to fulfill the request.
do_action( 'penci_paywall_api_' . $api_request );
// Done, clear buffer and exit.
ob_end_clean();
die( '-1' );
}
}
/**
* Add new query vars.
*
* @param array $vars query vars.
*
* @return array
*/
public function add_query_vars( $vars ) {
$vars[] = $this->endpoint;
return $vars;
}
/**
* Payment Gateways IPNs
*/
public function add_endpoint() {
add_rewrite_endpoint( $this->endpoint, EP_ALL );
}
/**
* Setup endpoint
*/
private function setup_endpoint() {
$endpoint = 'penci-paywall';
$this->endpoint = apply_filters( 'penci_paywall_ipn_endpooint', $endpoint );
}
/**
* Gateway handler
*/
public function gateway_handler() {
if ( class_exists( 'WC_Payment_Gateway' ) ) {
if ( class_exists( 'WC_Gateway_Paypal' ) ) {
include_once PENCI_PAYWALL_PATH . 'payments/paypal/class-penci-paypal.php';
}
include_once PENCI_PAYWALL_PATH . 'payments/stripe/class-penci-stripe.php';
add_filter( 'woocommerce_available_payment_gateways', [ $this, 'available_gateways' ], 10, 1 );
add_filter( 'woocommerce_payment_gateways', [ $this, 'init_new_gateways' ] );
// Add stripe payment method menu
$stripe = new \PenciPW_Stripe();
if ( $stripe->is_enabled() ) {
add_action( 'init', [ $this, 'paywall_method_new_endpoint' ] );
add_action( 'init', [ $this, 'paywall_method_add_new_endpoint' ] );
add_filter( 'woocommerce_get_query_vars', [ $this, 'query_vars' ], 0 );
add_action( 'wp_loaded', [ $this, 'flush_rewrite_rules' ] );
add_filter( 'woocommerce_account_menu_items', [ $this, 'add_account_endpoint' ] );
add_action( 'woocommerce_account_paywall-method_endpoint', [
$this,
'paywall_method_endpoint_content'
] );
add_action( 'woocommerce_account_add-paywall-method_endpoint', [
$this,
'paywall_method_add_endpoint_content'
] );
}
}
}
/**
* Set available gateways for certain products
*
* @param $gateways
*
* @return mixed
*/
public function available_gateways( $gateways ) {
if ( is_admin() ) {
return $gateways;
}
if ( is_wc_endpoint_url( 'add-paywall-method' ) ) {
$gateways['stripepaywall'] = new \PenciPW_Stripe();
return $gateways;
}
if ( pencipw_is_subscribe() ) {
foreach ( $gateways as $key => $value ) {
if ( $key !== 'paypalsubscribe' && $key !== 'stripepaywall' /** && $key !== 'stripepaywall_sepa'*/ ) {
unset( $gateways[ $key ] );
}
}
} elseif ( pencipw_is_unlock() ) {
foreach ( $gateways as $key => $value ) {
if ( $key === 'paypalsubscribe' || $key === 'stripe' ) {
unset( $gateways[ $key ] );
}
}
} else {
unset( $gateways['paypalsubscribe'] );
unset( $gateways['stripepaywall'] );
}
return $gateways;
}
/**
* Disable sale price for subscription
*
* @param string $value price.
* @param WC_Product $product The WooCommerce product class handles individual product data.
*
* @return mixed
*/
public function disable_sale_price_subscription( $value, $product ) {
if ( 'paywall_subscribe' === $product->get_type() ) {
return $product->get_regular_price();
}
return $value;
}
/**
* Init new gateways to Woocommerce Settings
*
* @param $methods
*
* @return mixed
*/
public function init_new_gateways( $methods ) {
$methods[] = 'PenciPW_Paypal';
$methods[] = 'PenciPW_Stripe';
return $methods;
}
/**
* Add menu to woocommerce account menu
*
* @param $endpoint
*
* @return array
*/
public function add_account_endpoint( $menu ) {
$item = array(
'paywall-method' => esc_html__( 'Paywall Payment Methods', 'penci-paywall' ),
);
$count = count( $menu );
$menu = array_merge( array_slice( $menu, 0, $count - 1 ), $item, array_slice( $menu, $count - 1 ) );
return $menu;
}
public function query_vars( $vars ) {
foreach ( [ 'paywall-method', 'add-paywall-method' ] as $e ) {
$vars[ $e ] = $e;
}
return $vars;
}
public function flush_rewrite_rules() {
flush_rewrite_rules();
}
public function paywall_method_new_endpoint() {
add_rewrite_endpoint( 'paywall-method', EP_ROOT | EP_PAGES );
}
public function paywall_method_add_new_endpoint() {
add_rewrite_endpoint( 'add-paywall-method', EP_ROOT | EP_PAGES );
}
public function paywall_method_endpoint_content() {
include PENCI_PAYWALL_PATH . 'template/payment-method.php';
}
public function paywall_method_add_endpoint_content() {
include PENCI_PAYWALL_PATH . 'template/payment-method-add.php';
}
}
woocommerce/options/subscribe-option.php 0000644 00000002702 14760004044 0014556 0 ustar 00
ID;
$custom_options = array(
'id' => 'multiple_input',
'label' => esc_html__( 'Billing Time', 'penci-paywall' ),
'description' => esc_html__( 'Choose the billing interval, and period', 'penci-paywall' ),
'desc_tip' => true,
'options' => array(
'_pencipw_total' => array(
'label' => '',
'type' => 'wp_select',
'options' => array(
1 => esc_html__( 'every', 'penci-paywall' ),
2 => esc_html__( 'every 2nd', 'penci-paywall' ),
3 => esc_html__( 'every 3rd', 'penci-paywall' ),
4 => esc_html__( 'every 4th', 'penci-paywall' ),
5 => esc_html__( 'every 5th', 'penci-paywall' ),
6 => esc_html__( 'every 6th', 'penci-paywall' ),
),
),
'_pencipw_duration' => array(
'label' => '',
'type' => 'wp_select',
'options' => array(
'day' => esc_html__( 'Days', 'penci-paywall' ),
'week' => esc_html__( 'Weeks', 'penci-paywall' ),
'month' => esc_html__( 'Months', 'penci-paywall' ),
'year' => esc_html__( 'Years', 'penci-paywall' ),
),
),
),
);
pencipw_wc_multiple_option( $custom_options );
?>
woocommerce/options/unlock-option.php 0000644 00000001503 14760004044 0014066 0 ustar 00
ID;
woocommerce_wp_text_input(
array(
'id' => '_penci_total_unlock',
'label' => esc_html__( 'Number of Post Unlock', 'penci-paywall' ),
'description' => esc_html__( 'The number of posts that the user could buy/unlock.', 'penci-paywall' ),
'value' => get_post_meta( $post_id, '_penci_total_unlock', true ) ? get_post_meta( $post_id, '_penci_total_unlock', true ) : 1,
'type' => 'number',
'desc_tip' => true,
'custom_attributes' => array(
'min' => 1,
'step' => 1,
),
)
);
?>
woocommerce/class-wc-product.php 0000644 00000002414 14760004044 0012766 0 ustar 00 id, '_pencipw_total', true );
$interval = get_post_meta( $this->id, '_pencipw_duration', true );
switch ( $interval ) {
case 'day':
$days = $duration;
break;
case 'week':
$days = $duration * 7;
break;
case 'month':
$days = $duration * 30;
break;
case 'year':
$days = $duration * 365;
break;
default:
$days = 0;
break;
}
return $days;
}
public function get_interval() {
$interval = get_post_meta( $this->id, '_pencipw_duration', true );
return strtoupper( $interval );
}
public function get_duration() {
$duration = get_post_meta( $this->id, '_pencipw_total', true );
return $duration;
}
}
woocommerce/class-product.php 0000644 00000021264 14760004044 0012363 0 ustar 00 '',
);
foreach ( $fields as $key => $value ) {
$value = ! empty( $_POST[ $key ] ) ? $_POST[ $key ] : '';
switch ( $value ) {
case 'int':
$value = absint( $value );
break;
default:
$value = sanitize_text_field( $value );
}
if ( '_penci_subscription_paywall' === $key && ! empty( $value ) ) {
update_post_meta( $post_id, '_sold_individually', $value );
update_post_meta( $post_id, '_virtual', $value );
}
update_post_meta( $post_id, $key, $value );
}
}
}
/**
* Extend product subscription options
*/
public function extend_subscriptions_options() {
if ( function_exists( 'wcs_get_subscription' ) ) {
global $post;
$post_id = $post->ID;
woocommerce_wp_checkbox(
array(
'id' => '_penci_subscription_paywall',
'label' => esc_html__( 'Soledad Post Subscribe', 'penci-paywall' ),
'description' => esc_html__( 'Enable this option to use Product Subscription as Soledad Post Subscribe', 'penci-paywall' ),
'value' => get_post_meta( $post_id, '_penci_subscription_paywall', true ),
)
);
?>
'product',
'posts_per_page' => 10,
'tax_query' => array(
array(
'taxonomy' => 'product_type',
'field' => 'slug',
'terms' => apply_filters( 'pencipw_product_list', array(
'paywall_subscribe',
'paywall_unlock'
) ),
),
),
'orderby' => 'menu_order title',
'order' => 'ASC',
'post_status' => 'publish',
)
);
if ( $packages ) {
foreach ( $packages as $value ) {
$result[ $value->post_title ] = $value->ID;
}
}
return $result;
}
/**
* Register New Product Type
*/
public function product_register_term() {
if ( ! get_term_by( 'slug', sanitize_title( 'paywall_subscribe' ), 'product_type' ) ) {
wp_insert_term(
'paywall_subscribe',
'product_type',
array( 'description' => 'Soledad Post Subscribe' )
);
}
if ( ! get_term_by( 'slug', sanitize_title( 'paywall_unlock' ), 'product_type' ) ) {
wp_insert_term(
'paywall_unlock',
'product_type',
array( 'description' => 'Soledad Post Unlock' )
);
}
}
/**
* Add Product Type Selector
*
* @param $types
*
* @return mixed
*/
public function product_type_selector( $types ) {
$types['paywall_subscribe'] = esc_html__( 'Soledad Post Subscribe', 'penci-paywall' );
$types['paywall_unlock'] = esc_html__( 'Soledad Post Unlock', 'penci-paywall' );
return $types;
}
/**
* Add Product Data General Option
*/
public function paywall_product_data() {
include plugin_dir_path( __DIR__ ) . 'woocommerce/options/subscribe-option.php';
include plugin_dir_path( __DIR__ ) . 'woocommerce/options/unlock-option.php';
}
/**
* Hide Woocommerce Product Data Tabs
*
* @param $product_data_tabs
*
* @return array
*/
public function paywall_data_tabs( $product_data_tabs ) {
if ( empty( $product_data_tabs ) ) {
return false;
}
// product data - hide some tabs.
if ( isset( $product_data_tabs['shipping'] ) && isset( $product_data_tabs['shipping']['class'] ) ) {
$product_data_tabs['shipping']['class'][] = 'hide_if_paywall_subscribe hide_if_paywall_unlock';
}
if ( isset( $product_data_tabs['linked_product'] ) && isset( $product_data_tabs['linked_product']['class'] ) ) {
$product_data_tabs['linked_product']['class'][] = 'hide_if_paywall_subscribe hide_if_paywall_unlock';
}
if ( isset( $product_data_tabs['attribute'] ) && isset( $product_data_tabs['attribute']['class'] ) ) {
$product_data_tabs['attribute']['class'][] = 'hide_if_paywall_subscribe hide_if_paywall_unlock';
}
return $product_data_tabs;
}
/**
* Save Product Data
*
* @param $post_id
*/
public function save_product_data( $post_id ) {
$fields = array(
'_pencipw_total' => 'int',
'_pencipw_duration' => '',
'_pencipw_total_unlock' => 'int',
'_penci_total_unlock' => 'init',
'_penci_post_featured' => 'init',
'_penci_total' => '',
'_penci_duration' => '',
);
foreach ( $fields as $key => $value ) {
$value = ! empty( $_POST[ $key ] ) ? $_POST[ $key ] : '';
switch ( $value ) {
case 'int':
$value = absint( $value );
break;
default:
$value = sanitize_text_field( $value );
}
update_post_meta( $post_id, $key, $value );
}
}
}
woocommerce/class-wc-order.php 0000644 00000043506 14760004044 0012430 0 ustar 00 subscribe_status( $subscription );
}
}
/**
* Update user subscription status
*
* @param object $subscription An instance of a WC_Subscription object
*/
public function subscribe_status( $subscription ) {
if ( function_exists( 'wcs_get_subscription' ) ) {
$data = $subscription->get_data();
$user_id = $subscription->get_user_id();
$expired = new \DateTime();
if ( isset( $data['schedule_next_payment'] ) && is_object( $data['schedule_next_payment'] ) ) {
$next_payment_date = $data['schedule_next_payment']->getTimestamp();
$expired->setTimestamp( (int) $next_payment_date );
} elseif ( isset( $data['schedule_end'] ) && is_object( $data['schedule_end'] ) ) {
$next_payment_date = $data['schedule_end']->getTimestamp();
$expired->setTimestamp( (int) $next_payment_date );
}
$expired->setTimezone( new \DateTimeZone( 'UTC' ) );
$expired = $expired->format( 'Y-m-d H:i:s' );
update_user_option( $user_id, 'pencipw_subscribe_id', $data['id'] );
update_user_option( $user_id, 'pencipw_subscribe_status', 'ACTIVE' );
update_user_option( $user_id, 'pencipw_expired_date', $expired );
}
}
/**
* Check if subscription product is set for Penci Paywall
*
* @param mixed $subscription
*
* @return void
*/
public static function should_connect_paywall( $subscription ) {
if ( function_exists( 'wcs_get_subscription' ) ) {
$order_items = $subscription->get_items();
$order_products = array_filter(
array_map(
function ( $item ) {
return $item->get_product();
},
$order_items
),
function ( $product ) {
return ! ! $product;
}
);
if ( count( $order_products ) > 0 ) {
$is_wcs_pencipw = array_reduce(
$order_products,
function ( $virtual_order_so_far, $product ) {
return $virtual_order_so_far && $product->is_virtual() && 'subscription' === $product->get_type() && 'yes' === $product->get_meta( '_pencipw_subscription_paywall' );
},
true
);
if ( $is_wcs_pencipw ) {
return true;
}
}
}
return false;
}
/**
* Fire whenever a subscription's status is changed.
*
* @param object $subscription An instance of a WC_Subscription object
*/
public function on_subscription_status_changed( $subscription ) {
if ( function_exists( 'wcs_get_subscription' ) ) {
$is_cancelled = $subscription->has_status( 'cancelled' );
$is_expired = $subscription->has_status( 'expired' );
if ( $is_cancelled || $is_expired ) {
error_log( 'expire/cancel' );
$user_id = $subscription->get_user_id();
$pencipw_subscribe_id = get_user_option( 'pencipw_expired_date', $user_id );
if ( $subscription->get_id() === $pencipw_subscribe_id ) {
update_user_option( $user_id, 'pencipw_subscribe_id', false );
update_user_option( $user_id, 'pencipw_subscribe_status', false );
update_user_option( $user_id, 'pencipw_expired_date', false );
}
}
}
}
/**
* Triggers when a subscription switch is added to the cart.
*
* @param string $cart_item_key The new cart item's key.
* @param int $product_id The product added to the cart.
*/
public function subscription_added( $cart_item_key, $product_id ) {
if ( function_exists( 'wcs_get_subscription' ) ) {
/**
* @TODO: Detect if already have subscription
*/
foreach ( WC()->cart->get_cart() as $key => $cart_item ) {
$item_data = $cart_item['data'];
if ( 'subscription' === $item_data->get_type() && 'yes' === $item_data->get_meta( '_pencipw_subscription_paywall' ) ) {
if ( $product_id === $cart_item['product_id'] ) {
WC()->cart->set_quantity( $key, 1 );
} else {
WC()->cart->set_quantity( $key, 0 );
}
} else {
$product = wc_get_product( $product_id );
if ( 'subscription' === $product->get_type() && 'yes' === $product->get_meta( '_pencipw_subscription_paywall' ) ) {
WC()->cart->set_quantity( $key, 0 );
}
}
}
}
return $cart_item_key;
}
/**
* Automatically set the order's status to complete.
*
* @param string $new_order_status
* @param int $order_id
* @param WC_Order $order
*
* @return string $new_order_status
*/
public function auto_complete_order_wcs( $status, $order_id, $order ) {
if ( function_exists( 'wcs_get_subscription' ) ) {
$current_status = $order->get_status();
$allowed_current_statuses = array( 'on-hold', 'pending', 'failed' );
if ( 'processing' === $status && in_array( $current_status, $allowed_current_statuses ) ) {
$order_items = $order->get_items();
$order_products = array_filter(
array_map(
function ( $item ) {
return $item->get_product();
},
$order_items
),
function ( $product ) {
return ! ! $product;
}
);
if ( count( $order_products ) > 0 ) {
$is_wcs_pencipw = array_reduce(
$order_products,
function ( $virtual_order_so_far, $product ) {
return $virtual_order_so_far && $product->is_virtual() && 'subscription' === $product->get_type() && 'yes' === $product->get_meta( '_pencipw_subscription_paywall' );
},
true
);
if ( $is_wcs_pencipw ) {
$status = 'completed';
$order->update_status( 'completed' );
}
}
}
}
return $status;
}
/**
* Dismiss paywall notice
*/
public function dismiss_paywall_notice() {
update_option( 'penci_dismiss_paywall_notice', true );
}
/**
* Paywall notice
*/
public function paywall_notice() {
if ( ! class_exists( 'WooCommerce' ) && ! function_exists( 'is_checkout' ) && ! get_option( 'penci_dismiss_paywall_notice', false ) ) {
$this->print_paywall_notice();
}
}
/**
* Print paywall notice
*/
public function print_paywall_notice() {
?>
Penci Paywall
Please install and active WooCommerce plugin. Click the button below to manage your plugin :
Manage plugin
',
'penci-paywall'
),
array(
'strong' => array(),
'span' => array(
'style' => true,
'class' => true,
),
'a' => array(
'href' => true,
'class' => true,
),
)
),
esc_url( admin_url( 'themes.php?page=tgmpa-install-plugins' ) )
);
?>
post_type ) {
return;
}
WC()->cart->add_to_cart( $product_id );
} catch ( Exception $e ) {
return;
}
}
}
}
}
/**
* Check if product already added in cart
*
* @param $cart_item_key
* @param $product_id
*
* @return mixed
*/
public function product_added( $cart_item_key, $product_id ) {
foreach ( WC()->cart->get_cart() as $key => $cart_item ) {
$item_data = $cart_item['data'];
if ( 'paywall_subscribe' === $item_data->get_type() ) {
if ( $product_id === $cart_item['product_id'] ) {
WC()->cart->set_quantity( $key, 1 );
} else {
WC()->cart->set_quantity( $key, 0 );
}
} else {
$product = wc_get_product( $product_id );
if ( $product->get_type() === 'paywall_subscribe' ) {
WC()->cart->set_quantity( $key, 0 );
}
}
}
return $cart_item_key;
}
/**
* Auto Complete Order
*
* Hooked into woocommerce_thankyou hook.
*
* @param $order_id
*/
public function auto_complete_order( $order_id ) {
if ( ! $order_id ) {
return;
}
$order = wc_get_order( $order_id );
if ( $order && 'paypalsubscribe' === $order->get_payment_method() && class_exists( 'WC_Payment_Gateway' ) ) {
remove_action( 'woocommerce_order_details_after_order_table', 'woocommerce_order_again_button' );
$credentials = new PenciPW_Paypal();
$credentials->subscribe_status( $order_id );
}
}
/**
* Product paywall unlock doesn't need processing.
* Make it completed !
*
* @param string $status order status.
* @param int $id unique ID for this object.
* @param \WC_Order $order Order class.
*
* @return string
*/
public function payment_complete_order_status( $status, $id, $order ) {
foreach ( $order->get_items() as $item ) {
if ( $item->is_type( 'line_item' ) ) {
$product = $item->get_product();
/** @var \WC_Product|bool $product */
if ( $product && $product->is_type( 'paywall_unlock' ) ) {
$status = 'completed';
}
}
}
return $status;
}
/**
* Order paid
*
* @param $order_id
* @param $old_status
* @param $new_status
*
* @throws Exception
*/
public function order_paid( $order_id, $old_status, $new_status ) {
$order = wc_get_order( $order_id );
if ( $order ) {
$user_id = $order->get_customer_id() !== null ? $order->get_customer_id() : 0;
$completed = false;
$paywall_user_data = array();
$is_paywall = false;
// paywall_subscribe variables.
$subscribe_status = get_user_option( 'pencipw_subscribe_status', $user_id ) ? get_user_option( 'pencipw_subscribe_status', $user_id ) : false;
$expired = get_user_option( 'pencipw_expired_date', $user_id ) ? get_user_option( 'pencipw_expired_date', $user_id ) : false;
$paypalsubscribe_id = '';
// paywall_unlock variables.
$unlock_remaining = get_user_option( 'pencipw_unlock_remaining', $user_id ) ? get_user_option( 'pencipw_unlock_remaining', $user_id ) : 0;
$unlocked_posts = get_user_option( 'pencipw_unlocked_post_list', $user_id ) ? get_user_option( 'pencipw_unlocked_post_list', $user_id ) : array();
if ( $unlock_remaining < 0 ) {
$unlock_remaining = 0;
}
foreach ( $order->get_items() as $item_id => $item ) {
$product = wc_get_product( $item['product_id'] );
// check if product is paywall_subscribe.
if ( $product->is_type( 'paywall_subscribe' ) && $user_id > 0 ) {
$is_paywall = true;
$paypalsubscribe_id = get_post_meta( $order_id, 'subscription_id', true );
$stripesubscribe_id = get_post_meta( $order_id, 'pencipw_stripe_subs_id', true );
if ( $paypalsubscribe_id ) {
$credentials = new PenciPW_Paypal();
$request = new Paypal_Api( 'check', $credentials->get_api_credential(), $order_id );
$response = $request->get_response_message();
if ( 'completed' === $new_status && 'EMPTY' !== $response && 'ACTIVE' === $response->result->status ) {
$subscribe_status = $response->result->status;// true.
$expired = $response->result->billing_info->next_billing_time;
$expired = new DateTime( $expired );
$expired->setTimezone( new DateTimeZone( 'UTC' ) );
$expired->add( new DateInterval( 'PT1H' ) ); // We need to wait for recurring payment.
$expired = $expired->format( 'Y-m-d H:i:s' );
$completed = true;
} elseif ( 'cancelled' === $new_status || 'refunded' === $new_status || 'failed' === $new_status ) {
if ( get_post_meta( $order_id, 'pencipw_paywall_completed', true ) === 'yes' ) {
$expired = false;
$completed = false;
}
}
}
if ( $stripesubscribe_id ) {
$credentials = new PenciPW_Stripe();
$request = new Stripe_Api( 'check', $credentials->get_api_credential(), $order_id );
$response = $request->get_response_message();
$response = json_decode( json_encode( $response ), false );
if ( 'completed' === $new_status && isset( $response->status ) && 'active' === $response->status ) {
$subscribe_status = 'ACTIVE';
$expired = new DateTime();
$expired = $expired->setTimestamp( $response->current_period_end );
$expired = $expired->setTimezone( new DateTimeZone( 'UTC' ) );
$expired = $expired->format( 'Y-m-d H:i:s' );
$completed = true;
} elseif ( 'cancelled' === $new_status || 'refunded' === $new_status || 'failed' === $new_status ) {
if ( get_post_meta( $order_id, 'pencipw_paywall_completed', true ) === 'yes' ) {
$expired = false;
$completed = false;
}
}
}
}
// check if product is paywall_unlock.
if ( $product->is_type( 'paywall_unlock' ) && $user_id > 0 ) {
$is_paywall = true;
if ( 'completed' === $new_status ) {
$unlock_remaining += $product->get_total_unlock() * $item->get_quantity();
$completed = true;
} elseif ( 'cancelled' === $new_status || 'refunded' === $new_status || 'failed' === $new_status ) {
if ( get_post_meta( $order_id, 'pencipw_paywall_completed', true ) === 'yes' ) {
if ( $unlock_remaining >= $product->get_total_unlock() * $item->get_quantity() ) {
$unlock_remaining -= $product->get_total_unlock() * $item->get_quantity();
} else {
$leftover = $product->get_total_unlock() * $item->get_quantity() - $unlock_remaining;
$unlock_remaining = 0;
// lock post that has been unlocked
for ( $i = 0; $i < $leftover; $i ++ ) {
array_pop( $unlocked_posts );
}
}
$completed = false;
}
}
}
}
if ( $is_paywall ) {
if ( $completed ) {
update_post_meta( $order_id, 'pencipw_paywall_completed', 'yes' );
} else {
update_post_meta( $order_id, 'pencipw_paywall_completed', 'no' );
}
if ( ! empty( $paypalsubscribe_id ) ) {
$paywall_user_data['pencipw_paypal_subs_id'] = $paypalsubscribe_id;
$paywall_user_data['subscribe_status'] = $subscribe_status;
$paywall_user_data['expired_date'] = $expired;
$paywall_user_data['pencipw_subs_type'] = 'paypal';
} elseif ( ! empty( $stripesubscribe_id ) ) {
$paywall_user_data['pencipw_stripe_subs_id'] = $stripesubscribe_id;
$paywall_user_data['subscribe_status'] = $subscribe_status;
$paywall_user_data['expired_date'] = $expired;
$paywall_user_data['pencipw_subs_type'] = 'stripe';
} else {
$paywall_user_data['unlock_remaining'] = $unlock_remaining;
$paywall_user_data['unlocked_posts'] = $unlocked_posts;
}
$this->update_paywall_data( $paywall_user_data, $user_id );
}
}
}
/**
* Update User Data
*
* @param array $paywall
* @param int $user_id
*/
protected function update_paywall_data( $paywall, $user_id ) {
if ( isset( $paywall['pencipw_paypal_subs_id'] ) || isset( $paywall['pencipw_stripe_subs_id'] ) ) { // subscription meta.
update_user_option( $user_id, 'pencipw_subscribe_status', $paywall['subscribe_status'] );
update_user_option( $user_id, 'pencipw_expired_date', $paywall['expired_date'] );
update_user_option( $user_id, 'pencipw_paypal_subs_id', $paywall['pencipw_paypal_subs_id'] );
update_user_option( $user_id, 'pencipw_subs_type', $paywall['pencipw_subs_type'] );
} else { // unlock meta.
update_user_option( $user_id, 'pencipw_unlock_remaining', $paywall['unlock_remaining'] );
update_user_option( $user_id, 'pencipw_unlocked_post_list', $paywall['unlocked_posts'] );
}
}
/**
* Check if user allowed to purchase
*
* @param $product_id
*
* @return bool
*/
protected function allow_purchase( $product_id ) {
// Add codes here if need to restrict user from purchasing.
return true;
}
}
woocommerce/class-wc-product-unclock.php 0000644 00000001446 14760004044 0014426 0 ustar 00 id, '_penci_post_featured', true );
}
/**
* Get total unlock
*
* @return mixed
*/
public function get_total_unlock() {
$total = get_post_meta( $this->id, '_penci_total_unlock', true );
return $total ? $total : 1;
}
}
penci-paywall.php 0000644 00000004362 14760004044 0010026 0 ustar 00 30,
'path' => plugin_dir_path( __FILE__ ) . '/customizer/',
'panel' => array(
'title' => esc_html__( 'Content Paywall', 'soledad' ),
'icon' => 'fas fa-user-lock',
),
'penci_paywall_general_section' => array( 'title' => esc_html__( 'General', 'soledad' ) ),
'penci_paywall_advanced_section' => array( 'title' => esc_html__( 'Advanced Settings', 'soledad' ) ),
'penci_paywall_translations_section' => array( 'title' => esc_html__( 'Texts Translation', 'soledad' ) ),
);
return $options;
}
);
add_action(
'plugins_loaded',
function () {
load_plugin_textdomain( 'penci-paywall', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
}
);
/**
* Initialize Plugin
*/
PenciPaywall\Init::instance();