You've already forked wc-tier-and-package-prices
Release version 1.0.1
- Add Twig template engine integration - Migrate all templates to Twig format - Add German (Switzerland, Informal) translation - Improve template organization and security - Add Composer dependency management - Create comprehensive changelog
This commit is contained in:
91
assets/css/admin.css
Normal file
91
assets/css/admin.css
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Admin styles for WooCommerce Tier and Package Prices
|
||||
*/
|
||||
|
||||
.wc-tpp-tier-pricing,
|
||||
.wc-tpp-package-pricing {
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 15px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing > p:first-child,
|
||||
.wc-tpp-package-pricing > p:first-child {
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing .description,
|
||||
.wc-tpp-package-pricing .description {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
font-style: italic;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row,
|
||||
.wc-tpp-package-row {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: flex-end;
|
||||
padding: 15px;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row .form-field,
|
||||
.wc-tpp-package-row .form-field {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row label,
|
||||
.wc-tpp-package-row label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row input,
|
||||
.wc-tpp-package-row input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wc-tpp-remove-tier,
|
||||
.wc-tpp-remove-package {
|
||||
flex-shrink: 0;
|
||||
color: #b32d2e;
|
||||
border-color: #b32d2e;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.wc-tpp-remove-tier:hover,
|
||||
.wc-tpp-remove-package:hover {
|
||||
background: #b32d2e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.wc-tpp-add-tier,
|
||||
.wc-tpp-add-package {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.wc-tpp-tiers-container,
|
||||
.wc-tpp-packages-container {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.wc-tpp-tiers-container:empty::before,
|
||||
.wc-tpp-packages-container:empty::before {
|
||||
content: "No items added yet. Click 'Add' button to create pricing rules.";
|
||||
display: block;
|
||||
padding: 20px;
|
||||
background: #f0f0f1;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
173
assets/css/frontend.css
Normal file
173
assets/css/frontend.css
Normal file
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Frontend styles for WooCommerce Tier and Package Prices
|
||||
*/
|
||||
|
||||
.wc-tpp-pricing-container {
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing-table,
|
||||
.wc-tpp-package-pricing-table {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing-table:last-child,
|
||||
.wc-tpp-package-pricing-table:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing-table h3,
|
||||
.wc-tpp-package-pricing-table h3 {
|
||||
margin: 0 0 15px 0;
|
||||
font-size: 1.2em;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Tier pricing table */
|
||||
.wc-tpp-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wc-tpp-table thead {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.wc-tpp-table th {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.wc-tpp-table tbody tr {
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.wc-tpp-table tbody tr:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.wc-tpp-table tbody tr.wc-tpp-active-tier {
|
||||
background: #e7f3e7;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wc-tpp-table td {
|
||||
padding: 12px;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
/* Package pricing */
|
||||
.wc-tpp-packages {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.wc-tpp-package {
|
||||
background: #fff;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wc-tpp-package:hover {
|
||||
border-color: #333;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.wc-tpp-package.wc-tpp-selected {
|
||||
border-color: #4CAF50;
|
||||
background: #f0f8f0;
|
||||
}
|
||||
|
||||
.wc-tpp-package-header h4 {
|
||||
margin: 0 0 15px 0;
|
||||
font-size: 1.1em;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.wc-tpp-package-details {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.wc-tpp-package-qty {
|
||||
font-size: 1.4em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.wc-tpp-package-qty strong {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.wc-tpp-package-price {
|
||||
font-size: 1.6em;
|
||||
font-weight: 700;
|
||||
color: #4CAF50;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.wc-tpp-package-unit-price {
|
||||
font-size: 0.85em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.wc-tpp-select-package {
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
background: #333;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.95em;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.wc-tpp-select-package:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
.wc-tpp-package.wc-tpp-selected .wc-tpp-select-package {
|
||||
background: #4CAF50;
|
||||
}
|
||||
|
||||
.wc-tpp-package.wc-tpp-selected .wc-tpp-select-package:hover {
|
||||
background: #45a049;
|
||||
}
|
||||
|
||||
/* Cart notices */
|
||||
.wc-tpp-notice {
|
||||
color: #4CAF50;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.wc-tpp-packages {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.wc-tpp-table {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.wc-tpp-table th,
|
||||
.wc-tpp-table td {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
62
assets/js/admin.js
Normal file
62
assets/js/admin.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Admin JavaScript for WooCommerce Tier and Package Prices
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function() {
|
||||
let tierIndex = $('.wc-tpp-tier-row').length;
|
||||
let packageIndex = $('.wc-tpp-package-row').length;
|
||||
|
||||
// Add tier
|
||||
$('.wc-tpp-add-tier').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
const template = $('#wc-tpp-tier-row-template').html();
|
||||
const newRow = template.replace(/\{\{INDEX\}\}/g, tierIndex);
|
||||
$('.wc-tpp-tiers-container').append(newRow);
|
||||
tierIndex++;
|
||||
});
|
||||
|
||||
// Remove tier
|
||||
$(document).on('click', '.wc-tpp-remove-tier', function(e) {
|
||||
e.preventDefault();
|
||||
if (confirm('Are you sure you want to remove this tier?')) {
|
||||
$(this).closest('.wc-tpp-tier-row').remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Add package
|
||||
$('.wc-tpp-add-package').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
const template = $('#wc-tpp-package-row-template').html();
|
||||
const newRow = template.replace(/\{\{INDEX\}\}/g, packageIndex);
|
||||
$('.wc-tpp-packages-container').append(newRow);
|
||||
packageIndex++;
|
||||
});
|
||||
|
||||
// Remove package
|
||||
$(document).on('click', '.wc-tpp-remove-package', function(e) {
|
||||
e.preventDefault();
|
||||
if (confirm('Are you sure you want to remove this package?')) {
|
||||
$(this).closest('.wc-tpp-package-row').remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate inputs
|
||||
$(document).on('input', 'input[name*="[min_qty]"], input[name*="[qty]"]', function() {
|
||||
const value = parseInt($(this).val());
|
||||
if (value < 1) {
|
||||
$(this).val(1);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('input', 'input[name*="[price]"]', function() {
|
||||
const value = parseFloat($(this).val());
|
||||
if (value < 0) {
|
||||
$(this).val(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
179
assets/js/frontend.js
Normal file
179
assets/js/frontend.js
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* Frontend JavaScript for WooCommerce Tier and Package Prices
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function() {
|
||||
const $quantityInput = $('input.qty');
|
||||
const $priceDisplay = $('.woocommerce-Price-amount.amount').first();
|
||||
|
||||
if ($quantityInput.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get tiers and packages data
|
||||
const tiers = [];
|
||||
const packages = [];
|
||||
|
||||
$('.wc-tpp-tier-pricing-table tbody tr').each(function() {
|
||||
tiers.push({
|
||||
minQty: parseInt($(this).data('min-qty')),
|
||||
price: parseFloat($(this).data('price'))
|
||||
});
|
||||
});
|
||||
|
||||
$('.wc-tpp-package').each(function() {
|
||||
packages.push({
|
||||
qty: parseInt($(this).data('qty')),
|
||||
price: parseFloat($(this).data('price'))
|
||||
});
|
||||
});
|
||||
|
||||
// Update price display based on quantity
|
||||
function updatePriceDisplay() {
|
||||
const quantity = parseInt($quantityInput.val()) || 1;
|
||||
|
||||
// Check for exact package match
|
||||
let matchedPackage = null;
|
||||
packages.forEach(function(pkg) {
|
||||
if (pkg.qty === quantity) {
|
||||
matchedPackage = pkg;
|
||||
}
|
||||
});
|
||||
|
||||
if (matchedPackage) {
|
||||
const totalPrice = matchedPackage.price;
|
||||
const unitPrice = totalPrice / quantity;
|
||||
updatePrice(unitPrice, 'Package price: ' + formatPrice(totalPrice) + ' total');
|
||||
highlightPackage(quantity);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for tier pricing
|
||||
let applicableTier = null;
|
||||
tiers.forEach(function(tier) {
|
||||
if (quantity >= tier.minQty) {
|
||||
applicableTier = tier;
|
||||
}
|
||||
});
|
||||
|
||||
if (applicableTier) {
|
||||
updatePrice(applicableTier.price, 'Volume discount applied');
|
||||
highlightTier(quantity);
|
||||
removePackageHighlight();
|
||||
} else {
|
||||
removeAllHighlights();
|
||||
}
|
||||
}
|
||||
|
||||
// Update price in the product page
|
||||
function updatePrice(price, message) {
|
||||
if ($priceDisplay.length) {
|
||||
const formattedPrice = formatPrice(price);
|
||||
$priceDisplay.html(formattedPrice);
|
||||
|
||||
// Add message if provided
|
||||
if (message) {
|
||||
if (!$('.wc-tpp-price-message').length) {
|
||||
$priceDisplay.after('<div class="wc-tpp-price-message"></div>');
|
||||
}
|
||||
$('.wc-tpp-price-message').html('<small>' + message + '</small>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Format price according to WooCommerce settings
|
||||
function formatPrice(price) {
|
||||
const decimals = wcTppData.price_decimals || 2;
|
||||
const decimalSep = wcTppData.price_decimal_separator || '.';
|
||||
const thousandSep = wcTppData.price_thousand_separator || ',';
|
||||
const symbol = wcTppData.currency_symbol || '$';
|
||||
const position = wcTppData.currency_position || 'left';
|
||||
|
||||
let priceStr = price.toFixed(decimals);
|
||||
const parts = priceStr.split('.');
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousandSep);
|
||||
priceStr = parts.join(decimalSep);
|
||||
|
||||
switch (position) {
|
||||
case 'left':
|
||||
return symbol + priceStr;
|
||||
case 'right':
|
||||
return priceStr + symbol;
|
||||
case 'left_space':
|
||||
return symbol + ' ' + priceStr;
|
||||
case 'right_space':
|
||||
return priceStr + ' ' + symbol;
|
||||
default:
|
||||
return symbol + priceStr;
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight active tier
|
||||
function highlightTier(quantity) {
|
||||
$('.wc-tpp-table tbody tr').removeClass('wc-tpp-active-tier');
|
||||
let activeRow = null;
|
||||
|
||||
$('.wc-tpp-table tbody tr').each(function() {
|
||||
const minQty = parseInt($(this).data('min-qty'));
|
||||
if (quantity >= minQty) {
|
||||
activeRow = $(this);
|
||||
}
|
||||
});
|
||||
|
||||
if (activeRow) {
|
||||
activeRow.addClass('wc-tpp-active-tier');
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight selected package
|
||||
function highlightPackage(quantity) {
|
||||
$('.wc-tpp-package').removeClass('wc-tpp-selected');
|
||||
$('.wc-tpp-table tbody tr').removeClass('wc-tpp-active-tier');
|
||||
|
||||
$('.wc-tpp-package').each(function() {
|
||||
const pkgQty = parseInt($(this).data('qty'));
|
||||
if (pkgQty === quantity) {
|
||||
$(this).addClass('wc-tpp-selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Remove package highlight
|
||||
function removePackageHighlight() {
|
||||
$('.wc-tpp-package').removeClass('wc-tpp-selected');
|
||||
}
|
||||
|
||||
// Remove all highlights
|
||||
function removeAllHighlights() {
|
||||
$('.wc-tpp-package').removeClass('wc-tpp-selected');
|
||||
$('.wc-tpp-table tbody tr').removeClass('wc-tpp-active-tier');
|
||||
$('.wc-tpp-price-message').remove();
|
||||
}
|
||||
|
||||
// Handle quantity input changes
|
||||
$quantityInput.on('input change', function() {
|
||||
updatePriceDisplay();
|
||||
});
|
||||
|
||||
// Handle package selection
|
||||
$('.wc-tpp-select-package').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
const $package = $(this).closest('.wc-tpp-package');
|
||||
const qty = parseInt($package.data('qty'));
|
||||
|
||||
$quantityInput.val(qty).trigger('change');
|
||||
|
||||
// Scroll to add to cart button
|
||||
$('html, body').animate({
|
||||
scrollTop: $('.single_add_to_cart_button').offset().top - 100
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// Initial update
|
||||
updatePriceDisplay();
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
Reference in New Issue
Block a user