Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Autoresponder to Stripe #1675

Merged
merged 15 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions inc/plugins/class-stripe-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,22 @@ function( $item ) use ( $product ) {

return $bool;
}

/**
* Get session email.
*
* @param string $session_id Stripe Session ID.
*
* @return bool|string
* @access public
*/
public function get_session_email( $session_id ) {
$session = $this->create_request( 'get_session', $session_id );

if ( empty( $session['customer_details']['email'] ) ) {
return false;
}

return $session['customer_details']['email'];
}
}
4 changes: 4 additions & 0 deletions inc/render/class-stripe-checkout-block.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public function render( $attributes ) {
if ( false !== $status ) {
if ( 'success' === $status ) {
$message = isset( $attributes['successMessage'] ) ? wp_kses_post( $attributes['successMessage'] ) : __( 'Your payment was successful. If you have any questions, please email [email protected].', 'otter-blocks' );

if ( has_action( 'otter_blocks_stripe_checkout_success' ) ) {
Soare-Robert-Daniel marked this conversation as resolved.
Show resolved Hide resolved
do_action( 'otter_blocks_stripe_checkout_success', $attributes, $stripe, $session_id );
}
} else {
$message = isset( $attributes['cancelMessage'] ) ? wp_kses_post( $attributes['cancelMessage'] ) : __( 'Your payment was unsuccessful. If you have any questions, please email [email protected].', 'otter-blocks' );
}
Expand Down
1 change: 1 addition & 0 deletions plugins/otter-pro/inc/class-main.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public function autoload_classes( $classnames ) {
'\ThemeIsle\OtterPro\Plugins\Posts_ACF_Integration',
'\ThemeIsle\OtterPro\Plugins\Review_Woo_Integration',
'\ThemeIsle\OtterPro\Plugins\WooCommerce_Builder',
'\ThemeIsle\OtterPro\Plugins\Stripe_Pro_Features',
'\ThemeIsle\OtterPro\Server\Dashboard_Server',
'\ThemeIsle\OtterPro\Server\Filter_Blocks_Server',
'\ThemeIsle\OtterPro\Server\Live_Search_Server',
Expand Down
116 changes: 116 additions & 0 deletions plugins/otter-pro/inc/plugins/class-stripe-pro-features.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php
/**
* Stripe Pro Features.
*
* @package ThemeIsle\OtterPro\Plugins
*/

namespace ThemeIsle\OtterPro\Plugins;

/**
* Class Live_Search
*/
class Stripe_Pro_Features {
/**
* The main instance var.
*
* @var Live_Search
*/
public static $instance = null;

/**
* Initialize the class
*/
public function init() {
if ( License::has_active_license() ) {
add_action( 'otter_blocks_stripe_checkout_success', array( $this, 'autoresponder' ), 10, 3 );
}
}

/**
* Autoresponder.
*
* @param mixed $attributes Block attributes.
* @param \ThemeIsle\GutenbergBlocks\Plugins\Stripe_API $stripe Stripe API object.
* @param string $session_id Session ID.
*/
public function autoresponder( $attributes, $stripe, $session_id ) {

if ( ! isset( $attributes['autoresponder'] ) ) {
return;
}

if ( empty( $session_id ) || empty( $stripe ) ) {
return;
}

$transient_key = 'otter_stripe_checkout_' . $session_id;

$transient = get_transient( $transient_key );

if ( false !== $transient ) {
return;
}
$email = $stripe->get_session_email( $session_id );

if ( ! $email ) {
return;
}

$to = $email;
$headers[] = 'Content-Type: text/html';
$headers[] = 'From: ' . get_bloginfo( 'name', 'display' );
$subject = isset( $attributes['autoresponder']['subject'] ) ? $attributes['autoresponder']['subject'] : __( 'Thank you for your purchase', 'otter-blocks' );
$body = isset( $attributes['autoresponder']['body'] ) ? $attributes['autoresponder']['body'] : __( 'Thank you for choosing our online store for your recent purchase. We greatly appreciate your business and trust in our products.', 'otter-blocks' );

// phpcs:ignore
Soare-Robert-Daniel marked this conversation as resolved.
Show resolved Hide resolved
if ( wp_mail( $to, $subject, $body, $headers ) ) {
set_transient( $transient_key, true, 60 * 24 * 7 );
Soare-Robert-Daniel marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* The instance method for the static class.
* Defines and returns the instance of the static class.
*
* @static
* @since 1.7.1
* @access public
* @return Live_Search
*/
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self();
self::$instance->init();
}

return self::$instance;
}

/**
* Throw error on object clone
*
* The whole idea of the singleton design pattern is that there is a single
* object therefore, we don't want the object to be cloned.
*
* @access public
* @since 1.7.1
* @return void
*/
public function __clone() {
// Cloning instances of the class is forbidden.
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'otter-blocks' ), '1.0.0' );
}

/**
* Disable unserializing of the class
*
* @access public
* @since 1.7.1
* @return void
*/
public function __wakeup() {
// Unserializing instances of the class is forbidden.
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'otter-blocks' ), '1.0.0' );
}
}
5 changes: 4 additions & 1 deletion src/blocks/blocks/stripe-checkout/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
},
"cancelMessage": {
"type": "string"
},
"autoresponder": {
"type": "object"
}
},
"supports": {
"html": false
},
"editorStyle": "otter-stripe-checkout-editor",
"style": "otter-stripe-checkout-style"
}
}
76 changes: 73 additions & 3 deletions src/blocks/blocks/stripe-checkout/inspector.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,77 @@ import {
SelectControl,
Spinner,
TextControl,
TextareaControl
TextareaControl,
ExternalLink
} from '@wordpress/components';

/**
* Internal dependencies
*/
import { ButtonToggleControl, RichTextEditor } from '../../components/index.js';
import { useState } from '@wordpress/element';
import { ButtonToggleControl, Notice as OtterNotice, Notice, RichTextEditor } from '../../components/index.js';
import { Fragment, useContext, useState } from '@wordpress/element';
Soare-Robert-Daniel marked this conversation as resolved.
Show resolved Hide resolved
import { applyFilters } from '@wordpress/hooks';
import { FormContext } from '../form/edit';
import { setUtm } from '../../helpers/helper-functions';

const ProFeatures = () => {
return (
<Fragment>

<PanelBody
title={ __( 'Autoresponder (Pro)', 'otter-blocks' ) }
Soare-Robert-Daniel marked this conversation as resolved.
Show resolved Hide resolved
>
<TextControl
label={__( 'Autoresponder Subject', 'otter-blocks' )}
placeholder={__(
'Thank you for your purchase',
'otter-blocks'
)}
value={ undefined }
onChange={ () => {}}
help={__(
'Enter the subject of the autoresponder email.',
'otter-blocks'
)}
className="o-disabled"
/>

<TextareaControl
label={ __( 'Autoresponder Body', 'otter-blocks' ) }
placeholder={ __( 'Thank you for choosing our online store for your recent purchase. We greatly appreciate your business and trust in our products.', 'otter-blocks' )}
Soare-Robert-Daniel marked this conversation as resolved.
Show resolved Hide resolved
rows={2}
value={ undefined }
onChange={ () => {} }
help={ __( 'Enter the body of the autoresponder email.', 'otter-blocks' ) }
disabled
className="o-disabled"
/>

{
( ! Boolean( window?.otterPro?.isActive ) && Boolean( window?.themeisleGutenberg?.hasPro ) ) && (
<OtterNotice
notice={ __( 'You need to activate Otter Pro.', 'otter-blocks' ) }
instructions={ __( 'You need to activate your Otter Pro license to use Pro features of Stripe Checkout.', 'otter-blocks' ) }
/>
)
}

{
( ! Boolean( window?.themeisleGutenberg?.hasPro ) ) && (
<div>
<Notice
notice={ <ExternalLink href={ setUtm( window.themeisleGutenberg.upgradeLink, 'form-block' ) }>{ __( 'Unlock this with Otter Pro.', 'otter-blocks' ) }</ExternalLink> }
variant="upsell"
/>
<p className="description">{ __( 'Automatically send follow-up emails to your users with the Autoresponder feature.', 'otter-blocks' ) }</p>
</div>
)
}
</PanelBody>

</Fragment>
Soare-Robert-Daniel marked this conversation as resolved.
Show resolved Hide resolved
);
};

const Inspector = ({
attributes,
Expand Down Expand Up @@ -160,6 +223,13 @@ const Inspector = ({
{ __( 'Save API Key', 'otter-blocks' ) }
</Button>
</PanelBody>

{ applyFilters(
'otter.stripe-checkout.inspector',
<ProFeatures />,
attributes,
setAttributes
) }
</InspectorControls>
);
};
Expand Down
4 changes: 4 additions & 0 deletions src/blocks/blocks/stripe-checkout/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ type Attributes = {
price: string
successMessage: string
cancelMessage: string
autoresponder: {
subject: string
body: string
}
}

export type StripeCheckoutProps = BlockProps<Attributes>
Expand Down
36 changes: 36 additions & 0 deletions src/pro/components/autoresponder/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useState } from '@wordpress/element';
import { Button, Modal } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { RichTextEditor } from '../../../blocks/components';

const AutoresponderBodyModal = ({ value, onChange }) => {
const [ isOpen, setOpen ] = useState( false );

return (
<>
{ isOpen && (
<Modal
title={ __( 'Autoresponder Body' ) }
onRequestClose={() => setOpen( false )}
shouldCloseOnClickOutside={ false }
>
<RichTextEditor
value={ value }
onChange={ onChange }
help={ __( 'Enter the body of the autoresponder email.', 'otter-blocks' ) }
allowRawHTML
/>
</Modal>
) }
<br/>
<Button
variant="secondary"
onClick={() => setOpen( true )}
>
{ __( 'Add Autoresponder Body', 'otter-blocks' ) }
</Button>
</>
);
};

export default AutoresponderBodyModal;
28 changes: 2 additions & 26 deletions src/pro/plugins/form/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,40 +21,16 @@ import { Notice as OtterNotice } from '../../../blocks/components';
import { RichTextEditor } from '../../../blocks/components';
import { FieldInputWidth, HideFieldLabelToggle } from '../../../blocks/blocks/form/common';
import { setSavedState } from '../../../blocks/helpers/helper-functions';
import AutoreponderBodyModal from '../../components/autoresponder/index.js';

// +-------------- Autoresponder --------------+

const AutoresponderBody = ({ formOptions, setFormOption }) => {
const [ isOpen, setOpen ] = useState( false );
const onChange = body => {
setFormOption({ autoresponder: { ...formOptions.autoresponder, body }});
};

return (
<>
{ isOpen && (
<Modal
title={ __( 'Autoresponder Body' ) }
onRequestClose={() => setOpen( false )}
shouldCloseOnClickOutside={ false }
>
<RichTextEditor
value={ formOptions.autoresponder?.body }
onChange={ onChange }
help={ __( 'Enter the body of the autoresponder email.', 'otter-blocks' ) }
allowRawHTML
/>
</Modal>
) }
<br/>
<Button
variant="secondary"
onClick={() => setOpen( true )}
>
{ __( 'Add Autoresponder Body', 'otter-blocks' ) }
</Button>
</>
);
return <AutoresponderBodyModal value={formOptions.autoresponder?.body} onChange={onChange} />;
};

const helpMessages = {
Expand Down
1 change: 1 addition & 0 deletions src/pro/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ import './wc-integration/index.js';
import './countdown/index';
import './live-search/index.js';
import './form/index.js';
import './stripe-checkout/index.js';
Loading