First Commit

This commit is contained in:
2025-08-28 19:35:28 -07:00
commit 264e65006a
488 changed files with 155661 additions and 0 deletions

411
assets/js/admin.js Normal file
View File

@@ -0,0 +1,411 @@
jQuery(document).ready(function($) {
'use strict';
/**
* Main WPDD Admin Object
*/
window.WPDD_Admin = {
init: function() {
this.initFileManager();
this.initPriceToggle();
this.initFormValidation();
},
initFileManager: function() {
var fileIndex = $('#wpdd-files-list .wpdd-file-item').length;
// Add new file
$('#wpdd-add-file').on('click', function(e) {
e.preventDefault();
var template = $('#wpdd-file-template').html();
template = template.replace(/INDEX/g, fileIndex);
var $newFile = $(template);
$newFile.attr('data-index', fileIndex);
$('#wpdd-files-list').append($newFile);
fileIndex++;
WPDD_Admin.updateFileIndices();
});
// Remove file
$(document).on('click', '.wpdd-remove-file', function(e) {
e.preventDefault();
if (confirm('Are you sure you want to remove this file?')) {
$(this).closest('.wpdd-file-item').remove();
WPDD_Admin.updateFileIndices();
}
});
// Upload file
$(document).on('click', '.wpdd-upload-file', function(e) {
e.preventDefault();
var $button = $(this);
var $container = $button.closest('.wpdd-file-item');
var $urlInput = $container.find('.wpdd-file-url-input');
var $idInput = $container.find('.wpdd-file-id');
var $nameInput = $container.find('input[name*="[name]"]');
// Create file input element
var $fileInput = $('<input type="file" style="display:none;" />');
$fileInput.on('change', function(event) {
var file = event.target.files[0];
if (!file) return;
// Show loading state
$button.prop('disabled', true).text('Uploading...');
var formData = new FormData();
formData.append('action', 'wpdd_upload_protected_file');
formData.append('file', file);
formData.append('nonce', wpdd_admin_nonce);
$.ajax({
url: ajaxurl,
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.success) {
$urlInput.val(response.data.protected_url);
$idInput.val(response.data.file_id);
if (!$nameInput.val()) {
$nameInput.val(file.name);
}
WPDD_Admin.showAdminNotice('File uploaded to protected directory', 'success');
} else {
WPDD_Admin.showAdminNotice(response.data || 'Upload failed', 'error');
}
$button.prop('disabled', false).text('Upload File');
},
error: function() {
WPDD_Admin.showAdminNotice('Upload failed', 'error');
$button.prop('disabled', false).text('Upload File');
}
});
// Clean up
$fileInput.remove();
});
// Trigger file selection
$('body').append($fileInput);
$fileInput.trigger('click');
});
// Make files sortable
if ($.fn.sortable) {
$('#wpdd-files-list').sortable({
handle: '.wpdd-file-handle',
placeholder: 'wpdd-file-placeholder',
update: function() {
WPDD_Admin.updateFileIndices();
}
});
}
},
moveToProtectedDirectory: function(attachmentId, $container) {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'wpdd_move_to_protected',
attachment_id: attachmentId,
nonce: wpdd_admin_nonce
},
success: function(response) {
if (response.success && response.data.protected_url) {
$container.find('.wpdd-file-url-input').val(response.data.protected_url);
}
}
});
},
updateFileIndices: function() {
$('#wpdd-files-list .wpdd-file-item').each(function(index) {
var $item = $(this);
$item.attr('data-index', index);
// Update input names
$item.find('input').each(function() {
var name = $(this).attr('name');
if (name) {
name = name.replace(/\[\d+\]/, '[' + index + ']');
$(this).attr('name', name);
}
});
});
},
initPriceToggle: function() {
$('#wpdd_is_free').on('change', function() {
var $priceFields = $('.wpdd-price-field');
if ($(this).is(':checked')) {
$priceFields.slideUp();
} else {
$priceFields.slideDown();
}
}).trigger('change');
},
initFormValidation: function() {
// Validate PayPal settings
$('input[name="wpdd_paypal_client_id"], input[name="wpdd_paypal_secret"]').on('blur', function() {
var $field = $(this);
var value = $field.val().trim();
if (value && value.length < 10) {
$field.addClass('error');
WPDD_Admin.showAdminNotice('Invalid PayPal credential format', 'error');
} else {
$field.removeClass('error');
}
});
// Validate email fields
$('input[type="email"]').on('blur', function() {
var $field = $(this);
var value = $field.val().trim();
var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (value && !emailRegex.test(value)) {
$field.addClass('error');
} else {
$field.removeClass('error');
}
});
// Validate number fields
$('input[type="number"]').on('input', function() {
var $field = $(this);
var value = parseFloat($field.val());
var min = parseFloat($field.attr('min'));
var max = parseFloat($field.attr('max'));
if (isNaN(value) || (min !== undefined && value < min) || (max !== undefined && value > max)) {
$field.addClass('error');
} else {
$field.removeClass('error');
}
});
},
showAdminNotice: function(message, type) {
type = type || 'info';
var notice = $('<div class="notice notice-' + type + ' is-dismissible">' +
'<p>' + message + '</p>' +
'<button type="button" class="notice-dismiss"></button>' +
'</div>');
$('.wrap h1').first().after(notice);
// Handle dismiss
notice.find('.notice-dismiss').on('click', function() {
notice.fadeOut(function() {
notice.remove();
});
});
// Auto-dismiss after 5 seconds for non-error notices
if (type !== 'error') {
setTimeout(function() {
notice.fadeOut(function() {
notice.remove();
});
}, 5000);
}
},
initReportsCharts: function() {
// Placeholder for future chart implementation
// Could integrate Chart.js or similar library
},
initBulkActions: function() {
// Handle bulk actions for orders, customers, etc.
$('.bulkactions select').on('change', function() {
var action = $(this).val();
var $button = $(this).siblings('input[type="submit"]');
if (action) {
$button.prop('disabled', false);
} else {
$button.prop('disabled', true);
}
});
},
initQuickEdit: function() {
// Quick edit functionality for products
$('.editinline').on('click', function() {
var $row = $(this).closest('tr');
var productId = $row.find('.check-column input').val();
// Populate quick edit fields with current values
setTimeout(function() {
var $quickEdit = $('.inline-edit-row');
// Pre-fill price from the displayed value
var price = $row.find('.column-wpdd_price').text().replace('$', '');
if (price !== 'Free') {
$quickEdit.find('input[name="_wpdd_price"]').val(price);
}
}, 100);
});
},
initFilePreview: function() {
// Show file preview/details when hovering over file names
$(document).on('mouseenter', '.wpdd-file-url-input', function() {
var url = $(this).val();
if (url) {
var filename = url.split('/').pop();
var extension = filename.split('.').pop().toLowerCase();
var fileType = WPDD_Admin.getFileType(extension);
$(this).attr('title', 'File: ' + filename + ' (Type: ' + fileType + ')');
}
});
},
getFileType: function(extension) {
var types = {
'pdf': 'PDF Document',
'doc': 'Word Document',
'docx': 'Word Document',
'zip': 'Archive',
'rar': 'Archive',
'jpg': 'Image',
'jpeg': 'Image',
'png': 'Image',
'gif': 'Image',
'mp3': 'Audio',
'wav': 'Audio',
'mp4': 'Video',
'avi': 'Video'
};
return types[extension] || 'File';
},
initColorPicker: function() {
// Initialize color picker for watermark settings
if ($.fn.wpColorPicker) {
$('.wpdd-color-picker').wpColorPicker();
}
},
initTabs: function() {
// Settings page tabs
$('.wpdd-settings-tabs').on('click', 'a', function(e) {
e.preventDefault();
var $tab = $(this);
var target = $tab.attr('href');
// Update active tab
$tab.siblings().removeClass('nav-tab-active');
$tab.addClass('nav-tab-active');
// Show/hide content
$('.wpdd-settings-content').hide();
$(target).show();
});
}
};
// Initialize admin functionality
WPDD_Admin.init();
// Add admin-specific styles
$('<style>')
.prop('type', 'text/css')
.html(`
.wpdd-file-item.ui-sortable-helper {
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
transform: rotate(2deg);
}
.wpdd-file-placeholder {
border: 2px dashed #0073aa !important;
background: transparent !important;
height: 80px !important;
}
input.error {
border-color: #dc3232 !important;
box-shadow: 0 0 2px rgba(220, 50, 50, 0.3) !important;
}
.wpdd-loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255,255,255,0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
}
.wpdd-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #0073aa;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.wpdd-help-tip {
color: #666;
cursor: help;
margin-left: 5px;
}
.wpdd-help-tip:hover {
color: #0073aa;
}
`)
.appendTo('head');
// Initialize additional features based on current page
var currentScreen = window.pagenow || '';
if (currentScreen === 'wpdd_product') {
WPDD_Admin.initQuickEdit();
WPDD_Admin.initFilePreview();
}
if (currentScreen.includes('wpdd-settings')) {
WPDD_Admin.initColorPicker();
WPDD_Admin.initTabs();
}
if (currentScreen.includes('wpdd-reports')) {
WPDD_Admin.initReportsCharts();
}
// Global admin features
WPDD_Admin.initBulkActions();
});

554
assets/js/frontend.js Normal file
View File

@@ -0,0 +1,554 @@
jQuery(document).ready(function($) {
'use strict';
/**
* Main WPDD Frontend Object
*/
window.WPDD = {
init: function() {
this.bindEvents();
this.initProductCards();
this.initCheckout();
},
bindEvents: function() {
// Add to cart buttons
$(document).on('click', '.wpdd-add-to-cart', this.addToCart);
// Free download buttons
$(document).on('click', '.wpdd-free-download', this.processFreeDownload);
// Product quickview
$(document).on('click', '.wpdd-quickview', this.showQuickview);
// Filter form submission
$(document).on('submit', '.wpdd-filter-form', this.handleFilters);
// Download status check
$(document).on('click', '.wpdd-check-download', this.checkDownloadStatus);
},
initProductCards: function() {
// Add hover effects and animations
$('.wpdd-product-card').each(function() {
var $card = $(this);
var $image = $card.find('.wpdd-product-image img');
$card.hover(
function() {
$(this).addClass('hovered');
},
function() {
$(this).removeClass('hovered');
}
);
});
},
initCheckout: function() {
// Free product checkout handler
$('#wpdd-checkout-form').on('submit', function(e) {
var $form = $(this);
var isFree = $form.data('product-free') == '1';
if (isFree) {
e.preventDefault();
WPDD.processFreeCheckout($form);
}
});
// Price display toggle based on free checkbox
$('#wpdd_is_free').on('change', function() {
var $priceFields = $('.wpdd-price-field');
if ($(this).is(':checked')) {
$priceFields.hide();
} else {
$priceFields.show();
}
});
},
addToCart: function(e) {
e.preventDefault();
var $button = $(this);
var productId = $button.data('product-id');
if (!productId) {
WPDD.showNotice('Invalid product', 'error');
return;
}
$button.addClass('loading').prop('disabled', true);
$.ajax({
url: wpdd_ajax.url,
type: 'POST',
data: {
action: 'wpdd_add_to_cart',
product_id: productId,
nonce: wpdd_ajax.nonce
},
success: function(response) {
if (response.success) {
WPDD.showNotice(response.data.message, 'success');
// Update cart count if element exists
$('.wpdd-cart-count').text(response.data.cart_count);
// Show checkout button
if (response.data.checkout_url) {
$button.after('<a href="' + response.data.checkout_url +
'" class="wpdd-btn wpdd-btn-primary">Checkout</a>');
}
} else {
WPDD.showNotice(response.data, 'error');
}
},
error: function() {
WPDD.showNotice('An error occurred. Please try again.', 'error');
},
complete: function() {
$button.removeClass('loading').prop('disabled', false);
}
});
},
processFreeDownload: function(e) {
e.preventDefault();
var $button = $(this);
var productId = $button.data('product-id');
var $form = $button.closest('form');
if (!productId) {
WPDD.showNotice('Invalid product', 'error');
return;
}
var customerEmail = $form.find('input[name="customer_email"]').val();
var customerName = $form.find('input[name="customer_name"]').val();
if (!customerEmail && !WPDD.isUserLoggedIn()) {
WPDD.showNotice('Please provide your email address', 'error');
return;
}
$button.addClass('loading').prop('disabled', true);
$.ajax({
url: wpdd_ajax.url,
type: 'POST',
data: {
action: 'wpdd_process_free_download',
product_id: productId,
customer_email: customerEmail,
customer_name: customerName,
nonce: wpdd_ajax.nonce
},
success: function(response) {
if (response.success) {
window.location.href = response.data.redirect_url;
} else {
WPDD.showNotice(response.data, 'error');
}
},
error: function() {
WPDD.showNotice('An error occurred. Please try again.', 'error');
},
complete: function() {
$button.removeClass('loading').prop('disabled', false);
}
});
},
processFreeCheckout: function($form) {
var formData = $form.serialize();
var $submitBtn = $form.find('button[type="submit"]');
var productId = $form.find('input[name="product_id"]').val();
$submitBtn.addClass('loading').prop('disabled', true);
// Add visual feedback
$submitBtn.text('Processing...');
$.ajax({
url: wpdd_ajax.url,
type: 'POST',
data: formData + '&action=wpdd_process_free_download&nonce=' + wpdd_ajax.nonce + '&product_id=' + productId,
success: function(response) {
if (response.success) {
window.location.href = response.data.redirect_url;
} else {
WPDD.showNotice(response.data || 'Failed to process download', 'error');
$submitBtn.text('Get Free Download');
}
},
error: function(xhr, status, error) {
console.error('AJAX Error:', status, error);
WPDD.showNotice('An error occurred. Please try again.', 'error');
$submitBtn.text('Get Free Download');
},
complete: function() {
$submitBtn.removeClass('loading').prop('disabled', false);
}
});
},
showQuickview: function(e) {
e.preventDefault();
var productId = $(this).data('product-id');
if (!productId) {
return;
}
$.ajax({
url: wpdd_ajax.url,
type: 'POST',
data: {
action: 'wpdd_get_product_details',
product_id: productId,
nonce: wpdd_ajax.nonce
},
success: function(response) {
if (response.success) {
WPDD.displayQuickview(response.data);
} else {
WPDD.showNotice('Unable to load product details', 'error');
}
},
error: function() {
WPDD.showNotice('An error occurred. Please try again.', 'error');
}
});
},
displayQuickview: function(product) {
var modal = $('<div class="wpdd-modal"><div class="wpdd-modal-content"></div></div>');
var content = '';
content += '<div class="wpdd-modal-header">';
content += '<h2>' + product.title + '</h2>';
content += '<button class="wpdd-modal-close">&times;</button>';
content += '</div>';
content += '<div class="wpdd-modal-body">';
if (product.thumbnail) {
content += '<img src="' + product.thumbnail + '" alt="' + product.title + '" class="wpdd-modal-image">';
}
content += '<div class="wpdd-modal-details">';
content += '<p class="wpdd-modal-price">';
if (product.is_free) {
content += '<span class="wpdd-price-free">Free</span>';
} else {
content += '<span class="wpdd-price-regular">$' + product.final_price + '</span>';
}
content += '</p>';
content += '<p class="wpdd-modal-creator">by ' + product.creator.name + '</p>';
content += '<div class="wpdd-modal-description">' + product.description + '</div>';
content += '<p><strong>Files:</strong> ' + product.files_count + '</p>';
content += '<p><strong>Download Limit:</strong> ' + product.download_limit + '</p>';
content += '<p><strong>Expires:</strong> ' + product.download_expiry + '</p>';
content += '</div>';
content += '</div>';
content += '<div class="wpdd-modal-footer">';
content += '<a href="' + window.location.origin + '?product_id=' + product.id +
'" class="wpdd-btn wpdd-btn-primary">View Details</a>';
content += '</div>';
modal.find('.wpdd-modal-content').html(content);
$('body').append(modal);
modal.addClass('active');
// Close modal events
modal.on('click', '.wpdd-modal-close, .wpdd-modal', function(e) {
if (e.target === this) {
modal.removeClass('active');
setTimeout(function() {
modal.remove();
}, 300);
}
});
},
handleFilters: function(e) {
// Let the form submit naturally for now
// Could be enhanced with AJAX filtering
},
checkDownloadStatus: function(e) {
e.preventDefault();
var productId = $(this).data('product-id');
var $button = $(this);
if (!WPDD.isUserLoggedIn()) {
WPDD.showNotice('Please login to check download status', 'error');
return;
}
$button.addClass('loading');
$.ajax({
url: wpdd_ajax.url,
type: 'POST',
data: {
action: 'wpdd_check_download_status',
product_id: productId,
nonce: wpdd_ajax.nonce
},
success: function(response) {
if (response.success) {
var data = response.data;
if (data.can_download && data.download_url) {
window.location.href = data.download_url;
} else {
WPDD.showNotice(data.message, data.can_download ? 'success' : 'error');
}
} else {
WPDD.showNotice(response.data, 'error');
}
},
error: function() {
WPDD.showNotice('An error occurred. Please try again.', 'error');
},
complete: function() {
$button.removeClass('loading');
}
});
},
showNotice: function(message, type) {
type = type || 'info';
var notice = $('<div class="wpdd-notice wpdd-notice-' + type + '">' +
'<p>' + message + '</p>' +
'<button class="wpdd-notice-dismiss">&times;</button>' +
'</div>');
$('body').prepend(notice);
notice.addClass('active');
// Auto-dismiss after 5 seconds
setTimeout(function() {
notice.removeClass('active');
setTimeout(function() {
notice.remove();
}, 300);
}, 5000);
// Manual dismiss
notice.find('.wpdd-notice-dismiss').on('click', function() {
notice.removeClass('active');
setTimeout(function() {
notice.remove();
}, 300);
});
},
isUserLoggedIn: function() {
return $('body').hasClass('logged-in');
},
formatPrice: function(price) {
return '$' + parseFloat(price).toFixed(2);
}
};
// Initialize frontend functionality
WPDD.init();
// Add modal and notice styles if not already present
if (!$('#wpdd-dynamic-styles').length) {
var styles = `
<style id="wpdd-dynamic-styles">
.wpdd-modal {
display: flex;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
z-index: 999999;
opacity: 0;
visibility: hidden;
transition: all 0.3s;
align-items: center;
justify-content: center;
}
.wpdd-modal.active {
opacity: 1;
visibility: visible;
}
.wpdd-modal-content {
background: white;
max-width: 600px;
width: 90%;
max-height: 80vh;
border-radius: 8px;
overflow: hidden;
transform: scale(0.8);
transition: transform 0.3s;
}
.wpdd-modal.active .wpdd-modal-content {
transform: scale(1);
}
.wpdd-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #eee;
}
.wpdd-modal-header h2 {
margin: 0;
font-size: 20px;
}
.wpdd-modal-close {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.wpdd-modal-body {
padding: 20px;
max-height: 50vh;
overflow-y: auto;
}
.wpdd-modal-image {
width: 100%;
max-width: 200px;
height: auto;
float: left;
margin: 0 20px 20px 0;
border-radius: 4px;
}
.wpdd-modal-footer {
padding: 20px;
border-top: 1px solid #eee;
text-align: right;
}
.wpdd-notice {
position: fixed;
top: 32px;
right: 20px;
max-width: 400px;
z-index: 999999;
opacity: 0;
transform: translateX(100%);
transition: all 0.3s;
border-radius: 4px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.wpdd-notice.active {
opacity: 1;
transform: translateX(0);
}
.wpdd-notice p {
margin: 0;
padding: 15px 40px 15px 15px;
}
.wpdd-notice-dismiss {
position: absolute;
top: 5px;
right: 10px;
background: none;
border: none;
font-size: 18px;
cursor: pointer;
color: inherit;
opacity: 0.7;
}
.wpdd-notice-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.wpdd-notice-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.wpdd-notice-info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.loading {
position: relative;
pointer-events: none;
opacity: 0.7;
}
.loading::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 16px;
height: 16px;
margin: -8px 0 0 -8px;
border: 2px solid transparent;
border-top: 2px solid currentColor;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@media (max-width: 600px) {
.wpdd-modal-content {
width: 95%;
}
.wpdd-modal-image {
float: none;
margin: 0 0 20px 0;
max-width: 100%;
}
.wpdd-notice {
right: 10px;
left: 10px;
max-width: none;
}
}
</style>
`;
$('head').append(styles);
}
});

346
assets/js/paypal.js Normal file
View File

@@ -0,0 +1,346 @@
jQuery(document).ready(function($) {
'use strict';
/**
* PayPal Integration Object
*/
window.WPDD_PayPal = {
init: function() {
if (typeof paypal !== 'undefined') {
this.renderPayPalButton();
}
},
renderPayPalButton: function() {
var $container = $('#wpdd-paypal-button');
if (!$container.length) {
return;
}
var $form = $container.closest('form');
paypal.Buttons({
createOrder: function(data, actions) {
return WPDD_PayPal.createOrder($form);
},
onApprove: function(data, actions) {
return WPDD_PayPal.captureOrder(data.orderID);
},
onError: function(err) {
console.error('PayPal Error:', err);
WPDD_PayPal.showError('Payment processing failed. Please try again.');
},
onCancel: function(data) {
WPDD_PayPal.showNotice('Payment was cancelled.', 'info');
}
}).render('#wpdd-paypal-button');
},
createOrder: function($form) {
return new Promise(function(resolve, reject) {
var formData = $form.serialize();
$.ajax({
url: wpdd_paypal.ajax_url,
type: 'POST',
data: formData + '&action=wpdd_create_paypal_order&nonce=' + wpdd_paypal.nonce,
success: function(response) {
if (response.success) {
resolve(response.data.orderID);
} else {
reject(new Error(response.data || 'Failed to create PayPal order'));
}
},
error: function(xhr, status, error) {
reject(new Error('Network error: ' + error));
}
});
});
},
captureOrder: function(orderID) {
return new Promise(function(resolve, reject) {
$.ajax({
url: wpdd_paypal.ajax_url,
type: 'POST',
data: {
action: 'wpdd_capture_paypal_order',
orderID: orderID,
nonce: wpdd_paypal.nonce
},
success: function(response) {
if (response.success) {
// Redirect to thank you page
window.location.href = response.data.redirect_url;
} else {
reject(new Error(response.data || 'Failed to capture payment'));
}
},
error: function(xhr, status, error) {
reject(new Error('Network error: ' + error));
}
});
});
},
showError: function(message) {
this.showNotice(message, 'error');
},
showNotice: function(message, type) {
type = type || 'info';
// Remove existing notices
$('.wpdd-paypal-notice').remove();
var notice = $('<div class="wpdd-paypal-notice wpdd-notice-' + type + '">' +
'<p>' + message + '</p>' +
'<button class="wpdd-notice-dismiss">&times;</button>' +
'</div>');
$('#wpdd-paypal-button').before(notice);
// Auto-dismiss after 5 seconds
setTimeout(function() {
notice.fadeOut(function() {
notice.remove();
});
}, 5000);
// Manual dismiss
notice.find('.wpdd-notice-dismiss').on('click', function() {
notice.fadeOut(function() {
notice.remove();
});
});
},
validateForm: function($form) {
var isValid = true;
var errors = [];
// Check required fields
$form.find('input[required]').each(function() {
var $field = $(this);
var value = $field.val().trim();
var fieldName = $field.attr('name') || $field.attr('id');
if (!value) {
isValid = false;
errors.push(fieldName + ' is required');
$field.addClass('error');
} else {
$field.removeClass('error');
}
});
// Validate email format
$form.find('input[type="email"]').each(function() {
var $field = $(this);
var value = $field.val().trim();
var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (value && !emailRegex.test(value)) {
isValid = false;
errors.push('Please enter a valid email address');
$field.addClass('error');
}
});
if (!isValid) {
this.showError(errors.join('<br>'));
}
return isValid;
},
showLoadingState: function() {
$('#wpdd-paypal-button').addClass('wpdd-loading');
},
hideLoadingState: function() {
$('#wpdd-paypal-button').removeClass('wpdd-loading');
},
disableForm: function($form) {
$form.find('input, select, button').prop('disabled', true);
},
enableForm: function($form) {
$form.find('input, select, button').prop('disabled', false);
}
};
// Initialize PayPal integration after object definition
WPDD_PayPal.init();
// Add PayPal-specific styles
$('<style>')
.prop('type', 'text/css')
.html(`
#wpdd-paypal-button {
margin: 20px 0;
min-height: 45px;
}
.wpdd-paypal-notice {
padding: 12px 16px;
margin-bottom: 15px;
border-radius: 4px;
position: relative;
}
.wpdd-notice-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.wpdd-notice-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.wpdd-notice-info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.wpdd-notice-dismiss {
position: absolute;
top: 8px;
right: 12px;
background: none;
border: none;
font-size: 16px;
cursor: pointer;
color: inherit;
opacity: 0.7;
padding: 0;
line-height: 1;
}
.wpdd-notice-dismiss:hover {
opacity: 1;
}
.wpdd-loading {
position: relative;
opacity: 0.6;
pointer-events: none;
}
.wpdd-loading::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
margin: -10px 0 0 -10px;
border: 2px solid #ccc;
border-top: 2px solid #0073aa;
border-radius: 50%;
animation: wpdd-paypal-spin 1s linear infinite;
}
@keyframes wpdd-paypal-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
input.error {
border-color: #dc3545 !important;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25) !important;
}
.wpdd-checkout-section {
transition: opacity 0.3s;
}
.wpdd-checkout-section.disabled {
opacity: 0.5;
pointer-events: none;
}
/* PayPal button container responsive */
@media (max-width: 400px) {
#wpdd-paypal-button {
min-height: 40px;
}
}
/* Form validation styling */
.wpdd-form-row {
margin-bottom: 15px;
}
.wpdd-form-row.has-error input {
border-color: #dc3545;
}
.wpdd-field-error {
color: #dc3545;
font-size: 12px;
margin-top: 5px;
display: none;
}
.wpdd-form-row.has-error .wpdd-field-error {
display: block;
}
`)
.appendTo('head');
// Form validation enhancement
$(document).on('blur', '#wpdd-checkout-form input[required]', function() {
var $field = $(this);
var $row = $field.closest('.wpdd-form-row');
var value = $field.val().trim();
if (!value) {
$row.addClass('has-error');
} else {
$row.removeClass('has-error');
}
});
// Real-time email validation
$(document).on('input', '#wpdd-checkout-form input[type="email"]', function() {
var $field = $(this);
var $row = $field.closest('.wpdd-form-row');
var value = $field.val().trim();
var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (value && !emailRegex.test(value)) {
$row.addClass('has-error');
} else {
$row.removeClass('has-error');
}
});
// Prevent double-submission
var formSubmitting = false;
$(document).on('submit', '#wpdd-checkout-form', function(e) {
if (formSubmitting) {
e.preventDefault();
return false;
}
formSubmitting = true;
// Re-enable after 5 seconds as failsafe
setTimeout(function() {
formSubmitting = false;
}, 5000);
});
});