Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions assets/css/paybutton-admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@
border: none;
}

/* Disabled state for buttons*/
.paybutton-disabled {
opacity: 0.55;
cursor: not-allowed;
}

/* ------------------------------
Button Generator Page Styles
------------------------------ */
Expand Down
2 changes: 1 addition & 1 deletion assets/css/sticky-header.css
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
}

/* Prevent header from overlapping content */
body {
body.pb-has-sticky-header {
padding-top: 80px !important;
}

Expand Down
Binary file added assets/icons/eCash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 changes: 84 additions & 36 deletions assets/js/addressValidator.bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -752,45 +752,93 @@
window.cashaddrExports = cashaddrExports;

document.addEventListener('DOMContentLoaded', () => {
// Find the wallet address input field by its ID.
const addressInput = document.getElementById('paybutton_admin_wallet_address');
if (!addressInput) return;

// Find or create a span for validation feedback.
let resultSpan = document.getElementById('adminAddressValidationResult');
if (!resultSpan) {
resultSpan = document.createElement('span');
resultSpan.id = 'adminAddressValidationResult';
addressInput.parentNode.appendChild(resultSpan);
}

// Select the "Save Changes" button by its name attribute.
const saveButton = document.querySelector('button[name="paybutton_paywall_save_settings"]');

// Listen to input events to auto-validate as the user types.
addressInput.addEventListener('input', () => {
const address = addressInput.value.trim();
if (address === "") {
resultSpan.textContent = '';
resultSpan.style.color = '';
if (saveButton) saveButton.disabled = true;
return;

// Define the targets: Input ID, Button Name (to disable/enable), and Context
const targets = [
{
input: 'paybutton_admin_wallet_address',
btnName: 'paybutton_paywall_save_settings',
context: 'paywall'
},
{
input: 'pbGenTo',
btnName: null, // Generator doesn't have a save button to block
context: 'generator'
},
{
input: 'woocommerce_paybutton_address',
btnName: 'save', // Standard WooCommerce save button name
context: 'woo'
}
];

targets.forEach(target => {
const addressInput = document.getElementById(target.input);
if (!addressInput) return;

// Create a unique span ID for this input
const resultSpanId = target.input + '_validation_result';

const valid = cashaddrExports.isValidCashAddress(address);
if (valid) {
resultSpan.textContent = '✅ Valid address';
resultSpan.style.color = 'green';
if (saveButton) saveButton.disabled = false;
} else {
resultSpan.textContent = '❌ Invalid address';
resultSpan.style.color = 'red';
if (saveButton) saveButton.disabled = true;
// Find or create a span for validation feedback.
let resultSpan = document.getElementById(resultSpanId);

if (!resultSpan) {
resultSpan = document.createElement('span');
resultSpan.id = resultSpanId;

// STYLING UPDATES
resultSpan.style.display = 'block';
resultSpan.style.fontWeight = 'bold';
// Add spacing below the text so it doesn't touch the input
resultSpan.style.marginBottom = '5px';

// PLACEMENT FIX (ABOVE INPUT BOX)
// This inserts the resultSpan immediately BEFORE the addressInput element.
// On the Generator page, this will place it between the Label and the Input.
addressInput.parentNode.insertBefore(resultSpan, addressInput);
}

// Select the "Save Changes" button if applicable
let saveButton = null;
if (target.btnName) {
saveButton = document.querySelector(`button[name="${target.btnName}"]`);
}

const validateAddress = () => {
const address = addressInput.value.trim();

// Reset if empty
if (address === "") {
resultSpan.textContent = '';
// When empty, we hide the margin so it doesn't create a blank gap above the input
resultSpan.style.marginBottom = '0px';
resultSpan.style.color = '';

if (saveButton) saveButton.disabled = true;
return;
}

// Restore margin when text is visible
resultSpan.style.marginBottom = '3px';

const valid = cashaddrExports.isValidCashAddress(address);

if (valid) {
resultSpan.textContent = '✅ Valid address';
resultSpan.style.color = 'green';
if (saveButton) saveButton.disabled = false;
} else {
resultSpan.textContent = '❌ Invalid address';
resultSpan.style.color = 'red';
if (saveButton) saveButton.disabled = true;
}
};

// Listen to input events
addressInput.addEventListener('input', validateAddress);

// Run immediately on load
validateAddress();
});

// Run validation immediately on page load in case the field already has a value.
addressInput.dispatchEvent(new Event('input'));
});

})();
76 changes: 76 additions & 0 deletions assets/js/paybutton-blocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* WooCommerce PayButton Blocks Integration JS
*/
(function( wc, wp ) {
const { registerPaymentMethod } = wc.wcBlocksRegistry;
const { getSetting } = wc.wcSettings;
const { decodeEntities } = wp.htmlEntities;
const { createElement } = wp.element;

const settings = getSetting( 'paybutton_data', {} );

const labelText = decodeEntities( settings.title || 'PayButton' );

// Create a Custom Label Component (Dual Icons)
const LabelIconOnly = () => {
return createElement(
'span',
{
style: {
display: 'flex',
alignItems: 'center',
width: '100%',
}
},
// 1. The PayButton Image
settings.icon ? createElement( 'img', {
src: settings.icon,
alt: labelText,
style: {
maxHeight: '30px',
objectFit: 'contain'
}
} ) : null,

// 2. The Pipeline Separator (Only shows if BOTH icons exist)
(settings.icon && settings.icon2) ? createElement( 'span', {
style: {
margin: '0 10px', // Spacing around the pipe
color: '#ccc', // Light gray color
fontSize: '24px', // Size of the pipe
lineHeight: '1',
fontWeight: '300'
}
}, '|' ) : null,

// 3. The eCash Image
settings.icon2 ? createElement( 'img', {
src: settings.icon2,
alt: 'eCash',
style: {
maxHeight: '24px',
objectFit: 'contain'
}
} ) : null,

// 4. Fallback: If no icons are found, show text
(!settings.icon && !settings.icon2) ? createElement( 'span', null, labelText ) : null
);
};

const Content = () => {
return createElement( 'div', null, decodeEntities( settings.description || '' ) );
};

registerPaymentMethod( {
name: 'paybutton',
label: createElement( LabelIconOnly ),
content: createElement( Content ),
edit: createElement( Content ),
canMakePayment: () => true,
ariaLabel: labelText,
supports: {
features: settings.supports,
},
} );
})( window.wc, window.wp );
38 changes: 0 additions & 38 deletions assets/js/paybutton-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,6 @@
(function($) {
"use strict";

/* ==========================================================================
ADMIN WALLET ADDRESS VALIDATION
==========================================================================
*/
if ($('#pbGenTo').length) {

const $toField = $('#pbGenTo');
let $validationMsg;

if (!$('#pbGenToValidationResult').length) {
$toField.after('<p id="pbGenToValidationResult"></p>');
}
$validationMsg = $('#pbGenToValidationResult');

$toField.on('input', function() {
const address = $toField.val().trim();

if (!address) {
$validationMsg.text('').css('color', '');
return;
}

const valid = window.cashaddrExports && window.cashaddrExports.isValidCashAddress(address);
if (typeof window.cashaddrExports === 'undefined') {
console.error('[PayButton] addressValidator is missing or not loaded!');
}

if (valid) {
$validationMsg.text('✅ Valid address').css('color', 'green');
} else {
$validationMsg.text('❌ Invalid address').css('color', 'red');
}
});

// Trigger input event on page load to validate pre-set value (from Paywall Settings).
$toField.trigger('input');
}

/* ==========================================================================
BUTTON GENERATOR LOGIC
==========================================================================
Expand Down
57 changes: 57 additions & 0 deletions assets/js/paybutton-woo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* WooCommerce PayButton Integration JS
*/
jQuery(document).ready(function($) {
$('.paybutton-woo-container').each(function() {
var $container = $(this);
var configData = $container.data('config');

if (typeof configData === 'string') {
try { configData = JSON.parse(configData); }
catch (e) { return; }
}

let paymentInitiated = false;

function showOverlay(msg) {
const el = document.getElementById('paybutton_overlay');
if (el) {
document.getElementById('paybutton_overlay_text').innerText = msg;
el.style.display = 'block';
}
}

function pollOrderStatus() {
setInterval(function() {
$.ajax({
url: PaywallAjax.ajaxUrl,
method: 'POST',
data: {
action: 'paybutton_check_order_status',
security: PaywallAjax.nonce,
order_id: configData.opReturn
},
success: function(response) {
if (response.success) {
// Success! Reload to hide button and show receipt
location.reload();
}
}
});
}, 3000);
}

PayButton.render($container[0], {
...configData,
onSuccess: function(tx) {
paymentInitiated = true;
pollOrderStatus();
},
onClose: function() {
if (paymentInitiated) {
showOverlay("Verifying Payment...");
}
}
});
});
});
14 changes: 4 additions & 10 deletions includes/class-paybutton-activator.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,11 @@ public static function activate() {
self::create_profile_page();
// Set a flag to redirect the admin to the Paywall Settings page after activation
update_option('paybutton_activation_redirect', true);
self::migrate_old_option();
//self::migrate_old_option();
}

private static function migrate_old_option() {
// --- 1. unlocked‑indicator colours ---
$txt_old = get_option( 'paybutton_unlocked_indicator_text_color', '' );
$txt_new = get_option( 'paybutton_unlocked_indicator_color', '' );
if ( ! empty( $txt_old ) && empty( $txt_new ) ) {
update_option( 'paybutton_unlocked_indicator_color', $txt_old );
delete_option( 'paybutton_unlocked_indicator_text_color' );
}
// Empty function for future use
}

/**
Expand All @@ -55,7 +49,7 @@ public static function create_tables() {
PRIMARY KEY (id),
KEY pb_paywall_user_wallet_address_idx (pb_paywall_user_wallet_address),
KEY post_id_idx (post_id),
KEY tx_hash_idx (tx_hash),
UNIQUE KEY tx_hash_idx (tx_hash),
KEY unlock_token_idx (unlock_token)
) $charset_collate;";

Expand All @@ -75,7 +69,7 @@ public static function create_tables() {
used TINYINT(1) NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY tx_hash_idx (tx_hash),
UNIQUE KEY tx_hash_idx (tx_hash),
KEY wallet_addr_idx (wallet_address(190)),
KEY used_idx (used),
KEY login_token_idx (login_token)
Expand Down
Loading