-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Click To Buy functionality (#135)
* Add CTB functionality * Always load localized script variables * Fix PHPCS issues * Add notifications container to prevent duplicates
- Loading branch information
Showing
11 changed files
with
404 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
<?php | ||
|
||
namespace Bluehost\CTB; | ||
|
||
use Bluehost\SiteMeta; | ||
use Endurance\WP\Module\Data\HubConnection; | ||
use WP_Error; | ||
|
||
/** | ||
* Class CTBApi | ||
* | ||
* @package Bluehost\CTB | ||
*/ | ||
class CTBApi { | ||
|
||
/** | ||
* Register notification routes. | ||
*/ | ||
public static function registerRoutes() { | ||
|
||
// Add route for fetching a CTB | ||
register_rest_route( | ||
'bluehost/v1', | ||
'/ctb/(?P<id>[a-zA-Z0-9-]+)', | ||
array( | ||
'methods' => \WP_REST_Server::READABLE, | ||
'permission_callback' => function () { | ||
return current_user_can( 'manage_options' ); | ||
}, | ||
'callback' => function ( \WP_REST_Request $request ) { | ||
|
||
$response = wp_remote_get( | ||
BH_HUB_URL . '/sites/v1/ctb/' . $request->get_param( 'id' ) . '', | ||
array( | ||
'headers' => array( | ||
'Content-Type' => 'application/json', | ||
'Accept' => 'application/json', | ||
'Authorization' => 'Bearer ' . HubConnection::get_auth_token(), | ||
), | ||
'timeout' => 20, | ||
) | ||
); | ||
|
||
if ( $response instanceof WP_Error ) { | ||
return $response; | ||
} | ||
|
||
return new \WP_REST_Response( json_decode( wp_remote_retrieve_body( $response ) ), wp_remote_retrieve_response_code( $response ) ); | ||
}, | ||
) | ||
); | ||
|
||
// Add route for purchasing a CTB | ||
register_rest_route( | ||
'bluehost/v1', | ||
'/ctb/(?P<id>[a-zA-Z0-9-]+)', | ||
array( | ||
'methods' => \WP_REST_Server::CREATABLE, | ||
'permission_callback' => function () { | ||
return current_user_can( 'manage_options' ); | ||
}, | ||
'callback' => function ( \WP_REST_Request $request ) { | ||
|
||
$ctb_id = $request->get_param( 'id' ); | ||
$payload = array( | ||
'ctb_id' => $ctb_id, | ||
'site_id' => SiteMeta::get_id(), | ||
); | ||
|
||
$response = wp_remote_post( | ||
BH_HUB_URL . '/sites/v1/ctb/' . $ctb_id . '/purchase', | ||
array( | ||
'headers' => array( | ||
'Content-Type' => 'application/json', | ||
'Accept' => 'application/json', | ||
'Authorization' => 'Bearer ' . HubConnection::get_auth_token(), | ||
), | ||
'body' => wp_json_encode( $payload ), | ||
'timeout' => 20, | ||
) | ||
); | ||
|
||
if ( $response instanceof WP_Error ) { | ||
return $response; | ||
} | ||
|
||
return new \WP_REST_Response( json_decode( wp_remote_retrieve_body( $response ) ), wp_remote_retrieve_response_code( $response ) ); | ||
}, | ||
) | ||
); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
namespace Bluehost\CTB; | ||
|
||
add_action( 'rest_api_init', array( CTBApi::class, 'registerRoutes' ) ); | ||
add_action( | ||
'admin_enqueue_scripts', | ||
function() { | ||
wp_register_script( 'a11y-dialog', plugins_url( 'inc/CTB/js/a11y-dialog.min.js', BLUEHOST_PLUGIN_FILE ), array(), '7.4.0', false ); | ||
wp_enqueue_script( | ||
'bh-ctb', | ||
plugins_url( 'inc/CTB/js/ctb.js', BLUEHOST_PLUGIN_FILE ), | ||
array( 'a11y-dialog' ), | ||
BLUEHOST_PLUGIN_VERSION, | ||
true | ||
); | ||
} | ||
); | ||
|
||
add_action( | ||
'admin_enqueue_scripts', | ||
function() { | ||
wp_enqueue_style( | ||
'bh-ctb', | ||
plugins_url( 'inc/CTB/ctb.css', BLUEHOST_PLUGIN_FILE ), | ||
array(), | ||
BLUEHOST_PLUGIN_VERSION | ||
); | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
body.noscroll { | ||
overflow-y: hidden; | ||
} | ||
|
||
#ctb-modal-container { | ||
position: absolute; | ||
} | ||
|
||
#ctb-modal-container, | ||
.ctb-modal-overlay { | ||
position: fixed; | ||
top: 0; | ||
right: 0; | ||
bottom: 0; | ||
left: 0; | ||
} | ||
|
||
#ctb-modal-container { | ||
z-index: 100000; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
|
||
#ctb-modal-container[aria-hidden='true'] { | ||
display: none; | ||
} | ||
|
||
.ctb-modal-overlay { | ||
background-color: rgba(43, 46, 56, 0.9); | ||
} | ||
|
||
.ctb-modal-content { | ||
margin: auto; | ||
z-index: 2; | ||
position: relative; | ||
background-color: white; | ||
} | ||
|
||
.ctb-modal img { | ||
max-width:100%; | ||
} | ||
|
||
|
||
.ctb-modal button { | ||
cursor:pointer; | ||
} | ||
|
||
.ctb-modal-content { | ||
/* z-index: 20001; */ | ||
min-width: 500px; | ||
max-width: 75%; | ||
min-height: 250px; | ||
background: white; | ||
color: black; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
|
||
.ctb-loader { | ||
width: 5rem; | ||
height: 5rem; | ||
border-radius: 50%; | ||
background: #3575d3; | ||
background: linear-gradient(to right, #3575d3 5%, rgba(0, 0, 0, 0) 32%); | ||
position: relative; | ||
will-change: transform; | ||
-webkit-animation: ctbloader .9s infinite linear; | ||
animation: ctbloader .9s infinite linear; | ||
transform: translateZ(0); | ||
} | ||
|
||
.ctb-loader:before { | ||
width: 50%; | ||
height: 50%; | ||
background: #3575d3; | ||
border-radius: 100% 0 0 0; | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
content: ""; | ||
} | ||
|
||
.ctb-loader:after { | ||
background: #fff; | ||
width: 88%; | ||
height: 88%; | ||
border-radius: 50%; | ||
content: ""; | ||
margin: auto; | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
bottom: 0; | ||
right: 0; | ||
} | ||
|
||
@keyframes ctbloader { | ||
0% {transform: rotate(0deg);} | ||
100% {transform: rotate(360deg);} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
{ | ||
const purchase = (e) => { | ||
let modalWindow = e.target.closest('.ctb-modal-content'); | ||
e.target.closest('.ctb-actions').innerHTML = '<div class="ctb-loader"></div>'; | ||
window.fetch( | ||
`${ window.nfdNotifications.restApiUrl }bluehost/v1/ctb/${ e.target.getAttribute('data-ctb-id') }`, | ||
{ | ||
credentials: 'same-origin', | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'X-WP-Nonce': window.nfdNotifications.restApiNonce, | ||
}, | ||
} | ||
) | ||
.then( response => { | ||
purchaseStatus = (response.status === 200); | ||
return response.json(); | ||
}).then( data => { | ||
if (data.content) { | ||
modalWindow.innerHTML = data.content; | ||
} else { | ||
displayError(modalWindow, "purchase"); | ||
} | ||
}); | ||
} | ||
|
||
const loadCtb = (e) => { | ||
let modal = openModal(e); | ||
let modalWindow = modal.querySelector('.ctb-modal-content') | ||
window.fetch( | ||
`${ window.nfdNotifications.restApiUrl }bluehost/v1/ctb/${ e.target.getAttribute('data-ctb-id') }`, | ||
{ | ||
credentials: 'same-origin', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'X-WP-Nonce': window.nfdNotifications.restApiNonce, | ||
}, | ||
} | ||
) | ||
.then( response => { | ||
return response.json(); | ||
}).then( data => { | ||
if (data.content) { | ||
modalWindow.innerHTML = data.content; | ||
} else { | ||
displayError(modalWindow, 'load'); | ||
} | ||
}); | ||
} | ||
|
||
const openModal = (e) => { | ||
let el = document.createElement('div'); | ||
el.setAttribute('id', 'ctb-modal-container'); | ||
el.innerHTML = ` | ||
<div class="ctb-modal"> | ||
<div class="ctb-modal-overlay" data-a11y-dialog-destroy></div> | ||
<div role="document" class="ctb-modal-content"> | ||
<div class="ctb-loader"></div> | ||
</div> | ||
</div> | ||
`; | ||
e.target.insertAdjacentElement('afterend', el); | ||
|
||
ctbmodal = new A11yDialog(el); | ||
ctbmodal.show(); | ||
|
||
purchaseStatus = false; | ||
|
||
document.querySelector('body').classList.toggle('noscroll'); | ||
|
||
el.addEventListener('click', function(event) { | ||
if (event.target.dataset.action === 'purchase-ctb') { | ||
purchase(event); | ||
} | ||
if (event.target.hasAttribute('data-a11y-dialog-destroy')) { | ||
document.querySelector('body').classList.toggle('noscroll'); | ||
closeModal(event.target); | ||
} | ||
}); | ||
|
||
return el; | ||
} | ||
|
||
const closeModal = (e) => { | ||
ctbmodal.destroy(); | ||
if (purchaseStatus){ | ||
dismissNotice(e); | ||
} | ||
} | ||
|
||
const displayError = (modalWindow, error) => { | ||
let message = (error === 'purchase') ? 'complete the transaction' : 'load the product information'; | ||
modalWindow.innerHTML = `<div style="text-align:center;"> | ||
<p>Sorry, we are unable to ${message} at this time.</p> | ||
<button class="components-button bluehost is-primary" data-a11y-dialog-destroy>Cancel</button> | ||
</div>`; | ||
} | ||
|
||
const dismissNotice = (e) => { | ||
const notice = e.closest('.bluehost-notice'); | ||
if (notice) { | ||
const id = notice.getAttribute('data-id'); | ||
notice.parentNode.removeChild(notice); | ||
window.fetch( | ||
`${ window.nfdNotifications.restApiUrl }bluehost/v1/notifications/${ id }`, | ||
{ | ||
credentials: 'same-origin', | ||
method: 'DELETE', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'X-WP-Nonce': window.nfdNotifications.restApiNonce, | ||
}, | ||
} | ||
); | ||
} | ||
} | ||
|
||
window.addEventListener( | ||
'load', | ||
() => { | ||
document.getElementById('wpbody').addEventListener('click', function(event) { | ||
if (event.target.dataset.action === 'load-nfd-ctb') { | ||
loadCtb(event); | ||
} | ||
}); | ||
} | ||
); | ||
} |
Oops, something went wrong.