Refactor code structure for improved readability and maintainability
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
productold.php
|
productold.php
|
||||||
test.php
|
test.php
|
||||||
find_undeclared_vars.php.php
|
find_undeclared_vars.php.php
|
||||||
|
GTM_DataLayer_Triggers.md
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ defined('admin') or exit;
|
|||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
// Languages supported
|
// Languages supported
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
$supportedLanguages = ['US', 'NL', 'DE', 'ES','FR', 'IT'];
|
$supportedLanguages = ['US', 'NL', 'DE', 'ES','FR'];
|
||||||
|
|
||||||
if(isset($_POST['generatefile'])){
|
if(isset($_POST['generatefile'])){
|
||||||
|
|
||||||
|
|||||||
70
api_check_payment_status.php
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
define('MorvalWatches', true);
|
||||||
|
|
||||||
|
// Start session
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
// Includes
|
||||||
|
include './custom/settings/config.php';
|
||||||
|
include './custom/settings/settings.php';
|
||||||
|
include 'functions.php';
|
||||||
|
|
||||||
|
// Get the API token from session or authenticate
|
||||||
|
$token_refresh_buffer = 300;
|
||||||
|
|
||||||
|
if (!isset($_SESSION['api_token']) || !isset($_SESSION['api_token_expires']) || time() >= ($_SESSION['api_token_expires'] - $token_refresh_buffer)) {
|
||||||
|
$data = json_encode(array("clientID" => clientID, "clientsecret" => clientsecret), JSON_UNESCAPED_UNICODE);
|
||||||
|
$responses = ioAPIv2('/v2/authorization', $data,'');
|
||||||
|
if (!empty($responses)){$responses = json_decode($responses,true);}else{$responses = '400';}
|
||||||
|
|
||||||
|
if (isset($responses['token']) && isset($responses['token_valid'])) {
|
||||||
|
$_SESSION['api_token'] = $responses['token'];
|
||||||
|
$_SESSION['api_token_expires'] = strtotime($responses['token_valid']);
|
||||||
|
$clientsecret = $responses['token'];
|
||||||
|
} else {
|
||||||
|
$clientsecret = $responses['token'] ?? '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$clientsecret = $_SESSION['api_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set JSON header
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
// Get order ID from request
|
||||||
|
$order_id = $_GET['order_id'] ?? null;
|
||||||
|
|
||||||
|
if (!$order_id) {
|
||||||
|
echo json_encode(['error' => 'No order ID provided']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check transaction status
|
||||||
|
$transaction_data = ioAPIv2('/v2/transactions/txn_id='.$order_id,'',$clientsecret);
|
||||||
|
$transaction = json_decode($transaction_data, true);
|
||||||
|
|
||||||
|
if ($transaction && isset($transaction[0])) {
|
||||||
|
$payment_status_code = $transaction[0]['payment_status'] ?? 0;
|
||||||
|
|
||||||
|
// Map payment status codes: 1 = Paid, 101 = Pending, 102 = Failed, 103 = Expired, 999 = Cancelled
|
||||||
|
if ($payment_status_code == 1) {
|
||||||
|
$payment_status = 'success';
|
||||||
|
} elseif ($payment_status_code == 101) {
|
||||||
|
$payment_status = 'pending';
|
||||||
|
} elseif (in_array($payment_status_code, [102, 103, 999])) {
|
||||||
|
$payment_status = 'failed';
|
||||||
|
} else {
|
||||||
|
$payment_status = 'processing';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode([
|
||||||
|
'status' => $payment_status,
|
||||||
|
'payment_status_code' => $payment_status_code
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
echo json_encode([
|
||||||
|
'status' => 'processing',
|
||||||
|
'payment_status_code' => 101
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
1
cache/.htaccess
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Deny from all
|
||||||
1376
cache/catalog.json
vendored
Normal file
496
cache/categories.json
vendored
Normal file
@@ -0,0 +1,496 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 57
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 18,
|
||||||
|
"name": "Thomas-I Date",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:20",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:46",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 57
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 21,
|
||||||
|
"name": "fp_carrousel_1",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:13",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:13",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 57
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 19,
|
||||||
|
"name": "Thomas-II Open Heart",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:37",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:39",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 22,
|
||||||
|
"name": "fp_carrousel_2",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:22",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:22",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 61
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 19,
|
||||||
|
"name": "Thomas-II Open Heart",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:37",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:39",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 61
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 22,
|
||||||
|
"name": "fp_carrousel_2",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:22",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:22",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 61
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 62
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 19,
|
||||||
|
"name": "Thomas-II Open Heart",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:37",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:39",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 62
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 22,
|
||||||
|
"name": "fp_carrousel_2",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:22",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:22",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 62
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 63
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 19,
|
||||||
|
"name": "Thomas-II Open Heart",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:37",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:39",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 63
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 22,
|
||||||
|
"name": "fp_carrousel_2",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:22",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:22",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 63
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 19,
|
||||||
|
"name": "Thomas-II Open Heart",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:37",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:39",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 22,
|
||||||
|
"name": "fp_carrousel_2",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:22",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:22",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 20,
|
||||||
|
"name": "Accessories",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:55",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:19:24",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 65
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 23,
|
||||||
|
"name": "Bracelets",
|
||||||
|
"parent_id": 20,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-25 13:20:01",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:20:01",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 65
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 20,
|
||||||
|
"name": "Accessories",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:55",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:19:24",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 66
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 23,
|
||||||
|
"name": "Bracelets",
|
||||||
|
"parent_id": 20,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-25 13:20:01",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:20:01",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 66
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 20,
|
||||||
|
"name": "Accessories",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:55",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:19:24",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 67
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 23,
|
||||||
|
"name": "Bracelets",
|
||||||
|
"parent_id": 20,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-25 13:20:01",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:20:01",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 67
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 20,
|
||||||
|
"name": "Accessories",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:55",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:19:24",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 68
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 23,
|
||||||
|
"name": "Bracelets",
|
||||||
|
"parent_id": 20,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-25 13:20:01",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:20:01",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 68
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 69
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 18,
|
||||||
|
"name": "Thomas-I Date",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:20",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:46",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 69
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 21,
|
||||||
|
"name": "fp_carrousel_1",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:13",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:13",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 69
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 18,
|
||||||
|
"name": "Thomas-I Date",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:20",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:46",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 21,
|
||||||
|
"name": "fp_carrousel_1",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:13",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:13",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 71
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 18,
|
||||||
|
"name": "Thomas-I Date",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:20",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:46",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 71
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 21,
|
||||||
|
"name": "fp_carrousel_1",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:13",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:13",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 71
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 17,
|
||||||
|
"name": "Watches",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:56:56",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-25 13:18:55",
|
||||||
|
"updatedby": "MorvalWatches",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 72
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 18,
|
||||||
|
"name": "Thomas-I Date",
|
||||||
|
"parent_id": 17,
|
||||||
|
"status": 1,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:57:20",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-05-27 13:34:46",
|
||||||
|
"updatedby": "paul@veliti.nl",
|
||||||
|
"filter": 1,
|
||||||
|
"product_id": 72
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rowID": 21,
|
||||||
|
"name": "fp_carrousel_1",
|
||||||
|
"parent_id": 0,
|
||||||
|
"status": 0,
|
||||||
|
"accounthierarchy": "{\"salesid\":\"148-MorvalWatches\",\"soldto\":\"\"}",
|
||||||
|
"created": "2025-02-24 18:58:13",
|
||||||
|
"createdby": "MorvalWatches",
|
||||||
|
"updated": "2025-02-24 18:58:13",
|
||||||
|
"updatedby": null,
|
||||||
|
"filter": 0,
|
||||||
|
"product_id": 72
|
||||||
|
}
|
||||||
|
]
|
||||||
2
cart.php
@@ -207,7 +207,7 @@ $view .= '
|
|||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<input type="submit" form ="cart-form" value="'.$btn_emptycart.'" name="emptycart" class="btn" title="Remove cart" style="font-size:10px;background:none;">
|
<input type="submit" form ="cart-form" value="'.$btn_emptycart.'" name="emptycart" class="btn" title="Remove cart" style="font-size:10px;background:none;">
|
||||||
<input type="submit" form ="cart-form" value="'.$btn_update.'" name="update" class="btn" title="Refresh cart">
|
<input type="submit" form ="cart-form" value="'.$btn_update.'" name="update" class="btn" title="Refresh cart">
|
||||||
<input type="submit" form ="cart-form" value="'.$btn_checkout.'" name="checkout" class="btn" style="background-color:green;">
|
<input type="submit" form ="cart-form" value="'.$btn_checkout.'" name="checkout" class="btn btn-checkout-sticky" style="background-color:green;">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
';
|
';
|
||||||
|
|||||||
897
checkout.php
@@ -118,8 +118,9 @@ if ($products_in_cart) {
|
|||||||
//Place order
|
//Place order
|
||||||
//-------------------------------
|
//-------------------------------
|
||||||
// Make sure when the user submits the form all data was submitted and shopping cart is not empty
|
// Make sure when the user submits the form all data was submitted and shopping cart is not empty
|
||||||
if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['address_street'], $_POST['address_city'], $_POST['address_state'], $_POST['address_zip'], $_POST['address_country'], $_POST['address_phone'], $_SESSION['cart']) && !isset($_POST['update'])) {
|
if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['address_street'], $_POST['address_city'], $_POST['address_state'], $_POST['address_zip'], $_POST['address_country'], $_SESSION['cart']) && !isset($_POST['update'])) {
|
||||||
$account_id = null;
|
$account_id = null;
|
||||||
|
|
||||||
// If the user is already logged in
|
// If the user is already logged in
|
||||||
if (isset($_SESSION['account_loggedin'])) {
|
if (isset($_SESSION['account_loggedin'])) {
|
||||||
// Account logged-in, update the user's details
|
// Account logged-in, update the user's details
|
||||||
@@ -133,7 +134,7 @@ if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['a
|
|||||||
"address_state" => $_POST['address_state'],
|
"address_state" => $_POST['address_state'],
|
||||||
"address_zip" => $_POST['address_zip'],
|
"address_zip" => $_POST['address_zip'],
|
||||||
"address_country" => $_POST['address_country'],
|
"address_country" => $_POST['address_country'],
|
||||||
"address_phone" => $_POST['address_phone'],
|
"address_phone" => $_POST['address_phone'] ?? '',
|
||||||
"userkey" => $_SESSION['account_id']), JSON_UNESCAPED_UNICODE);
|
"userkey" => $_SESSION['account_id']), JSON_UNESCAPED_UNICODE);
|
||||||
$account_update = ioAPIv2('/v2/identity/',$payload,$clientsecret);
|
$account_update = ioAPIv2('/v2/identity/',$payload,$clientsecret);
|
||||||
$account_update = json_decode($account_update,true);
|
$account_update = json_decode($account_update,true);
|
||||||
@@ -172,7 +173,7 @@ if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['a
|
|||||||
"address_state" => $_POST['address_state'],
|
"address_state" => $_POST['address_state'],
|
||||||
"address_zip" => $_POST['address_zip'],
|
"address_zip" => $_POST['address_zip'],
|
||||||
"address_country" => $_POST['address_country'],
|
"address_country" => $_POST['address_country'],
|
||||||
"address_phone" => $_POST['address_phone']), JSON_UNESCAPED_UNICODE);
|
"address_phone" => $_POST['address_phone'] ?? ''), JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
$account = ioAPIv2('/v2/identity/',$payload,$clientsecret);
|
$account = ioAPIv2('/v2/identity/',$payload,$clientsecret);
|
||||||
$account= json_decode($account,true);
|
$account= json_decode($account,true);
|
||||||
@@ -210,24 +211,50 @@ if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['a
|
|||||||
|
|
||||||
if ($place_order['error'] == '' && $place_order['id'] != ''){
|
if ($place_order['error'] == '' && $place_order['id'] != ''){
|
||||||
|
|
||||||
//SEND CONFIRMATION TO CUSTOMER
|
// Push purchase event to dataLayer
|
||||||
send_order_details_email(
|
if (isset($place_order['products_checked-out']) && is_array($place_order['products_checked-out'])) {
|
||||||
$account['email'],
|
$productIds = [];
|
||||||
$place_order['products_checked-out'],
|
$totalQuantity = 0;
|
||||||
$account['first_name'],
|
$products = [];
|
||||||
$account['last_name'],
|
|
||||||
$account['address_street'],
|
foreach ($place_order['products_checked-out'] as $p) {
|
||||||
$account['address_city'],
|
if (is_array($p)) {
|
||||||
$account['address_state'],
|
$productIds[] = $p['id'] ?? '';
|
||||||
$account['address_zip'],
|
$totalQuantity += $p['quantity'] ?? 0;
|
||||||
$account['address_country'],
|
$products[] = [
|
||||||
$place_order['subtotal'],
|
'id' => $p['id'] ?? '',
|
||||||
$place_order['discounttotal'],
|
'name' => $p['meta']['name'] ?? '',
|
||||||
$place_order['shippingtotal'],
|
'price' => $p['options_price'] ?? 0,
|
||||||
$place_order['taxtotal'],
|
'quantity' => $p['quantity'] ?? 0
|
||||||
$place_order['payment_amount'],
|
];
|
||||||
$place_order['transaction_id']
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
|
echo "<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
window.dataLayer.push({
|
||||||
|
'event': 'purchase',
|
||||||
|
'ecommerce': {
|
||||||
|
'purchase': {
|
||||||
|
'actionField': {
|
||||||
|
'id': '" . $place_order['transaction_id'] . "',
|
||||||
|
'revenue': '" . $place_order['payment_amount'] . "',
|
||||||
|
'tax': '" . $place_order['taxtotal'] . "',
|
||||||
|
'shipping': '" . $place_order['shippingtotal'] . "'
|
||||||
|
},
|
||||||
|
'products': " . json_encode($products) . "
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'content_type': 'product',
|
||||||
|
'content_ids': " . json_encode($productIds) . ",
|
||||||
|
'value': " . floatval($place_order['payment_amount']) . ",
|
||||||
|
'currency': 'EUR',
|
||||||
|
'num_items': " . $totalQuantity . "
|
||||||
|
});
|
||||||
|
</script>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email will be sent by webhook after successful payment
|
||||||
|
|
||||||
//Disable giftcard
|
//Disable giftcard
|
||||||
if (isset($_SESSION['discount'])){
|
if (isset($_SESSION['discount'])){
|
||||||
@@ -366,200 +393,385 @@ if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['a
|
|||||||
//-------------------------------
|
//-------------------------------
|
||||||
// END PLACE ORDER
|
// END PLACE ORDER
|
||||||
//-------------------------------
|
//-------------------------------
|
||||||
|
|
||||||
$terms_link = url('index.php?page=termsandconditions');
|
$terms_link = url('index.php?page=termsandconditions');
|
||||||
$privacy_link = url('index.php?page=privacy');
|
$privacy_link = url('index.php?page=privacy');
|
||||||
|
|
||||||
$view = template_header(($checkout_header ?? 'Checkout'),'');
|
$view = template_header(($checkout_header ?? 'Checkout'),'');
|
||||||
|
|
||||||
$view .= '
|
$view .= '
|
||||||
<div class="checkout content-wrapper">
|
<div class="checkout checkout-wizard">
|
||||||
|
|
||||||
<h1>'.$h1_checkout.'</h1>';
|
<h1>'.($h1_Checkout ?? 'Checkout').'</h1>
|
||||||
|
|
||||||
if (!empty($errors) || count($errors) > 0){
|
<!-- Progress Steps -->
|
||||||
|
<div class="progress-steps">
|
||||||
|
<div class="progress-step active" data-step="1">
|
||||||
|
<div class="step-number">1</div>
|
||||||
|
<div class="step-label">'.($step_contact ?? 'Contact').'</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-step" data-step="2">
|
||||||
|
<div class="step-number">2</div>
|
||||||
|
<div class="step-label">'.($step_payment ?? 'Payment').'</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-step" data-step="3">
|
||||||
|
<div class="step-number">3</div>
|
||||||
|
<div class="step-label">'.($step_shipping ?? 'Shipping').'</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-step" data-step="4">
|
||||||
|
<div class="step-number">4</div>
|
||||||
|
<div class="step-label">'.($step_review ?? 'Review').'</div>
|
||||||
|
</div>
|
||||||
|
</div>';
|
||||||
|
|
||||||
$view .= '<p class="error">'.implode('<br>', $errors).'</p>';
|
if ($errors) {
|
||||||
}
|
foreach($errors as $error) {
|
||||||
if (!isset($_SESSION['account_loggedin'])){
|
$view .= '<p class="error">'.$error.'</p>';
|
||||||
$view .= '<p>'.$account_available.' <a href="'.url('index.php?page=myaccount').'">'.$account_log_in.'</a></p>';
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$view .= '
|
$view .= '
|
||||||
<form action="" method="post">
|
<form id="checkout-form" method="post" autocomplete="on">
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<div class="shipping-details">
|
<div class="checkout-steps">
|
||||||
<div id="dropin-container"></div>
|
|
||||||
<h2>'.$payment_method.'</h2>
|
|
||||||
|
|
||||||
<div class="payment-methods">';
|
<!-- STEP 1: Contact Information -->
|
||||||
if (mollie_enabled){
|
<div class="step-section active" id="step-1" data-step="1">
|
||||||
$view .= ' <input id="mollie-ideal" type="radio" name="method" value="3" '. ((mollie_default)? 'checked':'') .'>
|
<div class="step-header" onclick="editStep(1)">
|
||||||
<label for="mollie-ideal">
|
<div class="step-header-content">
|
||||||
<img src="./custom/assets/iDEAL.png" style="width: 50px;" alt="'.$payment_method_1.'">
|
<div class="step-badge">1</div>
|
||||||
<img src="./custom/assets/bancontact.png" style="width: 50px;" alt="'.$payment_method_1.'">
|
<h2 class="step-title">'.($step_contact ?? 'Contact Information').'</h2>
|
||||||
</label>';
|
</div>
|
||||||
|
<div class="step-edit">'.($edit_text ?? 'Edit').'</div>
|
||||||
$view .= ' <input id="mollie-card" type="radio" name="method" value="3">
|
|
||||||
<label for="mollie-card">
|
|
||||||
<img src="./custom/assets/mastercard.png" style="width: 50px;" alt="'.$payment_method_1.'">
|
|
||||||
<img src="./custom/assets/visa.png" style="width: 50px;" alt="'.$payment_method_1.'">
|
|
||||||
</label>';
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (paypal_enabled){
|
|
||||||
$view .= ' <input id="paypal" type="radio" name="method" value="1" '. ((paypal_default)? 'checked':'') .'>
|
|
||||||
<label for="paypal"><img src="https://www.paypalobjects.com/webstatic/mktg/Logo/pp-logo-100px.png" alt="PayPal Logo"></label>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pay_on_delivery_enabled){
|
|
||||||
$view .= ' <input id="payondelivery" type="radio" name="method" value="2" '. ((pay_on_delivery_default)? 'checked':'') .' >
|
|
||||||
<label for="payondelivery">'.$payment_method_2.'</label>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$view .= ' </div>';
|
|
||||||
|
|
||||||
if (!isset($_SESSION['account_loggedin'])){
|
|
||||||
|
|
||||||
$view .= '
|
|
||||||
<h2>'.$account_create_email.'</h2>
|
|
||||||
<label for="email"></label>
|
|
||||||
<input type="email" name="email" id="email" placeholder="'.$account_create_email.'" class="form-field" required>
|
|
||||||
|
|
||||||
<h2>'.$account_create.((!account_required) ? $account_create_optional : '').'</h2>
|
|
||||||
<label for="password">'.$account_create_password.'</label>
|
|
||||||
<input type="password" name="password" id="password" placeholder="'.$account_create_password.'" class="form-field" autocomplete="new-password">
|
|
||||||
|
|
||||||
<label for="cpassword">'.$account_create_password_confirm.'</label>
|
|
||||||
<input type="password" name="cpassword" id="cpassword" placeholder="'.$account_create_password_confirm.'" class="form-field" autocomplete="new-password">';
|
|
||||||
}
|
|
||||||
$view .= '
|
|
||||||
<h2>'.$h2_Shipping_details.'</h2>
|
|
||||||
|
|
||||||
<div class="row1">
|
|
||||||
<label for="first_name">'.$shipping_first_name.'</label>
|
|
||||||
<input type="text" value="'.htmlspecialchars($account['first_name'], ENT_QUOTES).'" name="first_name" id="first_name" placeholder="'.$shipping_first_name.'" class="form-field" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row2">
|
|
||||||
<label for="last_name">'.$shipping_last_name.'</label>
|
|
||||||
<input type="text" value="'.htmlspecialchars($account['last_name'], ENT_QUOTES).'" name="last_name" id="last_name" placeholder="'.$shipping_last_name.'" class="form-field" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label for="address_street">'.$shipping_address.'</label>
|
|
||||||
<input type="text" value="'.htmlspecialchars($account['address_street'], ENT_QUOTES).'" name="address_street" id="address_street" placeholder="'.$shipping_address.'" class="form-field" required>
|
|
||||||
|
|
||||||
<label for="address_city">'.$shipping_city.'</label>
|
|
||||||
<input type="text" value="'.htmlspecialchars($account['address_city'], ENT_QUOTES).'" name="address_city" id="address_city" placeholder="'.$shipping_city.'" class="form-field" required>
|
|
||||||
|
|
||||||
<div class="row1">
|
|
||||||
<label for="address_state">'.$shipping_state.'</label>
|
|
||||||
<input type="text" value="'.htmlspecialchars($account['address_state'], ENT_QUOTES).'" name="address_state" id="address_state" placeholder="'.$shipping_state.'" class="form-field">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row2">
|
|
||||||
<label for="address_zip">'.$shipping_zip.'</label>
|
|
||||||
<input type="text" value="'.htmlspecialchars($account['address_zip'], ENT_QUOTES).'" name="address_zip" id="address_zip" placeholder="'.$shipping_zip.'" class="form-field" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<label for="address_phone">'.$shipping_phone.'</label>
|
|
||||||
<input type="text" value="'.htmlspecialchars(($account['address_phone'] ?? ''), ENT_QUOTES).'" name="address_phone" id="address_phone" placeholder="'.$shipping_phone.'" class="form-field" required>
|
|
||||||
|
|
||||||
<label for="address_country">'.$shipping_country.'</label>
|
|
||||||
<select name="address_country" class="ajax-update form-field" required>';
|
|
||||||
foreach($countries_in_scope as $key => $value){
|
|
||||||
$view .= ' <option value="'.$key.'" '.($key==$account['address_country'] ? ' selected' : '').'>'.(${$value} ?? $value).'</option>';
|
|
||||||
}
|
|
||||||
$view .= ' </select>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cart-details">
|
|
||||||
|
|
||||||
<h2>'.$h2_shoppingcart.'</h2>
|
|
||||||
|
|
||||||
<table>';
|
|
||||||
foreach($products_in_cart['cart_details']['products'] as $product){
|
|
||||||
|
|
||||||
$view .= ' <tr>
|
|
||||||
<td><img src="'.img_url.$product['meta']['img'].'" width="35" height="35" alt="'.$product['meta']['name'].'"></td>
|
|
||||||
<td>'.$product['quantity'].' x '.$product['meta']['name'].'</td>
|
|
||||||
<td class="price">'.currency_code.''.number_format($product['options_price'] * $product['quantity'],2).'</td>
|
|
||||||
</tr>';
|
|
||||||
}
|
|
||||||
$view .= ' </table>
|
|
||||||
|
|
||||||
<div class="discount-code">
|
|
||||||
<input type="text" class="ajax-update form-field" name="discount_code" placeholder="'.$discount_label.'" value="'.(isset($_SESSION['discount']) ? $_SESSION['discount'] : '').'">
|
|
||||||
<span class="result">';
|
|
||||||
if (isset($_SESSION['discount'], $products_in_cart['totals']['discounttotal'])){
|
|
||||||
$view .= $products_in_cart['totals']['discount_message'];
|
|
||||||
}
|
|
||||||
$view .= ' </span>
|
|
||||||
</div>
|
|
||||||
<div class="shipping-methods-container">';
|
|
||||||
|
|
||||||
if (isset($shipping_methods) && count($shipping_methods) > 0){
|
|
||||||
$view .= ' <div class="shipping-methods">
|
|
||||||
<h3>'.$h3_shipping_method.'</h3>';
|
|
||||||
|
|
||||||
foreach($shipping_methods as $method){
|
|
||||||
$view .= ' <div class="shipping-method">
|
|
||||||
<input type="radio" class="ajax-update" id="sm'.$method['id'].'" name="shipping_method" value="'.$method['id'].'" required'.(($checkout_input['selected_shipment_method']==$method['id'] || count($shipping_methods) == 1) ? ' checked':'').'>
|
|
||||||
<label for="sm'.$method['id'].'">'.$method['name'].' ('.currency_code.''.number_format($method['price'], 2).')</label>
|
|
||||||
</div>';
|
|
||||||
}
|
|
||||||
$view .= '</div>';
|
|
||||||
|
|
||||||
}
|
|
||||||
$view .= ' </div>
|
|
||||||
<div class="summary">
|
|
||||||
<div class="subtotal">
|
|
||||||
<span>'.$total_subtotal.'</span>
|
|
||||||
<span>'.currency_code.''.number_format($subtotal,2).'</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="shipping">
|
<div class="step-content">';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['account_loggedin'])) {
|
||||||
|
$view .= '
|
||||||
|
<label for="email">'.($customer_email ?? 'Email').' *</label>
|
||||||
|
<input type="email" name="email" id="email" placeholder="you@example.com" class="form-field" required>
|
||||||
|
|
||||||
|
<div class="collapsible-section" style="margin-top: 1.5rem;">
|
||||||
|
<button type="button" class="collapsible-header" onclick="toggleCollapsible(this)">
|
||||||
|
<span>'.$account_create.((!account_required) ? ' '.($account_optional ?? '(Optional)') : '').'</span>
|
||||||
|
<svg class="collapsible-icon" width="20" height="20" viewBox="0 0 20 20">
|
||||||
|
<path d="M5 7.5L10 12.5L15 7.5" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="collapsible-content">
|
||||||
|
<label for="password">'.$account_create_password.'</label>
|
||||||
|
<input type="password" name="password" id="password" placeholder="'.$account_create_password.'" class="form-field" autocomplete="new-password">
|
||||||
|
|
||||||
|
<label for="cpassword">'.$account_create_password_confirm.'</label>
|
||||||
|
<input type="password" name="cpassword" id="cpassword" placeholder="'.$account_create_password_confirm.'" class="form-field" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
</div>';
|
||||||
|
} else {
|
||||||
|
$view .= '
|
||||||
|
<label for="email_display">'.($customer_email ?? 'Email').'</label>
|
||||||
|
<input type="email" id="email_display" value="'.htmlspecialchars($account['email'], ENT_QUOTES).'" class="form-field" readonly style="background-color: #f3f4f6;">
|
||||||
|
<input type="hidden" name="email" value="'.htmlspecialchars($account['email'], ENT_QUOTES).'">';
|
||||||
|
}
|
||||||
|
|
||||||
|
$view .= '
|
||||||
|
<div class="step-buttons">
|
||||||
|
<button type="button" class="btn-continue" onclick="goToStep(2)">
|
||||||
|
'.($continue_text ?? 'Continue to Payment').'
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M7.5 15L12.5 10L7.5 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- STEP 2: Payment Method -->
|
||||||
|
<div class="step-section" id="step-2" data-step="2">
|
||||||
|
<div class="step-header" onclick="editStep(2)">
|
||||||
|
<div class="step-header-content">
|
||||||
|
<div class="step-badge">2</div>
|
||||||
|
<h2 class="step-title">'.$payment_method.'</h2>
|
||||||
|
</div>
|
||||||
|
<div class="step-edit">'.($edit_text ?? 'Edit').'</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step-content">
|
||||||
|
<div class="payment-methods-grid">';
|
||||||
|
if (mollie_enabled){
|
||||||
|
$view .= ' <div class="payment-option">
|
||||||
|
<input id="mollie-ideal" type="radio" name="method" value="3" '. ((mollie_default)? 'checked':'') .'>
|
||||||
|
<label for="mollie-ideal" class="payment-card">
|
||||||
|
<div class="payment-card-content">
|
||||||
|
<div class="payment-logos">
|
||||||
|
<img src="./custom/assets/wero.svg" alt="Bank Transfer" class="payment-logo" style="width:120px">
|
||||||
|
</div>
|
||||||
|
<span class="payment-name">'.($bank_transfer ?? 'Bank Transfer').'</span>
|
||||||
|
</div>
|
||||||
|
<div class="payment-check">✓</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="payment-option">
|
||||||
|
<input id="mollie-card" type="radio" name="method" value="3">
|
||||||
|
<label for="mollie-card" class="payment-card">
|
||||||
|
<div class="payment-card-content">
|
||||||
|
<div class="payment-logos">
|
||||||
|
<img src="./custom/assets/mastercard.png" alt="Mastercard" class="payment-logo">
|
||||||
|
<img src="./custom/assets/visa.png" alt="Visa" class="payment-logo">
|
||||||
|
</div>
|
||||||
|
<span class="payment-name">'.($card_payment ?? 'Credit / Debit Card').'</span>
|
||||||
|
</div>
|
||||||
|
<div class="payment-check">✓</div>
|
||||||
|
</label>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paypal_enabled){
|
||||||
|
$view .= ' <div class="payment-option">
|
||||||
|
<input id="paypal" type="radio" name="method" value="1" '. ((paypal_default)? 'checked':'') .'>
|
||||||
|
<label for="paypal" class="payment-card">
|
||||||
|
<div class="payment-card-content">
|
||||||
|
<div class="payment-logos">
|
||||||
|
<img src="https://www.paypalobjects.com/webstatic/mktg/Logo/pp-logo-100px.png" alt="PayPal" class="payment-logo">
|
||||||
|
</div>
|
||||||
|
<span class="payment-name">PayPal</span>
|
||||||
|
</div>
|
||||||
|
<div class="payment-check">✓</div>
|
||||||
|
</label>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pay_on_delivery_enabled){
|
||||||
|
$view .= ' <div class="payment-option">
|
||||||
|
<input id="payondelivery" type="radio" name="method" value="2" '. ((pay_on_delivery_default)? 'checked':'') .'>
|
||||||
|
<label for="payondelivery" class="payment-card">
|
||||||
|
<div class="payment-card-content">
|
||||||
|
<div class="payment-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span class="payment-name">'.$payment_method_2.'</span>
|
||||||
|
</div>
|
||||||
|
<div class="payment-check">✓</div>
|
||||||
|
</label>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$view .= ' </div>
|
||||||
|
|
||||||
|
<div class="step-buttons">
|
||||||
|
<button type="button" class="btn-back" onclick="goToStep(1)">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M12.5 15L7.5 10L12.5 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
'.($back_text ?? 'Back').'
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn-continue" onclick="goToStep(3)">
|
||||||
|
'.($continue_text ?? 'Continue to Shipping').'
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M7.5 15L12.5 10L7.5 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- STEP 3: Shipping Details -->
|
||||||
|
<div class="step-section" id="step-3" data-step="3">
|
||||||
|
<div class="step-header" onclick="editStep(3)">
|
||||||
|
<div class="step-header-content">
|
||||||
|
<div class="step-badge">3</div>
|
||||||
|
<h2 class="step-title">'.$h2_Shipping_details.'</h2>
|
||||||
|
</div>
|
||||||
|
<div class="step-edit">'.($edit_text ?? 'Edit').'</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step-content">
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-col">
|
||||||
|
<label for="first_name">'.$shipping_first_name.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['first_name'], ENT_QUOTES).'" name="first_name" id="first_name" placeholder="'.$shipping_first_name.'" class="form-field" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-col">
|
||||||
|
<label for="last_name">'.$shipping_last_name.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['last_name'], ENT_QUOTES).'" name="last_name" id="last_name" placeholder="'.$shipping_last_name.'" class="form-field" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="address_street">'.$shipping_address.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['address_street'], ENT_QUOTES).'" name="address_street" id="address_street" placeholder="'.$shipping_address.'" class="form-field" required>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-col">
|
||||||
|
<label for="address_city">'.$shipping_city.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['address_city'], ENT_QUOTES).'" name="address_city" id="address_city" placeholder="'.$shipping_city.'" class="form-field" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-col">
|
||||||
|
<label for="address_zip">'.$shipping_zip.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['address_zip'], ENT_QUOTES).'" name="address_zip" id="address_zip" placeholder="'.$shipping_zip.'" class="form-field" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-col">
|
||||||
|
<label for="address_state">'.$shipping_state.'</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['address_state'], ENT_QUOTES).'" name="address_state" id="address_state" placeholder="'.$shipping_state.'" class="form-field">
|
||||||
|
</div>
|
||||||
|
<div class="form-col">
|
||||||
|
<label for="address_country">'.$shipping_country.' *</label>
|
||||||
|
<select name="address_country" class="ajax-update form-field" required>';
|
||||||
|
foreach($countries_in_scope as $key => $value){
|
||||||
|
$view .= ' <option value="'.$key.'" '.($key==(isset($_SESSION['account_loggedin']) ? $account['address_country'] : 21) ? ' selected' : '').'>'.(${$value} ?? $value).'</option>';
|
||||||
|
}
|
||||||
|
$view .= ' </select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="address_phone">'.$shipping_phone.'</label>
|
||||||
|
<input type="tel" value="'.htmlspecialchars(($account['address_phone'] ?? ''), ENT_QUOTES).'" name="address_phone" id="address_phone" placeholder="'.$shipping_phone.'" class="form-field">
|
||||||
|
|
||||||
|
<div class="step-buttons">
|
||||||
|
<button type="button" class="btn-back" onclick="goToStep(2)">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M12.5 15L7.5 10L12.5 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
'.($back_text ?? 'Back').'
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn-continue" onclick="goToStep(4)">
|
||||||
|
'.($continue_text ?? 'Continue to Review').'
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M7.5 15L12.5 10L7.5 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- STEP 4: Order Review -->
|
||||||
|
<div class="step-section" id="step-4" data-step="4">
|
||||||
|
<div class="step-header" onclick="editStep(4)">
|
||||||
|
<div class="step-header-content">
|
||||||
|
<div class="step-badge">4</div>
|
||||||
|
<h2 class="step-title">'.($step_review ?? 'Review Order').'</h2>
|
||||||
|
</div>
|
||||||
|
<div class="step-edit">'.($edit_text ?? 'Edit').'</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step-content">
|
||||||
|
|
||||||
|
<h2>'.$h2_shoppingcart.'</h2>
|
||||||
|
|
||||||
|
<table class="cart-table">';
|
||||||
|
foreach($products_in_cart['cart_details']['products'] as $product){
|
||||||
|
$view .= ' <tr>
|
||||||
|
<td class="cart-img"><img src="'.img_url.$product['meta']['img'].'" width="50" height="50" alt="'.$product['meta']['name'].'"></td>
|
||||||
|
<td class="cart-info">'.$product['quantity'].' × '.$product['meta']['name'].'</td>
|
||||||
|
<td class="cart-price">'.currency_code.''.number_format($product['options_price'] * $product['quantity'],2).'</td>
|
||||||
|
</tr>';
|
||||||
|
}
|
||||||
|
$view .= ' </table>
|
||||||
|
|
||||||
|
<div class="collapsible-section discount-section">
|
||||||
|
<button type="button" class="collapsible-header discount-header" onclick="toggleCollapsible(this)">
|
||||||
|
<span>'.$discount_label.'</span>
|
||||||
|
<svg class="collapsible-icon" width="20" height="20" viewBox="0 0 20 20">
|
||||||
|
<path d="M5 7.5L10 12.5L15 7.5" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="collapsible-content">
|
||||||
|
<div class="discount-input-wrapper">
|
||||||
|
<input type="text" class="ajax-update form-field" name="discount_code" placeholder="'.$discount_label.'" value="'.(isset($_SESSION['discount']) ? $_SESSION['discount'] : '').'">
|
||||||
|
</div>
|
||||||
|
<span class="discount-result">';
|
||||||
|
if (isset($_SESSION['discount'], $products_in_cart['totals']['discounttotal'])){
|
||||||
|
$view .= $products_in_cart['totals']['discount_message'];
|
||||||
|
}
|
||||||
|
$view .= ' </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="shipping-methods-wrapper" id="shipping-method-section">';
|
||||||
|
|
||||||
|
if (isset($shipping_methods) && count($shipping_methods) > 0){
|
||||||
|
$view .= ' <h3 class="shipping-title">'.$h3_shipping_method.' *</h3>
|
||||||
|
<div class="shipping-methods">';
|
||||||
|
|
||||||
|
foreach($shipping_methods as $method){
|
||||||
|
$view .= ' <label class="shipping-method">
|
||||||
|
<input type="radio" class="ajax-update" id="sm'.$method['id'].'" name="shipping_method" value="'.$method['id'].'" required'.(($checkout_input['selected_shipment_method']==$method['id'] || count($shipping_methods) == 1) ? ' checked':'').'>
|
||||||
|
<span class="shipping-info">
|
||||||
|
<span class="shipping-name">'.$method['name'].'</span>
|
||||||
|
<span class="shipping-price">'.currency_code.''.number_format($method['price'], 2).'</span>
|
||||||
|
</span>
|
||||||
|
</label>';
|
||||||
|
}
|
||||||
|
$view .= ' </div>';
|
||||||
|
|
||||||
|
}
|
||||||
|
$view .= ' </div>
|
||||||
|
|
||||||
|
<div class="order-summary">
|
||||||
|
<div class="summary-row">
|
||||||
|
<span>'.$total_subtotal.'</span>
|
||||||
|
<span class="summary-value">'.currency_code.''.number_format($subtotal,2).'</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="summary-row">
|
||||||
<span>'.$total_shipping.'</span>
|
<span>'.$total_shipping.'</span>
|
||||||
<span>'.currency_code.''.number_format($shippingtotal,2).'</span>
|
<span class="summary-value">'.currency_code.''.number_format($shippingtotal,2).'</span>
|
||||||
</div>';
|
</div>';
|
||||||
|
|
||||||
if ($discounttotal > 0){
|
if ($discounttotal > 0){
|
||||||
$view .= '<div class="discount">
|
$view .= ' <div class="summary-row discount-row">
|
||||||
<span>'.$total_discount.'</span>
|
<span>'.$total_discount.'</span>
|
||||||
<span>-'.currency_code.''.number_format(round($discounttotal, 1),2).'</span>
|
<span class="summary-value">-'.currency_code.''.number_format(round($discounttotal, 1),2).'</span>
|
||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($taxtotal > 0){
|
if ($taxtotal > 0){
|
||||||
$view .= '<div class="vat">
|
$view .= ' <div class="summary-row">
|
||||||
<span>'.($tax_text ?? 'VAT').' <span class="alt">('.$tax_rate.')</span></span>
|
<span>'.($tax_text ?? 'VAT').' <span class="tax-rate">('.$tax_rate.')</span></span>
|
||||||
<span>'.currency_code.''.number_format($taxtotal,2).'</span>
|
<span class="summary-value">'.currency_code.''.number_format($taxtotal,2).'</span>
|
||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
$view .= ' </div>
|
$view .= ' </div>
|
||||||
<div class="total">
|
|
||||||
<span>'.$total_total.' <span class="alt">'.$total_total_note.'</span></span><span>'.currency_code.''.number_format($total,2).'</span>
|
<div class="order-total">
|
||||||
</div>
|
<span class="total-label">'.$total_total.' <span class="total-note">'.$total_total_note.'</span></span>
|
||||||
<div class="summary">
|
<span class="total-amount">'.currency_code.''.number_format($total,2).'</span>
|
||||||
<div class="subtotal">
|
|
||||||
<span>
|
|
||||||
<input type="checkbox" id="consent" name="consent_comms" value="1">'.$order_consent_1.'</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="subtotal">
|
|
||||||
<span>
|
|
||||||
<input type="checkbox" id="consent" name="consent" value="1" required>'.$order_consent_2.' <a href="'.$terms_link.'" target="_blank">'.$order_consent_3.'</a> '.$order_consent_4.' <a href="'.$privacy_link.'" target="_blank">'.$order_consent_5.'</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="consent-section" id="consent-section" style="">
|
||||||
<button type="submit" name="checkout" class="checkout_btn">'.$btn_place_order.'</button>
|
<label class="consent-checkbox">
|
||||||
|
<input type="checkbox" id="consent_comms" name="consent_comms" value="1">
|
||||||
|
<span class="consent-text">'.$order_consent_1.'</span>
|
||||||
|
</label>
|
||||||
|
<label class="consent-checkbox required">
|
||||||
|
<input type="checkbox" id="consent" name="consent" value="1" required>
|
||||||
|
<span class="consent-text">'.$order_consent_2.' * <a href="'.$terms_link.'" target="_blank">'.$order_consent_3.'</a> '.$order_consent_4.' <a href="'.$privacy_link.'" target="_blank">'.$order_consent_5.'</a></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" name="checkout" class="checkout-btn" id="final-checkout-btn">
|
||||||
|
<span>'.$btn_place_order.'</span>
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M7.5 15L12.5 10L7.5 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="step-buttons">
|
||||||
|
<button type="button" class="btn-back" onclick="goToStep(3)">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M12.5 15L7.5 10L12.5 5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
'.($back_text ?? 'Back').'
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -568,7 +780,314 @@ $view .= ' </div>
|
|||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>';
|
</div>
|
||||||
|
';
|
||||||
|
|
||||||
|
echo '<style>
|
||||||
|
/* Sticky step buttons for mobile - CSS solution like cart.php and product.php */
|
||||||
|
.step-buttons {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.step-buttons {
|
||||||
|
position: fixed !important;
|
||||||
|
left: 0 !important;
|
||||||
|
right: 0 !important;
|
||||||
|
bottom: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
z-index: 1000 !important;
|
||||||
|
background: #fff !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 1rem !important;
|
||||||
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.15) !important;
|
||||||
|
display: flex !important;
|
||||||
|
gap: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add padding at bottom for sticky buttons */
|
||||||
|
.step-section.active .step-content {
|
||||||
|
padding-bottom: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure buttons take full width on mobile */
|
||||||
|
.step-buttons .btn-back,
|
||||||
|
.step-buttons .btn-continue {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When only one button on step 1, make container and button full orange background */
|
||||||
|
#step-1 .step-buttons {
|
||||||
|
background: var(--color-primary) !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#step-1 .step-buttons .btn-continue {
|
||||||
|
background-color: var(--color-primary) !important;
|
||||||
|
color: white !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 1rem !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add scroll margin to step sections for mobile */
|
||||||
|
.step-section {
|
||||||
|
scroll-margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-steps {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make checkout button sticky on step 4 */
|
||||||
|
#step-4 .checkout-btn {
|
||||||
|
position: fixed !important;
|
||||||
|
left: 0 !important;
|
||||||
|
right: 0 !important;
|
||||||
|
bottom: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
z-index: 1000 !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 1rem !important;
|
||||||
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.15) !important;
|
||||||
|
background-color: var(--color-primary) !important;
|
||||||
|
color: white !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide step-buttons on step 4 since checkout button is sticky */
|
||||||
|
#step-4 .step-buttons {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let currentStep = 1;
|
||||||
|
let maxStepReached = 1;
|
||||||
|
|
||||||
|
function goToStep(step) {
|
||||||
|
// Only validate if moving forward to a new step
|
||||||
|
if (step > maxStepReached && !validateStep(currentStep)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save current step data
|
||||||
|
saveStepSummary(currentStep);
|
||||||
|
|
||||||
|
// Update max step reached
|
||||||
|
if (step > maxStepReached) {
|
||||||
|
maxStepReached = step;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide all steps
|
||||||
|
document.querySelectorAll(".step-section").forEach(s => {
|
||||||
|
s.classList.remove("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mark all steps up to maxStepReached as completed
|
||||||
|
document.querySelectorAll(".step-section").forEach((s, i) => {
|
||||||
|
if (i < maxStepReached - 1) {
|
||||||
|
s.classList.add("completed");
|
||||||
|
} else if (i === maxStepReached - 1) {
|
||||||
|
s.classList.remove("completed");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show target step
|
||||||
|
const targetStep = document.getElementById("step-" + step);
|
||||||
|
if (targetStep) {
|
||||||
|
targetStep.classList.add("active");
|
||||||
|
targetStep.classList.remove("completed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update progress
|
||||||
|
document.querySelectorAll(".progress-step").forEach((s, i) => {
|
||||||
|
if (i < step - 1) {
|
||||||
|
s.classList.add("completed");
|
||||||
|
s.classList.remove("active");
|
||||||
|
} else if (i === step - 1) {
|
||||||
|
s.classList.add("active");
|
||||||
|
s.classList.remove("completed");
|
||||||
|
} else if (i < maxStepReached) {
|
||||||
|
s.classList.add("completed");
|
||||||
|
} else {
|
||||||
|
s.classList.remove("active", "completed");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
currentStep = step;
|
||||||
|
|
||||||
|
// Scroll to guide user through the step
|
||||||
|
setTimeout(() => {
|
||||||
|
const targetStep = document.getElementById("step-" + step);
|
||||||
|
if (targetStep) {
|
||||||
|
// Close any active keyboard
|
||||||
|
if (document.activeElement) {
|
||||||
|
document.activeElement.blur();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll with explicit position calculation
|
||||||
|
const rect = targetStep.getBoundingClientRect();
|
||||||
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||||
|
const offset = 10; // Small offset from top
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: scrollTop + rect.top - offset,
|
||||||
|
behavior: "smooth"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
function editStep(step) {
|
||||||
|
// Allow navigating to any step that has been reached
|
||||||
|
if (step <= maxStepReached) {
|
||||||
|
goToStep(step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateStep(step) {
|
||||||
|
const stepElement = document.getElementById("step-" + step);
|
||||||
|
const inputs = stepElement.querySelectorAll("input[required], select[required]");
|
||||||
|
|
||||||
|
// Remove previous error highlights
|
||||||
|
stepElement.querySelectorAll(".error-highlight").forEach(el => {
|
||||||
|
el.classList.remove("error-highlight");
|
||||||
|
});
|
||||||
|
|
||||||
|
let firstInvalidField = null;
|
||||||
|
let hasErrors = false;
|
||||||
|
|
||||||
|
for (let input of inputs) {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
// Add visual highlight for Step 3
|
||||||
|
if (step === 3) {
|
||||||
|
input.classList.add("error-highlight");
|
||||||
|
if (!firstInvalidField) {
|
||||||
|
firstInvalidField = input;
|
||||||
|
}
|
||||||
|
hasErrors = true;
|
||||||
|
} else {
|
||||||
|
input.reportValidity();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For Step 3, scroll to first error and show validation message
|
||||||
|
if (step === 3 && hasErrors) {
|
||||||
|
if (firstInvalidField) {
|
||||||
|
firstInvalidField.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||||
|
firstInvalidField.reportValidity();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional validation for payment method
|
||||||
|
if (step === 2) {
|
||||||
|
const paymentSelected = document.querySelector("input[name=\"method\"]:checked");
|
||||||
|
if (!paymentSelected) {
|
||||||
|
alert("'.($select_payment ?? 'Please select a payment method').'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveStepSummary(step) {
|
||||||
|
// Step summaries removed - validation handled by form
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleCollapsible(button) {
|
||||||
|
const section = button.closest(".collapsible-section");
|
||||||
|
const content = section.querySelector(".collapsible-content");
|
||||||
|
const icon = button.querySelector(".collapsible-icon");
|
||||||
|
|
||||||
|
section.classList.toggle("active");
|
||||||
|
|
||||||
|
if (section.classList.contains("active")) {
|
||||||
|
content.style.maxHeight = content.scrollHeight + "px";
|
||||||
|
icon.style.transform = "rotate(180deg)";
|
||||||
|
} else {
|
||||||
|
content.style.maxHeight = "0";
|
||||||
|
icon.style.transform = "rotate(0deg)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-expand discount if already applied
|
||||||
|
window.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const discountValue = document.querySelector("input[name=\"discount_code\"]").value;
|
||||||
|
if (discountValue) {
|
||||||
|
const discountButton = document.querySelector(".discount-header");
|
||||||
|
if (discountButton) {
|
||||||
|
toggleCollapsible(discountButton);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: Enter key on email field
|
||||||
|
const emailField = document.getElementById("email");
|
||||||
|
if (emailField) {
|
||||||
|
emailField.addEventListener("keypress", function(e) {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
goToStep(2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Auto-advance after payment method selection
|
||||||
|
const paymentMethods = document.querySelectorAll("input[name=\"method\"]");
|
||||||
|
paymentMethods.forEach(function(radio) {
|
||||||
|
radio.addEventListener("change", function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
goToStep(3);
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Form submission validation
|
||||||
|
const checkoutForm = document.getElementById("checkout-form");
|
||||||
|
if (checkoutForm) {
|
||||||
|
checkoutForm.addEventListener("submit", function(e) {
|
||||||
|
// Ensure user is on step 4
|
||||||
|
if (currentStep !== 4) {
|
||||||
|
e.preventDefault();
|
||||||
|
alert("Please complete all steps before placing your order.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate all required fields exist
|
||||||
|
const requiredFields = ["method", "first_name", "last_name", "address_street", "address_city", "address_zip", "address_country"];
|
||||||
|
for (let field of requiredFields) {
|
||||||
|
const input = checkoutForm.querySelector("[name=\"" + field + "\"]");
|
||||||
|
if (!input || !input.value) {
|
||||||
|
e.preventDefault();
|
||||||
|
alert("Please complete all required fields.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate consent checkbox
|
||||||
|
const consentCheckbox = document.getElementById("consent");
|
||||||
|
if (consentCheckbox && !consentCheckbox.checked) {
|
||||||
|
e.preventDefault();
|
||||||
|
consentCheckbox.classList.add("error-highlight");
|
||||||
|
consentCheckbox.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||||
|
setTimeout(() => {
|
||||||
|
consentCheckbox.reportValidity();
|
||||||
|
}, 300);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
';
|
||||||
|
|
||||||
$view .= template_footer();
|
$view .= template_footer();
|
||||||
|
|
||||||
|
|||||||
BIN
custom/assets/favicon/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
custom/assets/favicon/favicon-96x96.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
custom/assets/favicon/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
3
custom/assets/favicon/favicon.svg
Normal file
|
After Width: | Height: | Size: 24 KiB |
21
custom/assets/favicon/site.webmanifest
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "MyWebSite",
|
||||||
|
"short_name": "MySite",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
BIN
custom/assets/favicon/web-app-manifest-192x192.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
custom/assets/favicon/web-app-manifest-512x512.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
71
custom/assets/wero.svg
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" data-name="Layer 1" viewBox="0 0 480 182">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 {
|
||||||
|
fill: url(#linear-gradient);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-1, .cls-2, .cls-3, .cls-4, .cls-5, .cls-6, .cls-7, .cls-8, .cls-9 {
|
||||||
|
stroke-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-2, .cls-3 {
|
||||||
|
fill-rule: evenodd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-2, .cls-6 {
|
||||||
|
fill: #232323;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-3, .cls-8 {
|
||||||
|
fill: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-4 {
|
||||||
|
fill: url(#linear-gradient-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-5 {
|
||||||
|
fill: #1d1c1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-7 {
|
||||||
|
fill: #c06;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-9 {
|
||||||
|
fill: #fff48d;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<linearGradient id="linear-gradient" x1="352.72" y1="95.3" x2="330.2" y2="67.73" gradientTransform="translate(0 184) scale(1 -1)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop offset=".02" stop-color="#1d1c1c" stop-opacity="0"></stop>
|
||||||
|
<stop offset=".68" stop-color="#1d1c1c"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="linear-gradient-2" x1="313.44" y1="89.45" x2="336.52" y2="112.26" gradientTransform="translate(0 184) scale(1 -1)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop offset=".02" stop-color="#1d1c1c" stop-opacity="0"></stop>
|
||||||
|
<stop offset=".68" stop-color="#1d1c1c"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect class="cls-9" x="0" width="480" height="182" rx="13" ry="13"></rect>
|
||||||
|
<g>
|
||||||
|
<path class="cls-8" d="M11.02,22.87v136.4c0,6.53,5.37,11.87,11.93,11.87h81.89c61.91,0,88.74-34.49,88.74-80.25S166.74,11,104.83,11H22.94c-6.56,0-11.93,5.34-11.93,11.87Z"></path>
|
||||||
|
<path class="cls-7" d="M65.83,44.48v100.79h44.07c40.02,0,57.37-22.5,57.37-54.31s-17.36-54.07-57.37-54.07h-36.44c-4.23,0-7.63,3.44-7.63,7.6Z"></path>
|
||||||
|
<path class="cls-2" d="M33.62,160.28h71.21c50.04,0,77.65-24.63,77.65-69.33,0-25.76-10.08-69.03-77.65-69.03H33.62c-6.32,0-11.45,5.1-11.45,11.4v115.57c0,6.29,5.13,11.4,11.45,11.4ZM25.98,33.32c0-4.21,3.4-7.6,7.63-7.6h71.21c27.55,0,73.83,8.49,73.83,65.23,0,42.26-26.24,65.53-73.83,65.53H33.62c-4.23,0-7.63-3.38-7.63-7.6V33.32Z"></path>
|
||||||
|
<path class="cls-3" d="M87.51,76.3c-1.34-.48-2.74-.72-4.26-.72v-.06h-10.09v24.34h10.21c1.81,0,3.38-.36,4.73-.96,1.34-.66,2.45-1.5,3.33-2.58.88-1.08,1.52-2.4,1.98-3.9.41-1.5.64-3.12.64-4.92,0-2.04-.29-3.78-.82-5.28-.58-1.44-1.34-2.7-2.27-3.72-.99-.96-2.1-1.74-3.44-2.22ZM85.12,95.07c-.76.24-1.46.36-2.22.36v.06h-4.61v-15.35h3.73c1.28,0,2.33.18,3.21.54.88.36,1.58.96,2.1,1.62.52.66.93,1.56,1.17,2.52.23.96.35,2.1.35,3.3,0,1.38-.18,2.46-.52,3.42-.35.96-.82,1.68-1.34,2.28-.52.6-1.17,1.02-1.87,1.26Z"></path>
|
||||||
|
<path class="cls-8" d="M115.11,75.59v4.5h-12.49v5.22h11.49v4.14h-11.49v5.94h12.78v4.5h-17.97v-24.34h17.68v.06Z"></path>
|
||||||
|
<path class="cls-3" d="M141.83,99.93l-8.87-24.34h-5.42l-8.93,24.34h5.25l1.87-5.4h8.87l1.81,5.4h5.43ZM130.27,81.58l2.98,8.93h-6.12l3.09-8.93h.06Z"></path>
|
||||||
|
<path class="cls-8" d="M150.29,75.58v19.85h11.55v4.5h-16.74v-24.34h5.19Z"></path>
|
||||||
|
<path class="cls-6" d="M45.35,100.29c6.32,0,11.44-5.12,11.44-11.45s-5.12-11.45-11.44-11.45-11.44,5.12-11.44,11.45,5.12,11.45,11.44,11.45Z"></path>
|
||||||
|
<path class="cls-6" d="M52.16,146.08c-8.86,0-15.96-7.65-15.96-17.05v-13.31c0-4.7,3.55-8.56,8.01-8.56s8.01,3.8,8.01,8.56v30.36h-.06Z"></path>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="cls-5" d="M405.6,91.62c0-13.38,9.52-25.57,25.96-25.57s26.03,12.2,26.03,25.57-9.52,25.57-26.03,25.57c-16.44,0-25.96-12.2-25.96-25.57ZM443.14,91.62c0-6.45-4.25-12.4-11.58-12.4s-11.58,5.96-11.58,12.4,4.32,12.41,11.58,12.41,11.58-5.96,11.58-12.41Z"></path>
|
||||||
|
<path class="cls-5" d="M395.49,101.12c5.48-3.12,8.77-9.08,8.77-15.66,0-9.77-7.06-18.09-18.02-18.09h-23.01v48.51h14.25v-12.4h2.67l8.15,12.4h16.78l-9.59-14.76ZM383.37,92.31h-5.89v-13.72h5.96c3.84,0,6.3,3.12,6.3,6.86s-2.54,6.86-6.37,6.86Z"></path>
|
||||||
|
<path class="cls-5" d="M298.18,67.31l-8.55,28.91-8.34-28.91h-11.35l-8.41,28.91-8.48-28.91h-15.04l17.23,48.42h12.37l8-26.36,7.93,26.36h12.44l17.23-48.42h-15.04Z"></path>
|
||||||
|
<path class="cls-5" d="M334.78,103.91h-.03c-5.33,0-9.07-3.22-10.67-7.48h36.21c.29-1.6.44-3.24.44-4.9,0-13.34-9.49-25.51-25.95-25.52v13.14c5.36.01,9.06,3.23,10.65,7.48h-36.16c-.29,1.6-.44,3.24-.44,4.9,0,13.35,9.5,25.53,25.91,25.53h.03v-13.15Z"></path>
|
||||||
|
<path class="cls-1" d="M334.75,117.05c.56,0,1.11-.02,1.65-.04,3.33-.17,6.36-.85,9.06-1.94,2.7-1.09,5.07-2.6,7.08-4.42,2.02-1.82,3.68-3.95,4.97-6.3,1.17-2.14,2.03-4.45,2.57-6.86h-15.09c-.31.64-.67,1.26-1.08,1.83-.56.79-1.22,1.5-1.97,2.11-.75.62-1.59,1.14-2.51,1.54-.92.4-1.93.68-3.02.83-.53.07-1.08.11-1.65.11-3.39,0-6.14-1.31-8.11-3.36l-9.81,9.92c4.36,4.03,10.41,6.57,17.91,6.57Z"></path>
|
||||||
|
<path class="cls-4" d="M334.75,66c-13.92,0-22.87,8.76-25.26,19.56h15.04c1.8-3.72,5.34-6.42,10.22-6.42,3.89,0,6.91,1.68,8.88,4.22l9.9-10.01c-4.42-4.48-10.78-7.35-18.77-7.35Z"></path>
|
||||||
|
</g>
|
||||||
|
<path class="cls-5" d="M215.61,145c-1.1,0-2-.9-2-2V39c0-1.1.9-2,2-2s2,.9,2,2v104c0,1.1-.9,2-2,2Z"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.9 KiB |
1944
custom/css/main.css
@@ -39,14 +39,14 @@ function template_header($title,$head) {
|
|||||||
if (maintenanceMode){$maintenanceMode = maintenanceMode();} else {$maintenanceMode = '';}
|
if (maintenanceMode){$maintenanceMode = maintenanceMode();} else {$maintenanceMode = '';}
|
||||||
|
|
||||||
$veliti_analytics = '';
|
$veliti_analytics = '';
|
||||||
if (veliti_analytics && $_COOKIE['cookie_consent'] == 'accepted'){
|
if (veliti_analytics && (!isset($_COOKIE['cookie_consent']) || (isset($_COOKIE['cookie_consent']) && $_COOKIE['cookie_consent'] != 'declined'))){
|
||||||
$veliti_analytics = '<script src="'.$base_url.'/lib/analytics/analytics.js"></script>';
|
$veliti_analytics = '<script src="'.base_url.'lib/analytics/analytics.js"></script>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$tag_manager_header = '';
|
$tag_manager_header = '';
|
||||||
$tag_manager_body = '';
|
$tag_manager_body = '';
|
||||||
|
|
||||||
if (isset($_COOKIE['cookie_consent']) && $_COOKIE['cookie_consent'] == 'accepted') {
|
if (!isset($_COOKIE['cookie_consent']) || (isset($_COOKIE['cookie_consent']) && $_COOKIE['cookie_consent'] != 'declined')) {
|
||||||
|
|
||||||
$tag_manager_header = "
|
$tag_manager_header = "
|
||||||
<script>
|
<script>
|
||||||
@@ -70,6 +70,11 @@ $view = '
|
|||||||
<link rel="icon" type="image/png" href="'.base_url.icon_image.'">
|
<link rel="icon" type="image/png" href="'.base_url.icon_image.'">
|
||||||
<link href="'.base_url.'custom/css/main.css" rel="stylesheet" type="text/css">
|
<link href="'.base_url.'custom/css/main.css" rel="stylesheet" type="text/css">
|
||||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.0.0/css/all.css">
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.0.0/css/all.css">
|
||||||
|
<link rel="icon" type="image/png" href="'.base_url.'custom/assets/favicon/favicon-96x96.png" sizes="96x96" />
|
||||||
|
<link rel="shortcut icon" href="'.base_url.'custom/assets/favicon/favicon.ico" />
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="'.base_url.'custom/assets/favicon/apple-touch-icon.png" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="MorvalWatches" />
|
||||||
|
<link rel="manifest" href="'.base_url.'custom/assets/favicon/site.webmanifest" />
|
||||||
'.$head.'
|
'.$head.'
|
||||||
'.$tag_manager_header.'
|
'.$tag_manager_header.'
|
||||||
<script>
|
<script>
|
||||||
@@ -197,6 +202,9 @@ $view = '
|
|||||||
<span class="star-rating">★★★★★</span>
|
<span class="star-rating">★★★★★</span>
|
||||||
'.($header_rating ?? 'Client rate 5.0/5.0').'
|
'.($header_rating ?? 'Client rate 5.0/5.0').'
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="https://www.valuedshops.com/webshop/Morval-Watches_1223642" class="webwinkelkeurPopup" title="WebwinkelKeur" target="_blank"><img src="https://dashboard.webwinkelkeur.nl/banners/5/1223642/1767769194000.svg" width="18" height="18" alt="WebwinkelKeur Banner"></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
@@ -599,10 +607,11 @@ function template_footer() {
|
|||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="payment-methods">
|
<div class="payment-methods">
|
||||||
<img src="'.base_url.'custom/assets/iDEAL.png" alt="iDeal" class="payment-method">
|
<img src="'.base_url.'custom/assets/wero.svg" alt="iDeal" class="payment-method">
|
||||||
<img src="'.base_url.'custom/assets/mastercard.png" alt="Mastercard" class="payment-method">
|
<img src="'.base_url.'custom/assets/mastercard.png" alt="Mastercard" class="payment-method">
|
||||||
<img src="'.base_url.'custom/assets/visa.png" alt="Visa" class="payment-method">
|
<img src="'.base_url.'custom/assets/visa.png" alt="Visa" class="payment-method">
|
||||||
<img src="'.base_url.'custom/assets/paypal.png" alt="Pay Pal" class="payment-method">
|
<img src="'.base_url.'custom/assets/paypal.png" alt="Pay Pal" class="payment-method">
|
||||||
|
<a href="https://www.valuedshops.com/webshop/Morval-Watches_1223642" class="webwinkelkeurPopup" title="WebwinkelKeur" target="_blank"><img src="https://dashboard.webwinkelkeur.nl/banners/5/1223642/1767769194000.svg" width="32" height="32" alt="WebwinkelKeur Banner"></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-bottom">
|
<div class="footer-bottom">
|
||||||
@@ -879,7 +888,7 @@ EOT;
|
|||||||
|
|
||||||
// Cookie consent banner
|
// Cookie consent banner
|
||||||
function cookie_consent() {
|
function cookie_consent() {
|
||||||
if (isset($_COOKIE['cookie_consent']) && $_COOKIE['cookie_consent'] == 'accepted') {
|
if (isset($_COOKIE['cookie_consent'])) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,8 +906,8 @@ function cookie_consent() {
|
|||||||
location.reload();
|
location.reload();
|
||||||
};
|
};
|
||||||
document.getElementById("decline-cookies").onclick = function() {
|
document.getElementById("decline-cookies").onclick = function() {
|
||||||
document.cookie = "cookie_consent=declined; path=/; max-age=15768000";
|
document.cookie = "cookie_consent=declined; path=/; max-age=432000";
|
||||||
document.getElementById("cookie-consent-banner").style.display = "none";
|
location.reload();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
';
|
';
|
||||||
|
|||||||
@@ -112,6 +112,77 @@ defined(security_key) or exit;
|
|||||||
color: var(--color-dark-blue);
|
color: var(--color-dark-blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return Request Section Styling */
|
||||||
|
.return-request-section {
|
||||||
|
background-color: var(--color-lighter-gray);
|
||||||
|
border: 2px solid var(--color-primary);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 30px;
|
||||||
|
margin: 40px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: var(--color-white);
|
||||||
|
padding: 10px 24px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease, transform 0.2s ease;
|
||||||
|
box-shadow: 0 2px 4px rgba(255, 111, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn:hover {
|
||||||
|
background-color: var(--color-primary-dark);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 8px rgba(255, 111, 0, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
background-color: var(--color-primary-darker);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-success {
|
||||||
|
color: var(--color-green);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-success.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 350px;
|
||||||
|
padding: 15px;
|
||||||
|
border: 2px solid var(--color-gray);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
resize: vertical;
|
||||||
|
background-color: var(--color-white);
|
||||||
|
color: var(--color-text-dark);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.content-section {
|
.content-section {
|
||||||
padding: 40px 0;
|
padding: 40px 0;
|
||||||
@@ -157,6 +228,31 @@ defined(security_key) or exit;
|
|||||||
.content-section h2 + ul {
|
.content-section h2 + ul {
|
||||||
margin-left: 25px;
|
margin-left: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.return-request-section {
|
||||||
|
padding: 20px;
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn-container {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-textarea {
|
||||||
|
min-height: 300px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 576px) {
|
||||||
@@ -207,6 +303,22 @@ defined(security_key) or exit;
|
|||||||
.content-section h2 + ul {
|
.content-section h2 + ul {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.return-request-section {
|
||||||
|
padding: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-textarea {
|
||||||
|
min-height: 280px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -223,7 +335,86 @@ defined(security_key) or exit;
|
|||||||
|
|
||||||
<h2>Register a Return</h2>
|
<h2>Register a Return</h2>
|
||||||
<p>To exercise this right, you can contact us via <a href="mailto:info@morvalwatches.com">info@morvalwatches.com</a>. We will then refund the order amount within 14 days after registering your return, provided the product has been received back in good condition.</p>
|
<p>To exercise this right, you can contact us via <a href="mailto:info@morvalwatches.com">info@morvalwatches.com</a>. We will then refund the order amount within 14 days after registering your return, provided the product has been received back in good condition.</p>
|
||||||
|
|
||||||
|
<h2>Making a Return</h2>
|
||||||
|
<p>Use the template below to register your return. Click the "Copy Template" button, insert in your email client, fill in your details and send it to <a href="mailto:info@morvalwatches.com">info@morvalwatches.com</a>.</p>
|
||||||
|
|
||||||
|
<!-- Return Request Section with Template Always Visible -->
|
||||||
|
<div class="return-request-section">
|
||||||
|
<textarea class="template-textarea" id="templateText" readonly>I would like to register a return for my recent order.
|
||||||
|
|
||||||
|
ORDER DETAILS:
|
||||||
|
Order Number: [Please enter your order number]
|
||||||
|
Order Date: [Please enter the date you placed your order]
|
||||||
|
Product(s): [Please list the product(s) you wish to return]
|
||||||
|
|
||||||
|
REASON FOR RETURN:
|
||||||
|
[Please explain your reason for returning the product(s)]
|
||||||
|
|
||||||
|
CUSTOMER INFORMATION:
|
||||||
|
Name: [Your full name]
|
||||||
|
Email: [Your email address]
|
||||||
|
Phone: [Your phone number]
|
||||||
|
Return Address: [Your full address where the product should be collected or returned to]
|
||||||
|
|
||||||
|
I confirm that I am returning the product(s) within 14 days of receipt, with all supplied accessories, in their original condition and packaging.
|
||||||
|
|
||||||
|
Please confirm receipt of this return request and provide instructions for the return shipping.
|
||||||
|
|
||||||
|
Best regards,
|
||||||
|
[Your name]</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="template-header">
|
||||||
|
<div class="copy-btn-container">
|
||||||
|
<button class="copy-btn" id="copyBtn">Copy Template</button>
|
||||||
|
<span class="copy-success" id="copySuccess">✓ Copied!</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Returnadres</h2>
|
||||||
|
<p>
|
||||||
|
<?php echo company_name; ?> <br>
|
||||||
|
<?php echo company_adres; ?><br>
|
||||||
|
<?php echo company_postal . ' ' . footer_city; ?><br>
|
||||||
|
<?php echo footer_country; ?>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Get elements
|
||||||
|
const copyBtn = document.getElementById('copyBtn');
|
||||||
|
const templateText = document.getElementById('templateText');
|
||||||
|
const copySuccess = document.getElementById('copySuccess');
|
||||||
|
|
||||||
|
// Copy template to clipboard
|
||||||
|
copyBtn.addEventListener('click', function() {
|
||||||
|
templateText.select();
|
||||||
|
templateText.setSelectionRange(0, 99999); // For mobile devices
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
|
||||||
|
// Show success message
|
||||||
|
copySuccess.classList.add('show');
|
||||||
|
|
||||||
|
// Change button text temporarily
|
||||||
|
const originalText = copyBtn.textContent;
|
||||||
|
copyBtn.textContent = 'Copied!';
|
||||||
|
|
||||||
|
// Reset after 2 seconds
|
||||||
|
setTimeout(function() {
|
||||||
|
copySuccess.classList.remove('show');
|
||||||
|
copyBtn.textContent = originalText;
|
||||||
|
}, 2000);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy text: ', err);
|
||||||
|
alert('Failed to copy template. Please select and copy manually.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deselect text
|
||||||
|
window.getSelection().removeAllRanges();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<?=template_footer()?>
|
<?=template_footer()?>
|
||||||
|
|||||||
@@ -232,4 +232,43 @@ $cookie_text = 'Cookies';
|
|||||||
$contact_text = 'Kontakt';
|
$contact_text = 'Kontakt';
|
||||||
$returns_text = 'Rückgaberecht';
|
$returns_text = 'Rückgaberecht';
|
||||||
$complaint_text = 'Beschwerden';
|
$complaint_text = 'Beschwerden';
|
||||||
|
|
||||||
|
// Payment Status Messages
|
||||||
|
$payment_success_title = "Zahlung erfolgreich!";
|
||||||
|
$payment_success_message = "Ihre Bestellung wurde bestätigt und eine E-Mail-Bestätigung wurde an Ihre E-Mail-Adresse gesendet.";
|
||||||
|
|
||||||
|
$payment_pending_title = "Zahlung ausstehend";
|
||||||
|
$payment_pending_message = "Ihre Bestellung ist eingegangen und wartet auf Zahlungsbestätigung. Sie erhalten eine E-Mail, sobald die Zahlung bestätigt wurde.";
|
||||||
|
|
||||||
|
$payment_processing_title = "Zahlung wird verarbeitet...";
|
||||||
|
$payment_processing_message = "Bitte warten Sie, während wir Ihre Zahlung bestätigen. Dies kann einige Momente dauern.";
|
||||||
|
|
||||||
|
$payment_failed_title = "Zahlung nicht erfolgreich";
|
||||||
|
$payment_failed_message = "Leider konnte Ihre Zahlung nicht verarbeitet werden. Bitte versuchen Sie es erneut oder wählen Sie eine andere Zahlungsmethode.";
|
||||||
|
|
||||||
|
// Button Labels
|
||||||
|
$order_number_label = "Bestellnummer";
|
||||||
|
$continue_shopping_btn = "Weiter einkaufen";
|
||||||
|
$return_to_checkout_btn = "Zurück zur Kasse";
|
||||||
|
$view_cart_btn = "Warenkorb ansehen";
|
||||||
|
|
||||||
|
// Checkout Step Labels
|
||||||
|
$step_contact = "Kontakt";
|
||||||
|
$step_payment = "Zahlung";
|
||||||
|
$step_shipping = "Versand";
|
||||||
|
$step_review = "Überprüfung";
|
||||||
|
|
||||||
|
// Checkout Button Text
|
||||||
|
$continue_text = "Weiter";
|
||||||
|
$back_text = "Zurück";
|
||||||
|
$edit_text = "Bearbeiten";
|
||||||
|
|
||||||
|
// Checkout Additional Labels
|
||||||
|
$contact_information = "Kontaktinformationen";
|
||||||
|
$customer_email = "E-Mail";
|
||||||
|
$account_optional = "(Optional)";
|
||||||
|
$select_payment = "Bitte wählen Sie eine Zahlungsmethode";
|
||||||
|
$ship_to = "Versand nach";
|
||||||
|
$bank_transfer = "Banküberweisung";
|
||||||
|
$card_payment = "Kredit-/Debitkarte";
|
||||||
?>
|
?>
|
||||||
@@ -232,4 +232,43 @@ $cookie_text = 'Cookies';
|
|||||||
$contact_text = 'Contacto';
|
$contact_text = 'Contacto';
|
||||||
$returns_text = 'Política de Devoluciones';
|
$returns_text = 'Política de Devoluciones';
|
||||||
$complaint_text = 'Quejas';
|
$complaint_text = 'Quejas';
|
||||||
|
|
||||||
|
// Payment Status Messages
|
||||||
|
$payment_success_title = "¡Pago exitoso!";
|
||||||
|
$payment_success_message = "Su pedido ha sido confirmado y se ha enviado un correo electrónico de confirmación a su dirección de correo electrónico.";
|
||||||
|
|
||||||
|
$payment_pending_title = "Pago pendiente";
|
||||||
|
$payment_pending_message = "Su pedido ha sido recibido y está esperando la confirmación del pago. Recibirá un correo electrónico una vez que se confirme el pago.";
|
||||||
|
|
||||||
|
$payment_processing_title = "Procesando pago...";
|
||||||
|
$payment_processing_message = "Por favor espere mientras confirmamos su pago. Esto puede tardar unos momentos.";
|
||||||
|
|
||||||
|
$payment_failed_title = "Pago no exitoso";
|
||||||
|
$payment_failed_message = "Desafortunadamente, su pago no pudo ser procesado. Por favor intente nuevamente o elija un método de pago diferente.";
|
||||||
|
|
||||||
|
// Button Labels
|
||||||
|
$order_number_label = "Número de pedido";
|
||||||
|
$continue_shopping_btn = "Continuar comprando";
|
||||||
|
$return_to_checkout_btn = "Volver al pago";
|
||||||
|
$view_cart_btn = "Ver carrito";
|
||||||
|
|
||||||
|
// Checkout Step Labels
|
||||||
|
$step_contact = "Contacto";
|
||||||
|
$step_payment = "Pago";
|
||||||
|
$step_shipping = "Envío";
|
||||||
|
$step_review = "Revisar";
|
||||||
|
|
||||||
|
// Checkout Button Text
|
||||||
|
$continue_text = "Continuar";
|
||||||
|
$back_text = "Atrás";
|
||||||
|
$edit_text = "Editar";
|
||||||
|
|
||||||
|
// Checkout Additional Labels
|
||||||
|
$contact_information = "Información de Contacto";
|
||||||
|
$customer_email = "Correo electrónico";
|
||||||
|
$account_optional = "(Opcional)";
|
||||||
|
$select_payment = "Por favor seleccione un método de pago";
|
||||||
|
$ship_to = "Enviar a";
|
||||||
|
$bank_transfer = "Transferencia Bancaria";
|
||||||
|
$card_payment = "Tarjeta de Crédito / Débito";
|
||||||
?>
|
?>
|
||||||
@@ -231,4 +231,43 @@ $cookie_text = 'Cookies';
|
|||||||
$contact_text = 'Contact';
|
$contact_text = 'Contact';
|
||||||
$returns_text = 'Politique de Retour';
|
$returns_text = 'Politique de Retour';
|
||||||
$complaint_text = 'Réclamations';
|
$complaint_text = 'Réclamations';
|
||||||
|
|
||||||
|
// Payment Status Messages
|
||||||
|
$payment_success_title = "Paiement réussi !";
|
||||||
|
$payment_success_message = "Votre commande a été confirmée et un e-mail de confirmation a été envoyé à votre adresse e-mail.";
|
||||||
|
|
||||||
|
$payment_pending_title = "Paiement en attente";
|
||||||
|
$payment_pending_message = "Votre commande a été reçue et attend la confirmation du paiement. Vous recevrez un e-mail une fois le paiement confirmé.";
|
||||||
|
|
||||||
|
$payment_processing_title = "Traitement du paiement...";
|
||||||
|
$payment_processing_message = "Veuillez patienter pendant que nous confirmons votre paiement. Cela peut prendre quelques instants.";
|
||||||
|
|
||||||
|
$payment_failed_title = "Paiement non réussi";
|
||||||
|
$payment_failed_message = "Malheureusement, votre paiement n'a pas pu être traité. Veuillez réessayer ou choisir un autre moyen de paiement.";
|
||||||
|
|
||||||
|
// Button Labels
|
||||||
|
$order_number_label = "Numéro de commande";
|
||||||
|
$continue_shopping_btn = "Continuer les achats";
|
||||||
|
$return_to_checkout_btn = "Retour au paiement";
|
||||||
|
$view_cart_btn = "Voir le panier";
|
||||||
|
|
||||||
|
// Checkout Step Labels
|
||||||
|
$step_contact = "Contact";
|
||||||
|
$step_payment = "Paiement";
|
||||||
|
$step_shipping = "Livraison";
|
||||||
|
$step_review = "Révision";
|
||||||
|
|
||||||
|
// Checkout Button Text
|
||||||
|
$continue_text = "Continuer";
|
||||||
|
$back_text = "Retour";
|
||||||
|
$edit_text = "Modifier";
|
||||||
|
|
||||||
|
// Checkout Additional Labels
|
||||||
|
$contact_information = "Informations de Contact";
|
||||||
|
$customer_email = "Email";
|
||||||
|
$account_optional = "(Facultatif)";
|
||||||
|
$select_payment = "Veuillez sélectionner un mode de paiement";
|
||||||
|
$ship_to = "Expédier à";
|
||||||
|
$bank_transfer = "Virement Bancaire";
|
||||||
|
$card_payment = "Carte de Crédit / Débit";
|
||||||
?>
|
?>
|
||||||
@@ -19,4 +19,43 @@ $order_consent_3 = 'Termini e condizioni';
|
|||||||
$order_consent_4 = 'e la';
|
$order_consent_4 = 'e la';
|
||||||
$order_consent_5 = 'Informativa sulla privacy';
|
$order_consent_5 = 'Informativa sulla privacy';
|
||||||
$btn_place_order = 'Acquista';
|
$btn_place_order = 'Acquista';
|
||||||
|
|
||||||
|
// Payment Status Messages
|
||||||
|
$payment_success_title = "Pagamento riuscito!";
|
||||||
|
$payment_success_message = "Il tuo ordine è stato confermato ed è stata inviata un'email di conferma al tuo indirizzo email.";
|
||||||
|
|
||||||
|
$payment_pending_title = "Pagamento in sospeso";
|
||||||
|
$payment_pending_message = "Il tuo ordine è stato ricevuto ed è in attesa di conferma del pagamento. Riceverai un'email una volta confermato il pagamento.";
|
||||||
|
|
||||||
|
$payment_processing_title = "Elaborazione pagamento...";
|
||||||
|
$payment_processing_message = "Attendi mentre confermiamo il tuo pagamento. Potrebbero essere necessari alcuni istanti.";
|
||||||
|
|
||||||
|
$payment_failed_title = "Pagamento non riuscito";
|
||||||
|
$payment_failed_message = "Purtroppo il tuo pagamento non è stato elaborato. Riprova o scegli un metodo di pagamento diverso.";
|
||||||
|
|
||||||
|
// Button Labels
|
||||||
|
$order_number_label = "Numero d'ordine";
|
||||||
|
$continue_shopping_btn = "Continua gli acquisti";
|
||||||
|
$return_to_checkout_btn = "Torna al checkout";
|
||||||
|
$view_cart_btn = "Visualizza carrello";
|
||||||
|
|
||||||
|
// Checkout Step Labels
|
||||||
|
$step_contact = "Contatto";
|
||||||
|
$step_payment = "Pagamento";
|
||||||
|
$step_shipping = "Spedizione";
|
||||||
|
$step_review = "Revisione";
|
||||||
|
|
||||||
|
// Checkout Button Text
|
||||||
|
$continue_text = "Continua";
|
||||||
|
$back_text = "Indietro";
|
||||||
|
$edit_text = "Modifica";
|
||||||
|
|
||||||
|
// Checkout Additional Labels
|
||||||
|
$contact_information = "Informazioni di Contatto";
|
||||||
|
$customer_email = "Email";
|
||||||
|
$account_optional = "(Facoltativo)";
|
||||||
|
$select_payment = "Seleziona un metodo di pagamento";
|
||||||
|
$ship_to = "Spedire a";
|
||||||
|
$bank_transfer = "Bonifico Bancario";
|
||||||
|
$card_payment = "Carta di Credito / Debito";
|
||||||
?>
|
?>
|
||||||
@@ -242,4 +242,43 @@ $cookie_text = 'Cookies';
|
|||||||
$contact_text = 'Contact';
|
$contact_text = 'Contact';
|
||||||
$returns_text = 'Retourbeleid';
|
$returns_text = 'Retourbeleid';
|
||||||
$complaint_text = 'Klachten';
|
$complaint_text = 'Klachten';
|
||||||
|
|
||||||
|
// Payment Status Messages
|
||||||
|
$payment_success_title = "Betaling geslaagd!";
|
||||||
|
$payment_success_message = "Uw bestelling is bevestigd en een bevestigingsmail is verzonden naar uw e-mailadres.";
|
||||||
|
|
||||||
|
$payment_pending_title = "Betaling in behandeling";
|
||||||
|
$payment_pending_message = "Uw bestelling is ontvangen en wacht op betalingsbevestiging. U ontvangt een e-mail zodra de betaling is bevestigd.";
|
||||||
|
|
||||||
|
$payment_processing_title = "Betaling verwerken...";
|
||||||
|
$payment_processing_message = "Een moment geduld terwijl we uw betaling bevestigen. Dit kan enkele ogenblikken duren.";
|
||||||
|
|
||||||
|
$payment_failed_title = "Betaling niet geslaagd";
|
||||||
|
$payment_failed_message = "Helaas kon uw betaling niet worden verwerkt. Probeer het opnieuw of kies een andere betaalmethode.";
|
||||||
|
|
||||||
|
// Button Labels
|
||||||
|
$order_number_label = "Bestelnummer";
|
||||||
|
$continue_shopping_btn = "Verder winkelen";
|
||||||
|
$return_to_checkout_btn = "Terug naar afrekenen";
|
||||||
|
$view_cart_btn = "Bekijk winkelwagen";
|
||||||
|
|
||||||
|
// Checkout Step Labels
|
||||||
|
$step_contact = "Contact";
|
||||||
|
$step_payment = "Betaling";
|
||||||
|
$step_shipping = "Verzending";
|
||||||
|
$step_review = "Beoordeling";
|
||||||
|
|
||||||
|
// Checkout Button Text
|
||||||
|
$continue_text = "Doorgaan";
|
||||||
|
$back_text = "Terug";
|
||||||
|
$edit_text = "Bewerken";
|
||||||
|
|
||||||
|
// Checkout Additional Labels
|
||||||
|
$contact_information = "Contactinformatie";
|
||||||
|
$customer_email = "E-mail";
|
||||||
|
$account_optional = "(Optioneel)";
|
||||||
|
$select_payment = "Selecteer een betaalmethode";
|
||||||
|
$ship_to = "Verzenden naar";
|
||||||
|
$bank_transfer = "Bankoverschrijving";
|
||||||
|
$card_payment = "Credit- / Debetkaart";
|
||||||
?>
|
?>
|
||||||
@@ -243,4 +243,43 @@ $cookie_text = 'Cookies';
|
|||||||
$contact_text = 'Contact';
|
$contact_text = 'Contact';
|
||||||
$returns_text = 'Return Policy';
|
$returns_text = 'Return Policy';
|
||||||
$complaint_text = 'Complaints';
|
$complaint_text = 'Complaints';
|
||||||
|
|
||||||
|
// Payment Status Messages
|
||||||
|
$payment_success_title = "Payment Successful!";
|
||||||
|
$payment_success_message = "Your order has been confirmed and an email confirmation has been sent to your email address.";
|
||||||
|
|
||||||
|
$payment_pending_title = "Payment Pending";
|
||||||
|
$payment_pending_message = "Your order has been received and is awaiting payment confirmation. You will receive an email once the payment is confirmed.";
|
||||||
|
|
||||||
|
$payment_processing_title = "Processing Payment...";
|
||||||
|
$payment_processing_message = "Please wait while we confirm your payment. This may take a few moments.";
|
||||||
|
|
||||||
|
$payment_failed_title = "Payment Not Successful";
|
||||||
|
$payment_failed_message = "Unfortunately, your payment could not be processed. Please try again or choose a different payment method.";
|
||||||
|
|
||||||
|
// Button Labels
|
||||||
|
$order_number_label = "Order number";
|
||||||
|
$continue_shopping_btn = "Continue Shopping";
|
||||||
|
$return_to_checkout_btn = "Return to Checkout";
|
||||||
|
$view_cart_btn = "View Cart";
|
||||||
|
|
||||||
|
// Checkout Step Labels
|
||||||
|
$step_contact = "Contact";
|
||||||
|
$step_payment = "Payment";
|
||||||
|
$step_shipping = "Shipping";
|
||||||
|
$step_review = "Review";
|
||||||
|
|
||||||
|
// Checkout Button Text
|
||||||
|
$continue_text = "Continue";
|
||||||
|
$back_text = "Back";
|
||||||
|
$edit_text = "Edit";
|
||||||
|
|
||||||
|
// Checkout Additional Labels
|
||||||
|
$contact_information = "Contact Information";
|
||||||
|
$customer_email = "Email";
|
||||||
|
$account_optional = "(Optional)";
|
||||||
|
$select_payment = "Please select a payment method";
|
||||||
|
$ship_to = "Ship to";
|
||||||
|
$bank_transfer = "Bank Transfer";
|
||||||
|
$card_payment = "Credit / Debit Card";
|
||||||
?>
|
?>
|
||||||
183
functions.php
@@ -42,38 +42,51 @@ require dirname(__FILE__).'/lib/mail/Exception.php';
|
|||||||
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
function send_mail_by_PHPMailer($to, $subject, $message, $attachment, $attachment_name){
|
function send_mail_by_PHPMailer($to, $subject, $message, $attachment, $attachment_name){
|
||||||
|
|
||||||
// SEND MAIL by PHP MAILER
|
// Log email attempt
|
||||||
$mail = new PHPMailer(true);
|
debuglog("Attempting to send email to: $to, subject: $subject");
|
||||||
$mail->isSMTP(); // Use SMTP
|
|
||||||
$mail->CharSet = 'UTF-8';
|
|
||||||
$mail->Host = email_host_name; // Specify SMTP server
|
|
||||||
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // Use TLS encryption
|
|
||||||
$mail->SMTPAuth = true; // Auth. SMTP
|
|
||||||
//$mail->SMTPDebug = 3; // To view debug output
|
|
||||||
$mail->Username = email; // Mail who send by PHPMailer
|
|
||||||
$mail->Password = email_outgoing_pw; // your pass mail box
|
|
||||||
$mail->SMTPSecure = email_outgoing_security; // Accept SSL
|
|
||||||
$mail->Port = email_outgoing_port; // port of your out server
|
|
||||||
$mail->setFrom(email, mail_from); // Mail to send at
|
|
||||||
$mail->addAddress($to); // Add sender
|
|
||||||
$mail->addReplyTo(email_reply_to); // Adress to reply
|
|
||||||
$mail->isHTML(true); // use HTML message
|
|
||||||
$mail->Subject = $subject;
|
|
||||||
$mail->Body = $message;
|
|
||||||
if (!empty($attachment) || $attachment != ''){
|
|
||||||
$mail->AddStringAttachment($attachment, $attachment_name, 'base64', 'application/pdf');
|
|
||||||
}
|
|
||||||
|
|
||||||
// SEND
|
try {
|
||||||
if( !$mail->send() ){
|
// SEND MAIL by PHP MAILER
|
||||||
// render error if it is
|
$mail = new PHPMailer(true);
|
||||||
$tab = array('error' => 'Mailer Error: '.$mail->ErrorInfo );
|
$mail->isSMTP(); // Use SMTP
|
||||||
debuglog(json_encode($tab));
|
$mail->CharSet = 'UTF-8';
|
||||||
exit;
|
$mail->Host = email_host_name; // Specify SMTP server
|
||||||
}
|
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // Use TLS encryption
|
||||||
else{
|
$mail->SMTPAuth = true; // Auth. SMTP
|
||||||
// return true if message is send
|
//$mail->SMTPDebug = 3; // To view debug output
|
||||||
return true;
|
$mail->Username = email; // Mail who send by PHPMailer
|
||||||
|
$mail->Password = email_outgoing_pw; // your pass mail box
|
||||||
|
$mail->SMTPSecure = email_outgoing_security; // Accept SSL
|
||||||
|
$mail->Port = email_outgoing_port; // port of your out server
|
||||||
|
|
||||||
|
debuglog("SMTP Config - Host: " . email_host_name . ", Port: " . email_outgoing_port . ", Security: " . email_outgoing_security);
|
||||||
|
|
||||||
|
$mail->setFrom(email, mail_from); // Mail to send at
|
||||||
|
$mail->addAddress($to); // Add sender
|
||||||
|
$mail->addReplyTo(email_reply_to); // Adress to reply
|
||||||
|
$mail->isHTML(true); // use HTML message
|
||||||
|
$mail->Subject = $subject;
|
||||||
|
$mail->Body = $message;
|
||||||
|
if (!empty($attachment) || $attachment != ''){
|
||||||
|
$mail->AddStringAttachment($attachment, $attachment_name, 'base64', 'application/pdf');
|
||||||
|
debuglog("Attachment added: $attachment_name");
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEND
|
||||||
|
if( !$mail->send() ){
|
||||||
|
// render error if it is
|
||||||
|
$tab = array('error' => 'Mailer Error: '.$mail->ErrorInfo );
|
||||||
|
debuglog("Email send failed: " . json_encode($tab));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// return true if message is send
|
||||||
|
debuglog("Email sent successfully to: $to");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
debuglog("PHPMailer Exception: " . $e->getMessage());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -479,13 +492,13 @@ function removeGiftCart($pdo, $orderID){
|
|||||||
function generateInvoice($invoice_cust,$orderID,$user_language){
|
function generateInvoice($invoice_cust,$orderID,$user_language){
|
||||||
|
|
||||||
//Variables
|
//Variables
|
||||||
$customer_email = htmlspecialchars($invoice_cust['customer']['email'] ?? '', ENT_QUOTES);
|
$invoice_customer_email = htmlspecialchars($invoice_cust['customer']['email'] ?? '', ENT_QUOTES);
|
||||||
//Generate invoice
|
//Generate invoice
|
||||||
ob_start();
|
ob_start();
|
||||||
include dirname(__FILE__).'/custom/email/order-invoice-template.php';
|
include dirname(__FILE__).'/custom/email/order-invoice-template.php';
|
||||||
$order_invoice_template = ob_get_clean();
|
$order_invoice_template = ob_get_clean();
|
||||||
|
|
||||||
return array($order_invoice_template,$customer_email,$orderId);
|
return array($order_invoice_template,$invoice_customer_email,$orderID);
|
||||||
}
|
}
|
||||||
|
|
||||||
function freeShipment($price, $type){
|
function freeShipment($price, $type){
|
||||||
@@ -613,13 +626,23 @@ function sortProducts(array $products, string $field, string $direction = 'asc')
|
|||||||
return $products;
|
return $products;
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlightedProducts($clientsecret,$categoryID,$range, $subtitle){
|
function highlightedProducts($categoryID, $range, $subtitle, $catalog, $categories){
|
||||||
|
|
||||||
include './custom/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
|
include './custom/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
|
||||||
|
|
||||||
//GET CATALOG DATA
|
//GET CATALOG DATA FROM CACHE
|
||||||
$products = ioAPIv2('/v2/catalog/category='.$categoryID,'',$clientsecret);
|
// Build product IDs that belong to this category
|
||||||
$products = json_decode($products,true);
|
$product_ids_in_category = [];
|
||||||
|
foreach ($categories as $cat) {
|
||||||
|
if ($cat['rowID'] == $categoryID && isset($cat['product_id'])) {
|
||||||
|
$product_ids_in_category[] = $cat['product_id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter products by category
|
||||||
|
$products = array_filter($catalog, function($product) use ($product_ids_in_category) {
|
||||||
|
return in_array($product['rowID'], $product_ids_in_category);
|
||||||
|
});
|
||||||
|
|
||||||
//RANDOM SORT
|
//RANDOM SORT
|
||||||
$products = sortProducts($products, 'random');
|
$products = sortProducts($products, 'random');
|
||||||
@@ -664,13 +687,23 @@ function highlightedProducts($clientsecret,$categoryID,$range, $subtitle){
|
|||||||
return $section ;
|
return $section ;
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlightedProducts2($clientsecret,$categoryID,$range, $subtitle){
|
function highlightedProducts2($categoryID, $range, $subtitle, $catalog, $categories){
|
||||||
|
|
||||||
include './custom/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
|
include './custom/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
|
||||||
|
|
||||||
//GET CATALOG DATA
|
//GET CATALOG DATA FROM CACHE
|
||||||
$products = ioAPIv2('/v2/catalog/category='.$categoryID,'',$clientsecret);
|
// Build product IDs that belong to this category
|
||||||
$products = json_decode($products,true);
|
$product_ids_in_category = [];
|
||||||
|
foreach ($categories as $cat) {
|
||||||
|
if ($cat['rowID'] == $categoryID && isset($cat['product_id'])) {
|
||||||
|
$product_ids_in_category[] = $cat['product_id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter products by category
|
||||||
|
$products = array_filter($catalog, function($product) use ($product_ids_in_category) {
|
||||||
|
return in_array($product['rowID'], $product_ids_in_category);
|
||||||
|
});
|
||||||
|
|
||||||
//RANDOM SORT
|
//RANDOM SORT
|
||||||
$products = sortProducts($products, 'random');
|
$products = sortProducts($products, 'random');
|
||||||
@@ -730,6 +763,74 @@ function debuglog($error){
|
|||||||
error_log($test, 3, $filelocation);
|
error_log($test, 3, $filelocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Get Cached Data from File (24-hour refresh)
|
||||||
|
//------------------------------------------
|
||||||
|
function getCachedData($api_endpoint, $cache_filename, $token){
|
||||||
|
$cache_file = './cache/' . $cache_filename;
|
||||||
|
$cache_age_limit = 24 * 60 * 60; // 24 hours in seconds
|
||||||
|
|
||||||
|
// Check if cache file exists and is fresh (less than 24 hours old)
|
||||||
|
if (file_exists($cache_file) && (time() - filemtime($cache_file)) < $cache_age_limit) {
|
||||||
|
// Return cached data from JSON file
|
||||||
|
$json_data = file_get_contents($cache_file);
|
||||||
|
return json_decode($json_data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache is stale or doesn't exist - attempt to refresh
|
||||||
|
try {
|
||||||
|
$response = ioAPIv2($api_endpoint, '', $token);
|
||||||
|
$data = json_decode($response, true);
|
||||||
|
|
||||||
|
if (!empty($data) && is_array($data)) {
|
||||||
|
// Successfully fetched new data - write to cache file as JSON
|
||||||
|
$cache_content = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
// Ensure cache directory exists
|
||||||
|
if (!is_dir('./cache')) {
|
||||||
|
mkdir('./cache', 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to write cache file
|
||||||
|
if (@file_put_contents($cache_file, $cache_content, LOCK_EX) === false) {
|
||||||
|
// Write failed - log error and fall back to existing cache
|
||||||
|
debuglog('Cache write failed for ' . $cache_filename . ' - using existing cache');
|
||||||
|
|
||||||
|
if (file_exists($cache_file)) {
|
||||||
|
$json_data = file_get_contents($cache_file);
|
||||||
|
return json_decode($json_data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No existing cache - return fresh data anyway
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
} else {
|
||||||
|
// API call failed - log error and fall back to existing cache
|
||||||
|
debuglog('API call failed for ' . $api_endpoint . ' - using existing cache');
|
||||||
|
|
||||||
|
if (file_exists($cache_file)) {
|
||||||
|
$json_data = file_get_contents($cache_file);
|
||||||
|
return json_decode($json_data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No existing cache and API failed - return empty array
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Exception occurred - log and fall back to existing cache
|
||||||
|
debuglog('Exception in getCachedData for ' . $cache_filename . ': ' . $e->getMessage());
|
||||||
|
|
||||||
|
if (file_exists($cache_file)) {
|
||||||
|
$json_data = file_get_contents($cache_file);
|
||||||
|
return json_decode($json_data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
// Retrieve all $_GET from URL
|
// Retrieve all $_GET from URL
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
|
|||||||
4
home.php
@@ -27,9 +27,9 @@ $view .= '
|
|||||||
// ++++++++++++++++++++++++++++++
|
// ++++++++++++++++++++++++++++++
|
||||||
// Include highlighted Products
|
// Include highlighted Products
|
||||||
// ++++++++++++++++++++++++++++++
|
// ++++++++++++++++++++++++++++++
|
||||||
$view .= highlightedProducts2($clientsecret,category_id_highlighted_products_1, ($highlight_2 ?? 'highlight 2'),'');
|
$view .= highlightedProducts2(category_id_highlighted_products_1, ($highlight_2 ?? 'highlight 2'), '', $GLOBALS['cached_catalog'], $GLOBALS['cached_categories']);
|
||||||
|
|
||||||
$view .= highlightedProducts($clientsecret,category_id_highlighted_products_2, ($highlight_2 ?? 'highlight 2'),'');
|
$view .= highlightedProducts(category_id_highlighted_products_2, ($highlight_2 ?? 'highlight 2'), '', $GLOBALS['cached_catalog'], $GLOBALS['cached_categories']);
|
||||||
|
|
||||||
|
|
||||||
$view .= '
|
$view .= '
|
||||||
|
|||||||
112
index.php
@@ -19,44 +19,98 @@ include './custom/settings/config.php';
|
|||||||
include './custom/settings/settings.php';
|
include './custom/settings/settings.php';
|
||||||
include 'functions.php';
|
include 'functions.php';
|
||||||
|
|
||||||
//TRANSLATION FILE LOCATION
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
if (isset($_GET['language']) && $_GET['language'] !=''){
|
// Debug functions
|
||||||
//INCLUDE LANGUAGE FILE
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
$file_language = './custom/translations/translations_'.strtoupper($_GET['language']).'.php';
|
if (debug){
|
||||||
if (file_exists($file_language)){
|
set_error_handler(function($errno, $errstr, $errfile, $errline) {
|
||||||
include $file_language; //Include the code
|
debuglog("PHP ERROR [$errno]: $errstr in $errfile on line $errline");
|
||||||
//DEFINE LANGUAGE
|
return false;
|
||||||
$_SESSION['country_code'] = trim($_GET['language']);
|
});
|
||||||
}
|
|
||||||
else {
|
set_exception_handler(function($exception) {
|
||||||
include './custom/translations/translations_NL.php';
|
debuglog("PHP EXCEPTION: " . $exception->getMessage() . " in " . $exception->getFile() . " on line " . $exception->getLine());
|
||||||
//DEFINE LANGUAGE
|
});
|
||||||
$_SESSION['country_code'] = language_code;
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Languages supported
|
||||||
|
//------------------------------------------
|
||||||
|
$supportedLanguages = ['US', 'NL', 'DE', 'ES','FR'];
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Determine language to use
|
||||||
|
//------------------------------------------
|
||||||
|
// Session language expires after 30 days (adjust as needed)
|
||||||
|
$session_expiry_days = 30;
|
||||||
|
|
||||||
|
// Check if language session has expired
|
||||||
|
if (isset($_SESSION['country_code_timestamp'])) {
|
||||||
|
$days_passed = (time() - $_SESSION['country_code_timestamp']) / (60 * 60 * 24);
|
||||||
|
if ($days_passed > $session_expiry_days) {
|
||||||
|
unset($_SESSION['country_code']);
|
||||||
|
unset($_SESSION['country_code_timestamp']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif(isset($_SESSION['country_code'])){
|
|
||||||
$file_language = './custom/translations/translations_'.strtoupper($_SESSION['country_code']).'.php';
|
// Detect browser language first
|
||||||
if (file_exists($file_language)){
|
$browser_lang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? strtoupper(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2)) : country_default;
|
||||||
include $file_language; //Include the code
|
|
||||||
}
|
if (isset($_GET['language']) && $_GET['language'] != '') {
|
||||||
else {
|
$selected_lang = strtoupper(trim($_GET['language']));
|
||||||
include './custom/translations/translations_NL.php';
|
} elseif (isset($_SESSION['country_code'])) {
|
||||||
}
|
$selected_lang = strtoupper($_SESSION['country_code']);
|
||||||
} else {
|
} else {
|
||||||
include './custom/translations/translations_NL.php';
|
$selected_lang = in_array($browser_lang, $supportedLanguages) ? $browser_lang : country_default;
|
||||||
//DEFINE LANGUAGE
|
}
|
||||||
$_SESSION['country_code'] = language_code;
|
|
||||||
|
// Load translation file
|
||||||
|
$file_language = './custom/translations/translations_'.$selected_lang.'.php';
|
||||||
|
if (file_exists($file_language)) {
|
||||||
|
include $file_language;
|
||||||
|
$_SESSION['country_code'] = $selected_lang;
|
||||||
|
$_SESSION['country_code_timestamp'] = time(); // Store timestamp when language is set
|
||||||
|
} else {
|
||||||
|
include './custom/translations/translations_'.strtoupper(country_default).'.php';
|
||||||
|
$_SESSION['country_code'] = country_default;
|
||||||
|
$_SESSION['country_code_timestamp'] = time();
|
||||||
}
|
}
|
||||||
|
|
||||||
$pdo = pdo_connect_mysql();
|
$pdo = pdo_connect_mysql();
|
||||||
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
//LOGIN TO API
|
//LOGIN TO API
|
||||||
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
$data = json_encode(array("clientID" => clientID, "clientsecret" => clientsecret), JSON_UNESCAPED_UNICODE);
|
// Token refresh buffer: refresh token 5 minutes (300 seconds) before expiry
|
||||||
$responses = ioAPIv2('/v2/authorization', $data,'');
|
$token_refresh_buffer = 300;
|
||||||
//Decode Payload
|
|
||||||
if (!empty($responses)){$responses = json_decode($responses,true);}else{$responses = '400';}
|
// Check if API token exists and is still valid
|
||||||
$clientsecret = $responses['token'];
|
if (!isset($_SESSION['api_token']) || !isset($_SESSION['api_token_expires']) || time() >= ($_SESSION['api_token_expires'] - $token_refresh_buffer)) {
|
||||||
|
// Token missing, expired, or about to expire - get new token
|
||||||
|
$data = json_encode(array("clientID" => clientID, "clientsecret" => clientsecret), JSON_UNESCAPED_UNICODE);
|
||||||
|
$responses = ioAPIv2('/v2/authorization', $data,'');
|
||||||
|
//Decode Payload
|
||||||
|
if (!empty($responses)){$responses = json_decode($responses,true);}else{$responses = '400';}
|
||||||
|
|
||||||
|
if (isset($responses['token']) && isset($responses['token_valid'])) {
|
||||||
|
// Store token and expiry timestamp in session
|
||||||
|
$_SESSION['api_token'] = $responses['token'];
|
||||||
|
$_SESSION['api_token_expires'] = strtotime($responses['token_valid']);
|
||||||
|
$clientsecret = $responses['token'];
|
||||||
|
} else {
|
||||||
|
// Fallback for backwards compatibility
|
||||||
|
$clientsecret = $responses['token'] ?? '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Use cached token
|
||||||
|
$clientsecret = $_SESSION['api_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
//LOAD CACHED CATALOG AND CATEGORIES DATA
|
||||||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Load catalog and categories from cache files (refreshes once per 24 hours)
|
||||||
|
$GLOBALS['cached_catalog'] = getCachedData('/v2/catalog/', 'catalog.json', $clientsecret);
|
||||||
|
$GLOBALS['cached_categories'] = getCachedData('/v2/products_categories/', 'categories.json', $clientsecret);
|
||||||
|
|
||||||
// Output error variable
|
// Output error variable
|
||||||
$error = '';
|
$error = '';
|
||||||
|
|||||||
BIN
log/.DS_Store
vendored
Normal file
672
log/checkout_old_working.php
Normal file
@@ -0,0 +1,672 @@
|
|||||||
|
<?php
|
||||||
|
// Prevent direct access to file
|
||||||
|
defined(security_key) or exit;
|
||||||
|
|
||||||
|
// ---------------------------------------
|
||||||
|
// Defaults
|
||||||
|
// ---------------------------------------
|
||||||
|
$account = [
|
||||||
|
'account_id' => $_SESSION['account_id'] ?? '',
|
||||||
|
'email' => $_POST['email'] ?? '',
|
||||||
|
'first_name' => $_POST['first_name'] ?? '',
|
||||||
|
'last_name' => $_POST['last_name'] ?? '',
|
||||||
|
'address_street' => $_POST['address_street'] ?? '',
|
||||||
|
'address_city' => $_POST['address_city'] ?? '',
|
||||||
|
'address_state' => $_POST['address_state'] ?? '',
|
||||||
|
'address_zip' => $_POST['address_zip'] ?? '',
|
||||||
|
'address_country' => $_POST['address_country'] ?? '',
|
||||||
|
'address_phone' => $_POST['address_phone'] ?? ''
|
||||||
|
];
|
||||||
|
|
||||||
|
$products_in_cart = isset($_SESSION['cart']) ? $_SESSION['cart'] : [];
|
||||||
|
$subtotal = 0.00;
|
||||||
|
$total = 0.00;
|
||||||
|
$shippingtotal = 0.00;
|
||||||
|
$discounttotal = 0.00;
|
||||||
|
$taxtotal = 0.00;
|
||||||
|
$tax_rate = '';
|
||||||
|
$weighttotal = 0;
|
||||||
|
$shipping_methods = [];
|
||||||
|
|
||||||
|
$checkout_input = [
|
||||||
|
"selected_country" => isset($_POST['address_country']) ? $_POST['address_country'] : (isset($account['address_country']) ? $account['address_country'] : 21) ,
|
||||||
|
"selected_shipment_method" => isset($_POST['shipping_method']) ? $_POST['shipping_method'] : '',
|
||||||
|
"business_type" => 'b2c',
|
||||||
|
"discount_code" => isset($_SESSION['discount']) ? $_SESSION['discount'] : ''
|
||||||
|
];
|
||||||
|
|
||||||
|
// Error array, output errors on the form
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
// ---------------------------------------------
|
||||||
|
// End defaults --------------------------------
|
||||||
|
// ---------------------------------------------
|
||||||
|
|
||||||
|
// Redirect the user if the shopping cart is empty
|
||||||
|
if (empty($_SESSION['cart'])) {
|
||||||
|
header('Location: ' . url('index.php?page=cart'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user is logged in
|
||||||
|
if (isset($_SESSION['account_loggedin'])) {
|
||||||
|
$api_url = '/v2/identity/userkey='.$_SESSION['account_id'];
|
||||||
|
$account = ioAPIv2($api_url,'',$clientsecret);
|
||||||
|
if (!empty($account)){$account = json_decode($account,true);}
|
||||||
|
$account = $account[0];
|
||||||
|
//RESET ACCOUNT_ID
|
||||||
|
$account['account_id'] = $account['userkey'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update discount code
|
||||||
|
if (isset($_POST['discount_code']) && !empty($_POST['discount_code'])) {
|
||||||
|
$_SESSION['discount'] = $_POST['discount_code'];
|
||||||
|
} else if (isset($_POST['discount_code']) && empty($_POST['discount_code']) && isset($_SESSION['discount'])) {
|
||||||
|
unset($_SESSION['discount']);
|
||||||
|
}
|
||||||
|
//-------------------------------
|
||||||
|
// If there are products in cart handle the checkout
|
||||||
|
//-------------------------------
|
||||||
|
if ($products_in_cart) {
|
||||||
|
|
||||||
|
// First, calculate cart to get initial totals (without shipping)
|
||||||
|
$initial_payload = json_encode(array("cart" => $products_in_cart, "checkout_input" => $checkout_input), JSON_UNESCAPED_UNICODE);
|
||||||
|
$initial_cart = ioAPIv2('/v2/checkout/',$initial_payload,$clientsecret);
|
||||||
|
$initial_cart = json_decode($initial_cart,true);
|
||||||
|
|
||||||
|
// Get initial totals for shipping method calculation
|
||||||
|
$initial_subtotal = $initial_cart['totals']['subtotal'] ?? 0;
|
||||||
|
$initial_weighttotal = $initial_cart['totals']['weighttotal'] ?? 0;
|
||||||
|
|
||||||
|
// Now retrieve shipping methods with correct totals
|
||||||
|
$shipping_methods = ioAPIv2('/v2/shipping/list=methods&country='.$checkout_input['selected_country'].'&price_total='.$initial_subtotal.'&weight_total='.$initial_weighttotal,'',$clientsecret);
|
||||||
|
$shipping_methods = json_decode($shipping_methods,true);
|
||||||
|
|
||||||
|
// If no shipping method is selected and shipping methods are available, select the first one as default
|
||||||
|
if (empty($checkout_input['selected_shipment_method']) && !empty($shipping_methods) && count($shipping_methods) > 0) {
|
||||||
|
$checkout_input['selected_shipment_method'] = $shipping_methods[0]['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate shopping_cart with selected shipping method
|
||||||
|
$payload = json_encode(array("cart" => $products_in_cart, "checkout_input" => $checkout_input), JSON_UNESCAPED_UNICODE);
|
||||||
|
$products_in_cart = ioAPIv2('/v2/checkout/',$payload,$clientsecret);
|
||||||
|
$products_in_cart = json_decode($products_in_cart,true);
|
||||||
|
|
||||||
|
//GET SPECIFIC TOTALS FROM API RESULTS
|
||||||
|
$subtotal = $products_in_cart['totals']['subtotal'];
|
||||||
|
$shippingtotal = $products_in_cart['totals']['shippingtotal'];
|
||||||
|
$discounttotal = $products_in_cart['totals']['discounttotal'];
|
||||||
|
$taxtotal = $products_in_cart['totals']['taxtotal'];
|
||||||
|
$tax_rate = $products_in_cart['totals']['tax_rate'];
|
||||||
|
$weighttotal = $products_in_cart['totals']['weighttotal'];
|
||||||
|
$total = $products_in_cart['totals']['total'];
|
||||||
|
|
||||||
|
// Redirect the user if the shopping cart is empty
|
||||||
|
if (empty($products_in_cart)) {
|
||||||
|
header('Location: ' . url('index.php?page=cart'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------
|
||||||
|
// END Checkout handler
|
||||||
|
//-------------------------------
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------
|
||||||
|
//Place order
|
||||||
|
//-------------------------------
|
||||||
|
// Make sure when the user submits the form all data was submitted and shopping cart is not empty
|
||||||
|
if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['address_street'], $_POST['address_city'], $_POST['address_state'], $_POST['address_zip'], $_POST['address_country'], $_POST['address_phone'], $_SESSION['cart']) && !isset($_POST['update'])) {
|
||||||
|
$account_id = null;
|
||||||
|
// If the user is already logged in
|
||||||
|
if (isset($_SESSION['account_loggedin'])) {
|
||||||
|
// Account logged-in, update the user's details
|
||||||
|
$payload = json_encode(
|
||||||
|
array(
|
||||||
|
"language" => $_SESSION['country_code'],
|
||||||
|
"first_name" => $_POST['first_name'],
|
||||||
|
"last_name" => $_POST['last_name'],
|
||||||
|
"address_street" => $_POST['address_street'],
|
||||||
|
"address_city" => $_POST['address_city'],
|
||||||
|
"address_state" => $_POST['address_state'],
|
||||||
|
"address_zip" => $_POST['address_zip'],
|
||||||
|
"address_country" => $_POST['address_country'],
|
||||||
|
"address_phone" => $_POST['address_phone'],
|
||||||
|
"userkey" => $_SESSION['account_id']), JSON_UNESCAPED_UNICODE);
|
||||||
|
$account_update = ioAPIv2('/v2/identity/',$payload,$clientsecret);
|
||||||
|
$account_update = json_decode($account_update,true);
|
||||||
|
$account_id = $account['account_id'] = $_SESSION['account_id'];
|
||||||
|
|
||||||
|
} else if (isset($_POST['email'], $_POST['password'], $_POST['cpassword']) && filter_var($_POST['email'], FILTER_VALIDATE_EMAIL) && !empty($_POST['password']) && !empty($_POST['cpassword'])) {
|
||||||
|
// User is not logged in, check if the account already exists with the email they submitted
|
||||||
|
// Check if the account exists
|
||||||
|
$account = ioAPIv2('/v2/identity/email='.$_POST['email'],'',$clientsecret);
|
||||||
|
$account = json_decode($account,true);
|
||||||
|
|
||||||
|
|
||||||
|
if ($account) {
|
||||||
|
// Email exists, user should login instead...
|
||||||
|
$errors[] = $error_account_name;
|
||||||
|
}
|
||||||
|
if (strlen($_POST['password']) > 20 || strlen($_POST['password']) < 5) {
|
||||||
|
// Password must be between 5 and 20 characters long.
|
||||||
|
$errors[] = $error_account_password_rules;
|
||||||
|
}
|
||||||
|
if ($_POST['password'] != $_POST['cpassword']) {
|
||||||
|
// Password and confirm password fields do not match...
|
||||||
|
$errors[] = $error_account_password_match;
|
||||||
|
}
|
||||||
|
if (!$errors) {
|
||||||
|
// Account doesnt exist, create new account
|
||||||
|
$payload = json_encode(
|
||||||
|
array(
|
||||||
|
"email" => $_POST['email'],
|
||||||
|
"password" => $_POST['password'],
|
||||||
|
"language" => $_SESSION['country_code'],
|
||||||
|
"first_name" => $_POST['first_name'],
|
||||||
|
"last_name" => $_POST['last_name'],
|
||||||
|
"address_street" => $_POST['address_street'],
|
||||||
|
"address_city" => $_POST['address_city'],
|
||||||
|
"address_state" => $_POST['address_state'],
|
||||||
|
"address_zip" => $_POST['address_zip'],
|
||||||
|
"address_country" => $_POST['address_country'],
|
||||||
|
"address_phone" => $_POST['address_phone']), JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
$account = ioAPIv2('/v2/identity/',$payload,$clientsecret);
|
||||||
|
$account= json_decode($account,true);
|
||||||
|
$account_id = $account['account_id'] = $account['accountID'];
|
||||||
|
|
||||||
|
if ($account && isset($account['accountID'])) {
|
||||||
|
//SEND VERIFICATION EMAIL
|
||||||
|
include dirname(__FILE__).'/custom/email/email_template_register.php';
|
||||||
|
$register_mail = $message;
|
||||||
|
|
||||||
|
send_mail_by_PHPMailer($account['identity'], $subject, $register_mail,'', '');
|
||||||
|
$register_error = 'Email send to verify your account';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (account_required) {
|
||||||
|
$errors[] = $error_account;
|
||||||
|
}
|
||||||
|
if (!$errors && $products_in_cart) {
|
||||||
|
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
//Process checkout => add payment_method to checkout_input array
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
$checkout_input['payment_method'] = $_POST['method'];
|
||||||
|
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Calculate shopping_cart based on session
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
$payload = json_encode(array("cart" => $_SESSION['cart'], "checkout_input" => $checkout_input, "customer_details" => $account), JSON_UNESCAPED_UNICODE);
|
||||||
|
$place_order = ioAPIv2('/v2/placeorder/',$payload,$clientsecret);
|
||||||
|
$place_order = json_decode($place_order,true);
|
||||||
|
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
//Check if transaction is succesfull and send order confirmation to customer
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
if ($place_order['error'] == '' && $place_order['id'] != ''){
|
||||||
|
|
||||||
|
// Push purchase event to dataLayer
|
||||||
|
if (isset($place_order['products_checked-out']) && is_array($place_order['products_checked-out'])) {
|
||||||
|
$productIds = [];
|
||||||
|
$totalQuantity = 0;
|
||||||
|
$products = [];
|
||||||
|
|
||||||
|
foreach ($place_order['products_checked-out'] as $p) {
|
||||||
|
if (is_array($p)) {
|
||||||
|
$productIds[] = $p['id'] ?? '';
|
||||||
|
$totalQuantity += $p['quantity'] ?? 0;
|
||||||
|
$products[] = [
|
||||||
|
'id' => $p['id'] ?? '',
|
||||||
|
'name' => $p['meta']['name'] ?? '',
|
||||||
|
'price' => $p['options_price'] ?? 0,
|
||||||
|
'quantity' => $p['quantity'] ?? 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
window.dataLayer.push({
|
||||||
|
'event': 'purchase',
|
||||||
|
'ecommerce': {
|
||||||
|
'purchase': {
|
||||||
|
'actionField': {
|
||||||
|
'id': '" . $place_order['transaction_id'] . "',
|
||||||
|
'revenue': '" . $place_order['payment_amount'] . "',
|
||||||
|
'tax': '" . $place_order['taxtotal'] . "',
|
||||||
|
'shipping': '" . $place_order['shippingtotal'] . "'
|
||||||
|
},
|
||||||
|
'products': " . json_encode($products) . "
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'content_type': 'product',
|
||||||
|
'content_ids': " . json_encode($productIds) . ",
|
||||||
|
'value': " . floatval($place_order['payment_amount']) . ",
|
||||||
|
'currency': 'EUR',
|
||||||
|
'num_items': " . $totalQuantity . "
|
||||||
|
});
|
||||||
|
</script>";
|
||||||
|
}
|
||||||
|
|
||||||
|
//SEND CONFIRMATION TO CUSTOMER
|
||||||
|
send_order_details_email(
|
||||||
|
$account['email'],
|
||||||
|
$place_order['products_checked-out'],
|
||||||
|
$account['first_name'],
|
||||||
|
$account['last_name'],
|
||||||
|
$account['address_street'],
|
||||||
|
$account['address_city'],
|
||||||
|
$account['address_state'],
|
||||||
|
$account['address_zip'],
|
||||||
|
$account['address_country'],
|
||||||
|
$place_order['subtotal'],
|
||||||
|
$place_order['discounttotal'],
|
||||||
|
$place_order['shippingtotal'],
|
||||||
|
$place_order['taxtotal'],
|
||||||
|
$place_order['payment_amount'],
|
||||||
|
$place_order['transaction_id']
|
||||||
|
);
|
||||||
|
|
||||||
|
//Disable giftcard
|
||||||
|
if (isset($_SESSION['discount'])){
|
||||||
|
if (preg_match("/[#][0-9]/", $_SESSION['discount']) == 1){
|
||||||
|
useGiftCart($pdo, $_SESSION['discount']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate the user
|
||||||
|
if ($account_id != null) {
|
||||||
|
// Log the user in with the details provided
|
||||||
|
session_regenerate_id();
|
||||||
|
$_SESSION['account_loggedin'] = TRUE;
|
||||||
|
$_SESSION['account_id'] = $account_id;
|
||||||
|
$_SESSION['account_role'] = $account ? $account['profile'] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
//Pay on delivery = 2
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
if (pay_on_delivery_enabled && $place_order['payment_method'] == 2){
|
||||||
|
header('Location: ' . url('index.php?page=placeorder'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Mollie = 3 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
if (mollie_enabled && $_POST['method'] == 3) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
/*
|
||||||
|
* Initialize the Mollie API library with your API key.
|
||||||
|
*
|
||||||
|
* See: https://www.mollie.com/dashboard/developers/api-keys
|
||||||
|
*/
|
||||||
|
require "initialize.php";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate a unique order id for this example. It is important to include this unique attribute
|
||||||
|
* in the redirectUrl (below) so a proper return page can be shown to the customer.
|
||||||
|
*/
|
||||||
|
$orderId = $place_order['transaction_id'];
|
||||||
|
$value = number_format($place_order['payment_amount'],2,'.','');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the url parts to these example files.
|
||||||
|
*/
|
||||||
|
$protocol = isset($_SERVER['HTTPS']) && strcasecmp('off', $_SERVER['HTTPS']) !== 0 ? "https" : "http";
|
||||||
|
$hostname = $_SERVER['HTTP_HOST'];
|
||||||
|
$path = dirname($_SERVER['REQUEST_URI'] ?? $_SERVER['PHP_SELF']);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Payment parameters:
|
||||||
|
* amount Amount in EUROs.
|
||||||
|
* description Description of the payment.
|
||||||
|
* redirectUrl Redirect location. The customer will be redirected there after the payment.
|
||||||
|
* webhookUrl Webhook location, used to report when the payment changes state.
|
||||||
|
* metadata Custom metadata that is stored with the payment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (rewrite_url){
|
||||||
|
$redirectURL = $protocol.'://'.$hostname.$path.'placeorder/'.$orderId;
|
||||||
|
}else{
|
||||||
|
$redirectURL = $protocol.'://'.$hostname.$path.'index.php?page=placeorder&order_id='.$orderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payment = $mollie->payments->create([
|
||||||
|
"amount" => [
|
||||||
|
"currency" => "EUR",
|
||||||
|
"value" => "{$value}", // You must send the correct number of decimals, thus we enforce the use of strings
|
||||||
|
],
|
||||||
|
"description" => "Order #{$orderId}",
|
||||||
|
"redirectUrl" => "$redirectURL",
|
||||||
|
"webhookUrl" => "{$protocol}://{$hostname}{$path}webhook.php",
|
||||||
|
"metadata" => [
|
||||||
|
"order_id" => $orderId,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
/*
|
||||||
|
* Send the customer off to complete the payment.
|
||||||
|
* This request should always be a GET, thus we enforce 303 http response code
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Send customer to checkout
|
||||||
|
header("Location: " . $payment->getCheckoutUrl(), true, 303);
|
||||||
|
|
||||||
|
} catch (\Mollie\Api\Exceptions\ApiException $e) {
|
||||||
|
echo "API call failed: " . htmlspecialchars($e->getMessage());
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// PayPal Payment = 1 +++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
if (paypal_enabled && $_POST['method'] == 1) {
|
||||||
|
|
||||||
|
//Process Payment
|
||||||
|
require_once __DIR__."/lib/paypal/paypal.php";
|
||||||
|
|
||||||
|
$base = PAYPAL_URL;
|
||||||
|
$id = PAYPAL_CLIENT_ID;
|
||||||
|
$secret = PAYPAL_CLIENT_SECRET;
|
||||||
|
|
||||||
|
//init input
|
||||||
|
$order = $place_order['transaction_id'];
|
||||||
|
$price = number_format($place_order['payment_amount'],2,'.','');
|
||||||
|
$currency = "EUR";
|
||||||
|
|
||||||
|
//make payment
|
||||||
|
$paypal = new paypalCurl();
|
||||||
|
$paypal->init($id,$secret,$base);
|
||||||
|
$result = $paypal->makePaymentURL($order,$price,$currency);
|
||||||
|
|
||||||
|
if ($result->status === true) {
|
||||||
|
header("location:". $result->url);
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
else { //raise error
|
||||||
|
echo $result->msg;
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($place_order['error'] as $error){
|
||||||
|
$errors[] = $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------
|
||||||
|
// END PLACE ORDER
|
||||||
|
//-------------------------------
|
||||||
|
|
||||||
|
$terms_link = url('index.php?page=termsandconditions');
|
||||||
|
$privacy_link = url('index.php?page=privacy');
|
||||||
|
|
||||||
|
$view = template_header(($checkout_header ?? 'Checkout'),'');
|
||||||
|
|
||||||
|
// Push initiateCheckout event to dataLayer
|
||||||
|
if (isset($products_in_cart['cart_details']['products']) && is_array($products_in_cart['cart_details']['products']) && count($products_in_cart['cart_details']['products']) > 0) {
|
||||||
|
$productIds = array_map(function($p) { return $p['id']; }, $products_in_cart['cart_details']['products']);
|
||||||
|
$totalQuantity = array_sum(array_map(function($p) { return $p['quantity']; }, $products_in_cart['cart_details']['products']));
|
||||||
|
|
||||||
|
$view .= '<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
window.dataLayer.push({
|
||||||
|
"event": "initiateCheckout",
|
||||||
|
"ecommerce": {
|
||||||
|
"checkout": {
|
||||||
|
"actionField": {
|
||||||
|
"step": 1
|
||||||
|
},
|
||||||
|
"products": ' . json_encode(array_map(function($p) {
|
||||||
|
return [
|
||||||
|
'id' => $p['id'],
|
||||||
|
'name' => $p['meta']['name'],
|
||||||
|
'price' => $p['options_price'],
|
||||||
|
'quantity' => $p['quantity']
|
||||||
|
];
|
||||||
|
}, $products_in_cart['cart_details']['products'])) . '
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content_type": "product",
|
||||||
|
"content_ids": ' . json_encode($productIds) . ',
|
||||||
|
"value": ' . $total . ',
|
||||||
|
"currency": "EUR",
|
||||||
|
"num_items": ' . $totalQuantity . '
|
||||||
|
});
|
||||||
|
</script>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$view .= '
|
||||||
|
<div class="checkout content-wrapper">
|
||||||
|
|
||||||
|
<h1>'.$h1_checkout.'</h1>';
|
||||||
|
|
||||||
|
if (!empty($errors) || count($errors) > 0){
|
||||||
|
|
||||||
|
$view .= '<p class="error">'.implode('<br>', $errors).'</p>';
|
||||||
|
}
|
||||||
|
if (!isset($_SESSION['account_loggedin'])){
|
||||||
|
$view .= '<p>'.$account_available.' <a href="'.url('index.php?page=myaccount').'">'.$account_log_in.'</a></p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$view .= '
|
||||||
|
<form action="" method="post">
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<div class="shipping-details">x
|
||||||
|
<div id="dropin-container"></div>
|
||||||
|
<h2>'.$payment_method.'</h2>
|
||||||
|
|
||||||
|
<div class="payment-methods">';
|
||||||
|
if (mollie_enabled){
|
||||||
|
$view .= ' <input id="mollie-ideal" type="radio" name="method" value="3" '. ((mollie_default)? 'checked':'') .'>
|
||||||
|
<label for="mollie-ideal">
|
||||||
|
<img src="./custom/assets/wero.svg" style="width: 100px;" alt="'.$payment_method_1.'">
|
||||||
|
</label>';
|
||||||
|
|
||||||
|
$view .= ' <input id="mollie-card" type="radio" name="method" value="3">
|
||||||
|
<label for="mollie-card">
|
||||||
|
<img src="./custom/assets/mastercard.png" style="width: 50px;" alt="'.$payment_method_1.'">
|
||||||
|
<img src="./custom/assets/visa.png" style="width: 50px;" alt="'.$payment_method_1.'">
|
||||||
|
</label>';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paypal_enabled){
|
||||||
|
$view .= ' <input id="paypal" type="radio" name="method" value="1" '. ((paypal_default)? 'checked':'') .'>
|
||||||
|
<label for="paypal"><img src="https://www.paypalobjects.com/webstatic/mktg/Logo/pp-logo-100px.png" alt="PayPal Logo"></label>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pay_on_delivery_enabled){
|
||||||
|
$view .= ' <input id="payondelivery" type="radio" name="method" value="2" '. ((pay_on_delivery_default)? 'checked':'') .' >
|
||||||
|
<label for="payondelivery">'.$payment_method_2.'</label>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$view .= ' </div>';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['account_loggedin'])){
|
||||||
|
|
||||||
|
$view .= '
|
||||||
|
<h2>'.$account_create_email.'</h2>
|
||||||
|
<label for="email">'.$account_create_email.' *</label>
|
||||||
|
<input type="email" name="email" id="email" placeholder="'.$account_create_email.'" class="form-field" required>
|
||||||
|
|
||||||
|
<h2 onclick="togglePasswordSection()" style="cursor: pointer;">'.$account_create.((!account_required) ? $account_create_optional : '').' <span id="indicator">▼</span></h2>
|
||||||
|
<div id="password-section" style="display: none;">
|
||||||
|
<label for="password">'.$account_create_password.'</label>
|
||||||
|
<input type="password" name="password" id="password" placeholder="'.$account_create_password.'" class="form-field" autocomplete="new-password">
|
||||||
|
|
||||||
|
<label for="cpassword">'.$account_create_password_confirm.'</label>
|
||||||
|
<input type="password" name="cpassword" id="cpassword" placeholder="'.$account_create_password_confirm.'" class="form-field" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
';
|
||||||
|
}
|
||||||
|
$view .= '
|
||||||
|
<h2>'.$h2_Shipping_details.'</h2>
|
||||||
|
|
||||||
|
<div class="row1">
|
||||||
|
<label for="first_name">'.$shipping_first_name.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['first_name'], ENT_QUOTES).'" name="first_name" id="first_name" placeholder="'.$shipping_first_name.'" class="form-field" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row2">
|
||||||
|
<label for="last_name">'.$shipping_last_name.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['last_name'], ENT_QUOTES).'" name="last_name" id="last_name" placeholder="'.$shipping_last_name.'" class="form-field" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="address_street">'.$shipping_address.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['address_street'], ENT_QUOTES).'" name="address_street" id="address_street" placeholder="'.$shipping_address.'" class="form-field" required>
|
||||||
|
|
||||||
|
<label for="address_city">'.$shipping_city.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['address_city'], ENT_QUOTES).'" name="address_city" id="address_city" placeholder="'.$shipping_city.'" class="form-field" required>
|
||||||
|
|
||||||
|
<div class="row1">
|
||||||
|
<label for="address_state">'.$shipping_state.'</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['address_state'], ENT_QUOTES).'" name="address_state" id="address_state" placeholder="'.$shipping_state.'" class="form-field">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row2">
|
||||||
|
<label for="address_zip">'.$shipping_zip.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars($account['address_zip'], ENT_QUOTES).'" name="address_zip" id="address_zip" placeholder="'.$shipping_zip.'" class="form-field" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<label for="address_phone">'.$shipping_phone.' *</label>
|
||||||
|
<input type="text" value="'.htmlspecialchars(($account['address_phone'] ?? ''), ENT_QUOTES).'" name="address_phone" id="address_phone" placeholder="'.$shipping_phone.'" class="form-field" required>
|
||||||
|
|
||||||
|
<label for="address_country">'.$shipping_country.' *</label>
|
||||||
|
<select name="address_country" class="ajax-update form-field" required>';
|
||||||
|
foreach($countries_in_scope as $key => $value){
|
||||||
|
$view .= ' <option value="'.$key.'" '.($key==(isset($_SESSION['account_loggedin']) ? $account['address_country'] : 21) ? ' selected' : '').'>'.(${$value} ?? $value).'</option>';
|
||||||
|
}
|
||||||
|
$view .= ' </select>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cart-details">
|
||||||
|
|
||||||
|
<h2>'.$h2_shoppingcart.'</h2>
|
||||||
|
|
||||||
|
<table>';
|
||||||
|
foreach($products_in_cart['cart_details']['products'] as $product){
|
||||||
|
|
||||||
|
$view .= ' <tr>
|
||||||
|
<td><img src="'.img_url.$product['meta']['img'].'" width="35" height="35" alt="'.$product['meta']['name'].'"></td>
|
||||||
|
<td>'.$product['quantity'].' x '.$product['meta']['name'].'</td>
|
||||||
|
<td class="price">'.currency_code.''.number_format($product['options_price'] * $product['quantity'],2).'</td>
|
||||||
|
</tr>';
|
||||||
|
}
|
||||||
|
$view .= ' </table>
|
||||||
|
|
||||||
|
<div class="discount-code">
|
||||||
|
<input type="text" class="ajax-update form-field" name="discount_code" placeholder="'.$discount_label.'" value="'.(isset($_SESSION['discount']) ? $_SESSION['discount'] : '').'">
|
||||||
|
<span class="result">';
|
||||||
|
if (isset($_SESSION['discount'], $products_in_cart['totals']['discounttotal'])){
|
||||||
|
$view .= $products_in_cart['totals']['discount_message'];
|
||||||
|
}
|
||||||
|
$view .= ' </span>
|
||||||
|
</div>
|
||||||
|
<div class="shipping-methods-container">';
|
||||||
|
|
||||||
|
if (isset($shipping_methods) && count($shipping_methods) > 0){
|
||||||
|
$view .= ' <div class="shipping-methods">
|
||||||
|
<h3>'.$h3_shipping_method.' *</h3>';
|
||||||
|
|
||||||
|
foreach($shipping_methods as $method){
|
||||||
|
$view .= ' <div class="shipping-method">
|
||||||
|
<input type="radio" class="ajax-update" id="sm'.$method['id'].'" name="shipping_method" value="'.$method['id'].'" required'.(($checkout_input['selected_shipment_method']==$method['id'] || count($shipping_methods) == 1) ? ' checked':'').'>
|
||||||
|
<label for="sm'.$method['id'].'">'.$method['name'].' ('.currency_code.''.number_format($method['price'], 2).')</label>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
$view .= '</div>';
|
||||||
|
|
||||||
|
}
|
||||||
|
$view .= ' </div>
|
||||||
|
<div class="summary">
|
||||||
|
<div class="subtotal">
|
||||||
|
<span>'.$total_subtotal.'</span>
|
||||||
|
<span>'.currency_code.''.number_format($subtotal,2).'</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="shipping">
|
||||||
|
<span>'.$total_shipping.'</span>
|
||||||
|
<span>'.currency_code.''.number_format($shippingtotal,2).'</span>
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
if ($discounttotal > 0){
|
||||||
|
$view .= '<div class="discount">
|
||||||
|
<span>'.$total_discount.'</span>
|
||||||
|
<span>-'.currency_code.''.number_format(round($discounttotal, 1),2).'</span>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($taxtotal > 0){
|
||||||
|
$view .= '<div class="vat">
|
||||||
|
<span>'.($tax_text ?? 'VAT').' <span class="alt">('.$tax_rate.')</span></span>
|
||||||
|
<span>'.currency_code.''.number_format($taxtotal,2).'</span>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
$view .= ' </div>
|
||||||
|
<div class="total">
|
||||||
|
<span>'.$total_total.' <span class="alt">'.$total_total_note.'</span></span><span>'.currency_code.''.number_format($total,2).'</span>
|
||||||
|
</div>
|
||||||
|
<div class="summary">
|
||||||
|
<div class="subtotal">
|
||||||
|
<span>
|
||||||
|
<input type="checkbox" id="consent" name="consent_comms" value="1">'.$order_consent_1.'</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="subtotal">
|
||||||
|
<span>
|
||||||
|
<input type="checkbox" id="consent" name="consent" value="1" required>'.$order_consent_2.' * <a href="'.$terms_link.'" target="_blank">'.$order_consent_3.'</a> '.$order_consent_4.' <a href="'.$privacy_link.'" target="_blank">'.$order_consent_5.'</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<button type="submit" name="checkout" class="checkout_btn">'.$btn_place_order.'</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
';
|
||||||
|
|
||||||
|
echo '<script>
|
||||||
|
function togglePasswordSection() {
|
||||||
|
var section = document.getElementById(\'password-section\');
|
||||||
|
var indicator = document.getElementById(\'indicator\');
|
||||||
|
if (section.style.display === \'none\') {
|
||||||
|
section.style.display = \'block\';
|
||||||
|
indicator.textContent = \'▲\';
|
||||||
|
} else {
|
||||||
|
section.style.display = \'none\';
|
||||||
|
indicator.textContent = \'▼\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
';
|
||||||
|
|
||||||
|
$view .= template_footer();
|
||||||
|
|
||||||
|
//OUTPUT
|
||||||
|
echo $view;
|
||||||
|
|
||||||
|
?>
|
||||||
5660
log/log_02.txt
1113
log/log_03.txt
2699
log/log_04.txt
247
log/log_05.txt
@@ -1,247 +0,0 @@
|
|||||||
2025-05-01 13:26:30;/v2/authorization
|
|
||||||
2025-05-01 13:26:30;/v2/catalog/category=22
|
|
||||||
2025-05-01 13:27:06;/v2/authorization
|
|
||||||
2025-05-01 13:27:07;/v2/authorization
|
|
||||||
2025-05-01 13:27:07;/v2/catalog/category=22
|
|
||||||
2025-05-01 17:33:32;/v2/authorization
|
|
||||||
2025-05-01 17:33:32;/v2/catalog/category=22
|
|
||||||
2025-05-01 21:17:53;/v2/authorization
|
|
||||||
2025-05-01 21:17:53;/v2/catalog/category=22
|
|
||||||
2025-05-04 09:58:52;/v2/authorization
|
|
||||||
2025-05-04 09:58:52;/v2/catalog/category=22
|
|
||||||
2025-05-04 10:04:17;/v2/authorization
|
|
||||||
2025-05-04 10:04:17;/v2/authorization
|
|
||||||
2025-05-04 10:04:17;/v2/authorization
|
|
||||||
2025-05-04 10:04:17;/v2/authorization
|
|
||||||
2025-05-04 10:04:17;/v2/authorization
|
|
||||||
2025-05-04 10:04:17;/v2/catalog/category=22
|
|
||||||
2025-05-04 10:04:17;/v2/authorization
|
|
||||||
2025-05-04 10:04:17;/v2/authorization
|
|
||||||
2025-05-04 10:04:17;/v2/catalog/category=22
|
|
||||||
2025-05-04 10:04:17;/v2/authorization
|
|
||||||
2025-05-04 10:04:18;/v2/catalog/category=22
|
|
||||||
2025-05-04 10:04:18;/v2/authorization
|
|
||||||
2025-05-04 10:04:18;/v2/catalog/category=22
|
|
||||||
2025-05-04 10:04:18;/v2/authorization
|
|
||||||
2025-05-04 10:04:18;/v2/catalog/category=22
|
|
||||||
2025-05-07 15:11:15;/v2/authorization
|
|
||||||
2025-05-07 15:11:15;/v2/catalog/category=22
|
|
||||||
2025-05-07 15:12:33;/v2/authorization
|
|
||||||
2025-05-07 15:12:33;/v2/catalog/category=22
|
|
||||||
2025-05-08 19:41:48;/v2/authorization
|
|
||||||
2025-05-08 19:41:48;/v2/catalog/category=22
|
|
||||||
2025-05-08 19:42:02;/v2/authorization
|
|
||||||
2025-05-08 19:42:02;/v2/authorization
|
|
||||||
2025-05-08 19:42:02;/v2/catalog/category=22
|
|
||||||
2025-05-08 19:42:10;/v2/authorization
|
|
||||||
2025-05-08 19:42:10;/v2/categories/
|
|
||||||
2025-05-08 19:42:10;/v2/catalog/category=17
|
|
||||||
2025-05-08 19:42:24;/v2/authorization
|
|
||||||
2025-05-08 19:42:28;/v2/authorization
|
|
||||||
2025-05-08 19:42:28;/v2/identity/
|
|
||||||
2025-05-08 19:42:28;/v2/authorization
|
|
||||||
2025-05-08 19:42:28;/v2/transactions_items/account_id=d808773e1ba5292d7c640d04ed04c1fbc32cce74a83d334061
|
|
||||||
2025-05-08 19:42:28;/v2/identity/userkey=d808773e1ba5292d7c640d04ed04c1fbc32cce74a83d334061
|
|
||||||
2025-05-08 19:42:55;/v2/authorization
|
|
||||||
2025-05-08 19:42:56;/v2/catalog/category=22
|
|
||||||
2025-05-08 19:43:08;/v2/authorization
|
|
||||||
2025-05-08 19:43:08;/v2/categories/
|
|
||||||
2025-05-08 19:43:09;/v2/catalog/category=17
|
|
||||||
2025-05-08 19:43:14;/v2/authorization
|
|
||||||
2025-05-08 19:43:14;/v2/catalog/category=22
|
|
||||||
2025-05-08 19:43:19;/v2/authorization
|
|
||||||
2025-05-08 19:43:19;/v2/catalog/category=22
|
|
||||||
2025-05-08 19:43:27;/v2/authorization
|
|
||||||
2025-05-08 19:43:27;/v2/categories/
|
|
||||||
2025-05-08 19:43:27;/v2/catalog/category=17
|
|
||||||
2025-05-08 19:45:41;/v2/authorization
|
|
||||||
2025-05-08 19:45:46;/v2/authorization
|
|
||||||
2025-05-08 19:45:46;/v2/categories/
|
|
||||||
2025-05-08 19:45:46;/v2/catalog/category=17
|
|
||||||
2025-05-08 19:45:47;/v2/authorization
|
|
||||||
2025-05-08 19:45:47;/v2/catalog/category=22
|
|
||||||
2025-05-08 19:54:20;/v2/authorization
|
|
||||||
2025-05-08 19:54:21;/v2/catalog/category=22
|
|
||||||
2025-05-09 11:12:58;/v2/authorization
|
|
||||||
2025-05-09 11:12:58;/v2/catalog/category=22
|
|
||||||
2025-05-09 11:13:01;/v2/authorization
|
|
||||||
2025-05-09 11:13:01;/v2/catalog/category=22
|
|
||||||
2025-05-09 11:14:06;/v2/authorization
|
|
||||||
2025-05-09 11:14:07;/v2/catalog/category=22
|
|
||||||
2025-05-09 11:14:42;/v2/authorization
|
|
||||||
2025-05-09 11:14:42;/v2/authorization
|
|
||||||
2025-05-09 11:14:42;/v2/catalog/category=22
|
|
||||||
2025-05-09 11:14:42;/v2/catalog/category=22
|
|
||||||
2025-05-09 11:45:34;/v2/authorization
|
|
||||||
2025-05-09 11:45:34;/v2/catalog/category=22
|
|
||||||
2025-05-09 11:45:39;/v2/authorization
|
|
||||||
2025-05-09 11:45:39;/v2/catalog/category=22
|
|
||||||
2025-05-09 11:45:48;/v2/authorization
|
|
||||||
2025-05-09 11:45:48;/v2/catalog/category=22
|
|
||||||
2025-05-09 11:45:49;/v2/authorization
|
|
||||||
2025-05-09 12:56:57;/v2/authorization
|
|
||||||
2025-05-09 12:56:57;/v2/catalog/category=22
|
|
||||||
2025-05-09 13:08:28;/v2/authorization
|
|
||||||
2025-05-09 13:08:29;/v2/catalog/category=22
|
|
||||||
2025-05-09 13:44:52;/v2/authorization
|
|
||||||
2025-05-09 13:44:52;/v2/catalog/category=22
|
|
||||||
2025-05-09 13:44:55;/v2/authorization
|
|
||||||
2025-05-09 13:44:56;/v2/authorization
|
|
||||||
2025-05-09 13:44:56;/v2/catalog/category=22
|
|
||||||
2025-05-09 15:15:07;/v2/authorization
|
|
||||||
2025-05-09 15:15:07;/v2/catalog/category=22
|
|
||||||
2025-05-09 21:10:30;/v2/authorization
|
|
||||||
2025-05-09 21:10:30;/v2/catalog/category=22
|
|
||||||
2025-05-10 20:03:56;/v2/authorization
|
|
||||||
2025-05-10 20:03:56;/v2/catalog/category=22
|
|
||||||
2025-05-10 20:03:57;/v2/authorization
|
|
||||||
2025-05-10 20:03:57;/v2/catalog/category=22
|
|
||||||
2025-05-11 03:21:55;/v2/authorization
|
|
||||||
2025-05-11 03:21:55;/v2/catalog/category=22
|
|
||||||
2025-05-11 03:21:57;/v2/authorization
|
|
||||||
2025-05-11 03:21:57;/v2/authorization
|
|
||||||
2025-05-11 03:21:57;/v2/catalog/category=22
|
|
||||||
2025-05-11 04:50:31;/v2/authorization
|
|
||||||
2025-05-11 04:50:31;/v2/catalog/category=22
|
|
||||||
2025-05-11 20:21:12;/v2/authorization
|
|
||||||
2025-05-11 20:21:12;/v2/catalog/category=22
|
|
||||||
2025-05-12 10:07:48;/v2/authorization
|
|
||||||
2025-05-12 10:07:49;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:36;/v2/authorization
|
|
||||||
2025-05-13 09:08:36;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:37;/v2/authorization
|
|
||||||
2025-05-13 09:08:37;/v2/authorization
|
|
||||||
2025-05-13 09:08:38;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:40;/v2/authorization
|
|
||||||
2025-05-13 09:08:40;/v2/authorization
|
|
||||||
2025-05-13 09:08:46;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:47;/v2/authorization
|
|
||||||
2025-05-13 09:08:47;/v2/authorization
|
|
||||||
2025-05-13 09:08:47;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:47;/v2/authorization
|
|
||||||
2025-05-13 09:08:48;/v2/authorization
|
|
||||||
2025-05-13 09:08:48;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:50;/v2/authorization
|
|
||||||
2025-05-13 09:08:50;/v2/authorization
|
|
||||||
2025-05-13 09:08:50;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:52;/v2/authorization
|
|
||||||
2025-05-13 09:08:52;/v2/authorization
|
|
||||||
2025-05-13 09:08:52;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:53;/v2/authorization
|
|
||||||
2025-05-13 09:08:53;/v2/authorization
|
|
||||||
2025-05-13 09:08:53;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:55;/v2/authorization
|
|
||||||
2025-05-13 09:08:57;/v2/authorization
|
|
||||||
2025-05-13 09:08:57;/v2/authorization
|
|
||||||
2025-05-13 09:08:57;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:58;/v2/authorization
|
|
||||||
2025-05-13 09:08:58;/v2/authorization
|
|
||||||
2025-05-13 09:08:59;/v2/catalog/category=22
|
|
||||||
2025-05-13 09:08:59;/v2/authorization
|
|
||||||
2025-05-13 09:08:59;/v2/authorization
|
|
||||||
2025-05-13 09:08:59;/v2/catalog/category=22
|
|
||||||
2025-05-13 13:14:28;/v2/authorization
|
|
||||||
2025-05-13 13:14:28;/v2/catalog/category=22
|
|
||||||
2025-05-13 13:14:41;/v2/authorization
|
|
||||||
2025-05-13 13:14:42;/v2/catalog/product_id=thomasII_navy_blue
|
|
||||||
2025-05-13 13:14:42;/v2/products_media/product_id=60
|
|
||||||
2025-05-13 13:15:02;/v2/authorization
|
|
||||||
2025-05-13 13:15:03;/v2/catalog/category=22
|
|
||||||
2025-05-13 13:15:42;/v2/authorization
|
|
||||||
2025-05-13 13:15:42;/v2/catalog/product_id=thomasII_navy_blue
|
|
||||||
2025-05-13 13:15:42;/v2/products_media/product_id=60
|
|
||||||
2025-05-13 13:15:56;/v2/authorization
|
|
||||||
2025-05-13 13:15:56;/v2/authorization
|
|
||||||
2025-05-13 13:15:56;/v2/catalog/category=22
|
|
||||||
2025-05-13 13:16:10;/v2/authorization
|
|
||||||
2025-05-13 13:16:10;/v2/catalog/category=22
|
|
||||||
2025-05-13 13:16:25;/v2/authorization
|
|
||||||
2025-05-13 13:16:26;/v2/authorization
|
|
||||||
2025-05-13 13:16:26;/v2/catalog/category=22
|
|
||||||
2025-05-13 13:16:36;/v2/authorization
|
|
||||||
2025-05-13 13:16:37;/v2/authorization
|
|
||||||
2025-05-13 13:16:37;/v2/catalog/category=22
|
|
||||||
2025-05-13 13:16:43;/v2/authorization
|
|
||||||
2025-05-13 13:16:43;/v2/catalog/product_id=thomasII_ice_blue
|
|
||||||
2025-05-13 13:16:43;/v2/products_media/product_id=61
|
|
||||||
2025-05-13 13:18:40;/v2/authorization
|
|
||||||
2025-05-13 13:18:40;/v2/catalog/category=22
|
|
||||||
2025-05-13 14:05:58;/v2/authorization
|
|
||||||
2025-05-13 14:05:58;/v2/authorization
|
|
||||||
2025-05-13 14:05:58;/v2/authorization
|
|
||||||
2025-05-13 14:05:59;/v2/catalog/category=22
|
|
||||||
2025-05-13 14:05:59;/v2/authorization
|
|
||||||
2025-05-13 14:05:59;/v2/authorization
|
|
||||||
2025-05-13 14:05:59;/v2/catalog/category=22
|
|
||||||
2025-05-13 14:59:33;/v2/authorization
|
|
||||||
2025-05-13 14:59:33;/v2/catalog/category=22
|
|
||||||
2025-05-13 15:00:23;/v2/authorization
|
|
||||||
2025-05-13 15:00:23;/v2/catalog/category=22
|
|
||||||
2025-05-13 15:01:35;/v2/authorization
|
|
||||||
2025-05-13 15:01:36;/v2/catalog/category=22
|
|
||||||
2025-05-13 15:49:43;/v2/authorization
|
|
||||||
2025-05-13 15:49:43;/v2/catalog/category=22
|
|
||||||
2025-05-13 15:56:55;/v2/authorization
|
|
||||||
2025-05-13 15:56:56;/v2/catalog/category=22
|
|
||||||
2025-05-13 15:57:01;/v2/authorization
|
|
||||||
2025-05-13 15:57:01;/v2/catalog/product_id=thomasII_dolphin_gray
|
|
||||||
2025-05-13 15:57:01;/v2/products_media/product_id=63
|
|
||||||
2025-05-13 15:57:03;/v2/authorization
|
|
||||||
2025-05-13 15:57:03;/v2/catalog/category=22
|
|
||||||
2025-05-13 15:57:30;/v2/authorization
|
|
||||||
2025-05-13 15:57:30;/v2/catalog/product_id=thomasII_racing_green
|
|
||||||
2025-05-13 15:57:30;/v2/products_media/product_id=62
|
|
||||||
2025-05-13 15:57:38;/v2/authorization
|
|
||||||
2025-05-13 15:57:38;/v2/catalog/category=22
|
|
||||||
2025-05-13 15:57:58;/v2/authorization
|
|
||||||
2025-05-13 15:57:58;/v2/categories/
|
|
||||||
2025-05-13 15:57:58;/v2/catalog/category=17
|
|
||||||
2025-05-13 15:58:06;/v2/authorization
|
|
||||||
2025-05-13 15:58:06;/v2/categories/
|
|
||||||
2025-05-13 15:58:06;/v2/catalog/category=23
|
|
||||||
2025-05-13 15:58:32;/v2/authorization
|
|
||||||
2025-05-13 15:58:32;/v2/categories/
|
|
||||||
2025-05-13 15:58:32;/v2/catalog/category=17
|
|
||||||
2025-05-13 15:58:48;/v2/authorization
|
|
||||||
2025-05-13 15:58:48;/v2/catalog/category=22
|
|
||||||
2025-05-13 17:39:53;/v2/authorization
|
|
||||||
2025-05-13 17:39:53;/v2/catalog/category=22
|
|
||||||
2025-05-13 18:07:39;/v2/authorization
|
|
||||||
2025-05-13 18:07:39;/v2/catalog/category=22
|
|
||||||
2025-05-13 22:58:35;/v2/authorization
|
|
||||||
2025-05-13 22:58:35;/v2/catalog/category=22
|
|
||||||
2025-05-15 22:34:09;/v2/authorization
|
|
||||||
2025-05-15 22:34:09;/v2/catalog/category=22
|
|
||||||
2025-05-21 14:46:27;/v2/authorization
|
|
||||||
2025-05-21 14:46:27;/v2/catalog/category=22
|
|
||||||
2025-05-21 14:46:28;/v2/authorization
|
|
||||||
2025-05-21 14:46:28;/v2/authorization
|
|
||||||
2025-05-21 14:46:29;/v2/catalog/category=22
|
|
||||||
2025-05-21 14:46:30;/v2/authorization
|
|
||||||
2025-05-21 14:46:30;/v2/catalog/product_id=thomasII_dolphin_gray
|
|
||||||
2025-05-21 14:46:30;/v2/products_media/product_id=63
|
|
||||||
2025-05-21 14:46:30;/v2/authorization
|
|
||||||
2025-05-21 14:46:30;/v2/authorization
|
|
||||||
2025-05-21 14:46:30;/v2/catalog/category=22
|
|
||||||
2025-05-21 14:46:31;/v2/authorization
|
|
||||||
2025-05-21 14:46:31;/v2/authorization
|
|
||||||
2025-05-21 14:46:31;/v2/catalog/category=22
|
|
||||||
2025-05-21 20:44:30;/v2/authorization
|
|
||||||
2025-05-21 20:44:30;/v2/catalog/category=22
|
|
||||||
2025-05-22 17:16:25;/v2/authorization
|
|
||||||
2025-05-22 17:16:25;/v2/catalog/category=22
|
|
||||||
2025-05-22 17:16:27;/v2/authorization
|
|
||||||
2025-05-22 17:16:27;/v2/catalog/category=22
|
|
||||||
2025-05-22 17:16:28;/v2/authorization
|
|
||||||
2025-05-22 17:16:28;/v2/catalog/category=22
|
|
||||||
2025-05-22 17:16:28;/v2/authorization
|
|
||||||
2025-05-22 17:16:29;/v2/catalog/category=22
|
|
||||||
2025-05-23 06:16:09;/v2/authorization
|
|
||||||
2025-05-23 06:16:09;/v2/catalog/category=22
|
|
||||||
2025-05-23 06:16:12;/v2/authorization
|
|
||||||
2025-05-23 06:16:13;/v2/authorization
|
|
||||||
2025-05-23 06:16:13;/v2/catalog/category=22
|
|
||||||
2025-05-23 22:27:40;/v2/authorization
|
|
||||||
2025-05-23 22:27:40;/v2/catalog/category=22
|
|
||||||
2025-05-25 20:27:10;/v2/authorization
|
|
||||||
2025-05-25 20:27:11;/v2/catalog/category=22
|
|
||||||
608
log/logging.php
Normal file
@@ -0,0 +1,608 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>System Logging</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--primary-green: #22c55e;
|
||||||
|
--white: #ffffff;
|
||||||
|
--gray-50: #f9fafb;
|
||||||
|
--gray-100: #f3f4f6;
|
||||||
|
--gray-200: #e5e7eb;
|
||||||
|
--gray-300: #d1d5db;
|
||||||
|
--gray-500: #6b7280;
|
||||||
|
--gray-600: #4b5563;
|
||||||
|
--gray-700: #374151;
|
||||||
|
--gray-900: #111827;
|
||||||
|
--space-xs: 0.25rem;
|
||||||
|
--space-sm: 0.5rem;
|
||||||
|
--space-md: 0.75rem;
|
||||||
|
--space-lg: 1rem;
|
||||||
|
--space-xl: 1.5rem;
|
||||||
|
--radius-md: 0.375rem;
|
||||||
|
--radius-lg: 0.5rem;
|
||||||
|
--font-size-sm: 0.875rem;
|
||||||
|
--font-size-base: 1rem;
|
||||||
|
--font-size-lg: 1.125rem;
|
||||||
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||||
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
background: var(--gray-50);
|
||||||
|
color: var(--gray-900);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-area {
|
||||||
|
padding: var(--space-xl);
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: var(--white);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
|
border: 1px solid var(--gray-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card__header {
|
||||||
|
padding: var(--space-xl);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card__title {
|
||||||
|
font-size: 1.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--gray-900);
|
||||||
|
margin-bottom: var(--space-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card__subtitle {
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
color: var(--gray-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
border: 1px solid var(--gray-300);
|
||||||
|
background: var(--white);
|
||||||
|
color: var(--gray-700);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
background: var(--gray-50);
|
||||||
|
border-color: var(--gray-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--secondary {
|
||||||
|
background: var(--gray-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--sm {
|
||||||
|
padding: var(--space-sm) var(--space-md);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<?php
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// POST HANDLER - Delete all logs
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
$delete_message = '';
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_all_logs'])) {
|
||||||
|
$logs_dir = __DIR__ . '/';
|
||||||
|
$deleted_count = 0;
|
||||||
|
|
||||||
|
if (is_dir($logs_dir)) {
|
||||||
|
$files = scandir($logs_dir);
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if (preg_match('/\.txt$/', $file)) {
|
||||||
|
if (unlink($logs_dir . $file)) {
|
||||||
|
$deleted_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$delete_message = "Successfully deleted $deleted_count log file(s).";
|
||||||
|
// Redirect to clear POST data
|
||||||
|
header("Location: " . strtok($_SERVER["REQUEST_URI"], '?') . "?deleted=$deleted_count");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show delete confirmation message
|
||||||
|
if (isset($_GET['deleted'])) {
|
||||||
|
$delete_message = "Successfully deleted " . intval($_GET['deleted']) . " log file(s).";
|
||||||
|
}
|
||||||
|
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// GET HANDLER
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
// Get selected log file from query parameter
|
||||||
|
$selected_log = $_GET['log'] ?? '';
|
||||||
|
|
||||||
|
// Scan logs directory for all log files
|
||||||
|
// Use __DIR__ to get current directory of this script
|
||||||
|
$logs_dir = __DIR__ . '/';
|
||||||
|
$log_files = [];
|
||||||
|
|
||||||
|
if (is_dir($logs_dir)) {
|
||||||
|
$files = scandir($logs_dir);
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if (preg_match('/\.txt$/', $file) && is_file($logs_dir . $file)) {
|
||||||
|
// Extract date from filename (last 2 digits before .txt)
|
||||||
|
$date = '00'; // Default date
|
||||||
|
if (preg_match('/_(\d{2})\.txt$/', $file, $matches)) {
|
||||||
|
$date = $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
$log_files[] = [
|
||||||
|
'filename' => $file,
|
||||||
|
'date' => $date,
|
||||||
|
'path' => $logs_dir . $file,
|
||||||
|
'size' => filesize($logs_dir . $file)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by date descending, then by filename
|
||||||
|
usort($log_files, function($a, $b) {
|
||||||
|
if ($a['date'] === $b['date']) {
|
||||||
|
return strcmp($b['filename'], $a['filename']);
|
||||||
|
}
|
||||||
|
return $b['date'] <=> $a['date'];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load selected log content
|
||||||
|
$contents = '';
|
||||||
|
if ($selected_log && file_exists($logs_dir . $selected_log)) {
|
||||||
|
$contents = file_get_contents($logs_dir . $selected_log);
|
||||||
|
} elseif (!empty($log_files)) {
|
||||||
|
// Default to most recent log
|
||||||
|
$contents = file_get_contents($log_files[0]['path']);
|
||||||
|
$selected_log = $log_files[0]['filename'];
|
||||||
|
} else {
|
||||||
|
$contents = 'No application log files found.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$filelocation_webserver = '/var/www/vhosts/morvalwatches.com/logs/'.$_SERVER['HTTP_HOST'].'/access_ssl_log';
|
||||||
|
|
||||||
|
if (file_exists($filelocation_webserver)){
|
||||||
|
$contents_webserver = file_get_contents($filelocation_webserver);
|
||||||
|
} else {$contents_webserver = 'No webserver log file found.';}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!-- Main Content Area --><?php
|
||||||
|
// Display delete message if exists
|
||||||
|
if ($delete_message) {
|
||||||
|
echo '<div style="
|
||||||
|
position: fixed;
|
||||||
|
top: var(--space-lg);
|
||||||
|
right: var(--space-lg);
|
||||||
|
background: var(--primary-green);
|
||||||
|
color: var(--white);
|
||||||
|
padding: var(--space-md) var(--space-lg);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
|
z-index: 1000;
|
||||||
|
font-weight: 500;
|
||||||
|
" id="delete-notification">
|
||||||
|
✓ ' . htmlspecialchars($delete_message) . '
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<div class="content-area">
|
||||||
|
<div class="w-full">
|
||||||
|
<!-- Tab Navigation -->
|
||||||
|
<div style="
|
||||||
|
background: var(--white);
|
||||||
|
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
|
||||||
|
border: 1px solid var(--gray-200);
|
||||||
|
border-bottom: none;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
">
|
||||||
|
<div style="
|
||||||
|
display: flex;
|
||||||
|
gap: 0;
|
||||||
|
padding: var(--space-sm);
|
||||||
|
background: var(--gray-50);
|
||||||
|
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
|
||||||
|
">
|
||||||
|
<button
|
||||||
|
class="tab-button active"
|
||||||
|
onclick="switchTab(\'app\', this)"
|
||||||
|
style="
|
||||||
|
flex: 1;
|
||||||
|
padding: var(--space-md) var(--space-xl);
|
||||||
|
border: none;
|
||||||
|
background: var(--primary-green);
|
||||||
|
color: var(--white);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
margin-right: var(--space-sm);
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
"
|
||||||
|
onmouseover="if(!this.classList.contains(\'active\')) { this.style.background=\'var(--gray-200)\'; this.style.color=\'var(--gray-700)\'; }"
|
||||||
|
onmouseout="if(!this.classList.contains(\'active\')) { this.style.background=\'var(--gray-100)\'; this.style.color=\'var(--gray-600)\'; }"
|
||||||
|
>
|
||||||
|
Application Log
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="tab-button"
|
||||||
|
onclick="switchTab(\'webserver\', this)"
|
||||||
|
style="
|
||||||
|
flex: 1;
|
||||||
|
padding: var(--space-md) var(--space-xl);
|
||||||
|
border: none;
|
||||||
|
background: var(--gray-100);
|
||||||
|
color: var(--gray-600);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
"
|
||||||
|
onmouseover="if(!this.classList.contains(\'active\')) { this.style.background=\'var(--gray-200)\'; this.style.color=\'var(--gray-700)\'; }"
|
||||||
|
onmouseout="if(!this.classList.contains(\'active\')) { this.style.background=\'var(--gray-100)\'; this.style.color=\'var(--gray-600)\'; }"
|
||||||
|
>
|
||||||
|
Webserver Log
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tab Content Container -->
|
||||||
|
<div style="
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--gray-200);
|
||||||
|
border-radius: 0 0 var(--radius-lg) var(--radius-lg);
|
||||||
|
padding: var(--space-xl);
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
|
min-height: 70vh;
|
||||||
|
">
|
||||||
|
<!-- Application Log Tab -->
|
||||||
|
<div id="tab-app" class="tab-content active" style="display: block;">
|
||||||
|
<div style="
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: var(--space-lg);
|
||||||
|
padding-bottom: var(--space-md);
|
||||||
|
border-bottom: 1px solid var(--gray-200);
|
||||||
|
">
|
||||||
|
<div style="flex: 1;">
|
||||||
|
<h3 style="
|
||||||
|
margin: 0;
|
||||||
|
color: var(--gray-900);
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
font-weight: 600;
|
||||||
|
">Application Log</h3>
|
||||||
|
<div style="
|
||||||
|
margin-top: var(--space-sm);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-sm);
|
||||||
|
">
|
||||||
|
<label style="
|
||||||
|
color: var(--gray-600);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-weight: 500;
|
||||||
|
">Select Log File:</label>
|
||||||
|
<select
|
||||||
|
id="log-file-selector"
|
||||||
|
onchange="loadLogFile(this.value)"
|
||||||
|
style="
|
||||||
|
padding: var(--space-xs) var(--space-md);
|
||||||
|
border: 1px solid var(--gray-300);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
background: var(--white);
|
||||||
|
color: var(--gray-700);
|
||||||
|
cursor: pointer;
|
||||||
|
min-width: 250px;
|
||||||
|
"
|
||||||
|
>';
|
||||||
|
|
||||||
|
foreach ($log_files as $log) {
|
||||||
|
$selected = ($log['filename'] === $selected_log) ? 'selected' : '';
|
||||||
|
$size_kb = round($log['size'] / 1024, 2);
|
||||||
|
echo '<option value="'.htmlspecialchars($log['filename']).'" '.$selected.'>'.htmlspecialchars($log['filename']).' ('.$size_kb.' KB)</option>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; gap: var(--space-sm);">
|
||||||
|
<button
|
||||||
|
onclick="refreshLog(\'app\')"
|
||||||
|
class="btn btn--secondary btn--sm"
|
||||||
|
style="
|
||||||
|
padding: var(--space-sm) var(--space-md);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-xs);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
🔄 Refresh
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onclick="clearLogContent(\'app-log\')"
|
||||||
|
class="btn btn--secondary btn--sm"
|
||||||
|
style="
|
||||||
|
padding: var(--space-sm) var(--space-md);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-xs);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
🗑️ Clear View
|
||||||
|
</button>
|
||||||
|
<form method="POST" onsubmit="return confirmDeleteAll()" style="margin: 0; display: inline;">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
name="delete_all_logs"
|
||||||
|
class="btn btn--sm"
|
||||||
|
style="
|
||||||
|
padding: var(--space-sm) var(--space-md);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
background: #ef4444;
|
||||||
|
color: var(--white);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-xs);
|
||||||
|
"
|
||||||
|
onmouseover="this.style.background=\'#dc2626\'"
|
||||||
|
onmouseout="this.style.background=\'#ef4444\'"
|
||||||
|
>
|
||||||
|
🗑️ Delete All Logs
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
id="app-log"
|
||||||
|
readonly
|
||||||
|
style="
|
||||||
|
width: 100%;
|
||||||
|
min-height: 60vh;
|
||||||
|
padding: var(--space-lg);
|
||||||
|
border: 1px solid var(--gray-300);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
font-family: \'Courier New\', monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
background: var(--gray-900);
|
||||||
|
color: var(--gray-100);
|
||||||
|
resize: vertical;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
"
|
||||||
|
placeholder="No log content available..."
|
||||||
|
>'.htmlspecialchars($contents).'</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Webserver Log Tab -->
|
||||||
|
<div id="tab-webserver" class="tab-content" style="display: none;">
|
||||||
|
<div style="
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: var(--space-lg);
|
||||||
|
padding-bottom: var(--space-md);
|
||||||
|
border-bottom: 1px solid var(--gray-200);
|
||||||
|
">
|
||||||
|
<div>
|
||||||
|
<h3 style="
|
||||||
|
margin: 0;
|
||||||
|
color: var(--gray-900);
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
font-weight: 600;
|
||||||
|
">Webserver Access Log</h3>
|
||||||
|
<p style="
|
||||||
|
margin: var(--space-xs) 0 0;
|
||||||
|
color: var(--gray-500);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
">File: '.$filelocation_webserver.'</p>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; gap: var(--space-sm);">
|
||||||
|
<button
|
||||||
|
onclick="refreshLog(\'webserver\')"
|
||||||
|
class="btn btn--secondary btn--sm"
|
||||||
|
style="
|
||||||
|
padding: var(--space-sm) var(--space-md);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-xs);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
🔄 Refresh
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onclick="clearLogContent(\'webserver-log\')"
|
||||||
|
class="btn btn--secondary btn--sm"
|
||||||
|
style="
|
||||||
|
padding: var(--space-sm) var(--space-md);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-xs);
|
||||||
|
"
|
||||||
|
>
|
||||||
|
🗑️ Clear View
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
id="webserver-log"
|
||||||
|
readonly
|
||||||
|
style="
|
||||||
|
width: 100%;
|
||||||
|
min-height: 60vh;
|
||||||
|
padding: var(--space-lg);
|
||||||
|
border: 1px solid var(--gray-300);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
font-family: \'Courier New\', monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
background: var(--gray-900);
|
||||||
|
color: var(--gray-100);
|
||||||
|
resize: vertical;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
"
|
||||||
|
placeholder="No log content available..."
|
||||||
|
>'.htmlspecialchars($contents_webserver).'</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
'; ?>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Confirm delete all logs
|
||||||
|
function confirmDeleteAll() {
|
||||||
|
return confirm('⚠️ WARNING: This will permanently delete ALL log files in the logs directory.\n\nAre you absolutely sure you want to continue?');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-hide delete notification
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const notification = document.getElementById('delete-notification');
|
||||||
|
if (notification) {
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.style.opacity = '0';
|
||||||
|
notification.style.transition = 'opacity 0.5s ease';
|
||||||
|
setTimeout(() => notification.remove(), 500);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Tab switching functionality
|
||||||
|
function switchTab(tabName, clickedButton) {
|
||||||
|
// Hide all tab contents
|
||||||
|
const tabContents = document.querySelectorAll('.tab-content');
|
||||||
|
tabContents.forEach(content => {
|
||||||
|
content.style.display = 'none';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove active class and reset styles for all tab buttons
|
||||||
|
const tabButtons = document.querySelectorAll('.tab-button');
|
||||||
|
tabButtons.forEach(button => {
|
||||||
|
button.classList.remove('active');
|
||||||
|
button.style.background = 'var(--gray-100)';
|
||||||
|
button.style.color = 'var(--gray-600)';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show the selected tab content
|
||||||
|
const selectedTab = document.getElementById('tab-' + tabName);
|
||||||
|
if (selectedTab) {
|
||||||
|
selectedTab.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add active class and style to clicked button
|
||||||
|
clickedButton.classList.add('active');
|
||||||
|
clickedButton.style.background = 'var(--primary-green)';
|
||||||
|
clickedButton.style.color = 'var(--white)';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load selected log file
|
||||||
|
function loadLogFile(filename) {
|
||||||
|
if (filename) {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
url.searchParams.set('log', filename);
|
||||||
|
window.location.href = url.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh log functionality
|
||||||
|
function refreshLog(logType) {
|
||||||
|
const button = event.target.closest('button');
|
||||||
|
const originalText = button.innerHTML;
|
||||||
|
|
||||||
|
// Show loading state
|
||||||
|
button.innerHTML = '⏳ Refreshing...';
|
||||||
|
button.disabled = true;
|
||||||
|
|
||||||
|
// Simulate refresh (reload the page to get fresh content)
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear log content from view
|
||||||
|
function clearLogContent(textareaId) {
|
||||||
|
const textarea = document.getElementById(textareaId);
|
||||||
|
if (textarea) {
|
||||||
|
if (confirm('Clear the log content from view? (This won\'t delete the actual log file)')) {
|
||||||
|
textarea.value = '';
|
||||||
|
|
||||||
|
// Show notification
|
||||||
|
showNotification('Log view cleared', 'info');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show notification function
|
||||||
|
|
||||||
|
|
||||||
|
// Add CSS animations
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
@keyframes slideInRight {
|
||||||
|
from { opacity: 0; transform: translateX(100%); }
|
||||||
|
to { opacity: 1; transform: translateX(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideOutRight {
|
||||||
|
from { opacity: 1; transform: translateX(0); }
|
||||||
|
to { opacity: 0; transform: translateX(100%); }
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
|
||||||
|
// Auto-scroll to bottom of logs when page loads
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const activeTextarea = document.querySelector('.tab-content.active textarea');
|
||||||
|
if (activeTextarea && activeTextarea.value.trim()) {
|
||||||
|
activeTextarea.scrollTop = activeTextarea.scrollHeight;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle checkbox values (existing functionality)
|
||||||
|
document.querySelectorAll("input[type='checkbox']").forEach(checkbox => {
|
||||||
|
checkbox.onclick = () => checkbox.value = checkbox.checked ? 'true' : 'false';
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
5463
log/main.css
Normal file
@@ -1,209 +0,0 @@
|
|||||||
<?php
|
|
||||||
$h2_brand_name_1 = 'MorvalWatches';
|
|
||||||
$h2_brand_name_2 = 'eine Marke mit einer Geschichte';
|
|
||||||
$h2_brand_visit = 'Besuche unsere Kollektion';
|
|
||||||
$h2_brand_wow = 'Morval vereint eine einzigartige Kombination aus minimalistischem Design, Schweizer Qualität und niederländischer Fertigung.Wir bieten Ihnen eine Uhr, die zu jedem Anlass getragen werden kann.';
|
|
||||||
$h1_content_top = 'Unsere Uhrenkollektion';
|
|
||||||
$product_count_1 = 'Produkt';
|
|
||||||
$product_count_2 = 'e';
|
|
||||||
$main_filter_category = 'Kategorie';
|
|
||||||
$main_category = 'Alle';
|
|
||||||
$main_filter_sort = 'Sortieren';
|
|
||||||
$sort1 = 'A-Z';
|
|
||||||
$sort2 = 'Z-A';
|
|
||||||
$sort3 = 'Neueste';
|
|
||||||
$sort4 = 'Älteste';
|
|
||||||
$sort5 = 'Preis hoch - niedrig';
|
|
||||||
$sort6 = 'Preis niedrig - hoch';
|
|
||||||
$free_delivery = 'kostenloser Versand';
|
|
||||||
$non_free_delivery = 'kostenloser Versand ab';
|
|
||||||
$breadcrum_products = 'Kollektion';
|
|
||||||
$product_quantity = 'Menge';
|
|
||||||
$product_on_stock = 'Auf Lager';
|
|
||||||
$out_of_stock_notify = 'Benachrichtigen Sie mich';
|
|
||||||
$out_of_stock_notify_2 = 'Besuchen Sie uns @';
|
|
||||||
$out_of_stock = 'Nicht auf Lager';
|
|
||||||
$add_to_basket = 'In den Warenkorb';
|
|
||||||
$h1_cart_name = 'Warenkorb';
|
|
||||||
$h2_cart_suggestions = 'Vorschläge';
|
|
||||||
$h2_cart_sample_product = 'Muster';
|
|
||||||
$tr_product = 'Produkt';
|
|
||||||
$tr_price = 'Preis';
|
|
||||||
$tr_quantity = 'Menge';
|
|
||||||
$tr_total = 'Gesamt';
|
|
||||||
$total_subtotal = 'Zwischensumme';
|
|
||||||
$total_note = '(Versandkosten werden während des Bezahlvorgangs berechnet)';
|
|
||||||
$total_vat = 'MwSt';
|
|
||||||
$total_shipping = 'Versand';
|
|
||||||
$total_shipping_note = '(Versand inbegriffen)';
|
|
||||||
$total_discount = 'Rabatt';
|
|
||||||
$total_total = 'Gesamt';
|
|
||||||
$total_total_note = 'MwSt inbegriffen';
|
|
||||||
$btn_emptycart = 'leeren';
|
|
||||||
$btn_update = 'Aktualisieren';
|
|
||||||
$btn_checkout = 'Zur Kasse';
|
|
||||||
$navigation_back_to_store = 'zurück zur Kollektion';
|
|
||||||
$cart_message_empty = 'Sie haben keine Produkte in Ihrem Warenkorb';
|
|
||||||
$error_account_name = 'Konto existiert bereits.';
|
|
||||||
$error_account_password_rules = 'Das Passwort muss zwischen 5 und 20 Zeichen lang sein.';
|
|
||||||
$error_account_password_match = 'Passwörter stimmen nicht überein.';
|
|
||||||
$error_account = 'Kontoerstellung erforderlich.';
|
|
||||||
$h1_checkout = 'Zur Kasse';
|
|
||||||
$account_available = 'Haben Sie bereits ein Konto?';
|
|
||||||
$account_log_in = 'Anmelden';
|
|
||||||
$account_create = 'Konto erstellen';
|
|
||||||
$account_create_optional = '(optional)';
|
|
||||||
$account_create_email = 'E-Mail';
|
|
||||||
$account_create_password = 'Passwort';
|
|
||||||
$account_create_password_confirm = 'Passwort bestätigen';
|
|
||||||
$h2_Shipping_details = 'Versanddetails';
|
|
||||||
$h3_shipping_method = 'Versandmethode';
|
|
||||||
$shipping_first_name = 'Vorname';
|
|
||||||
$shipping_last_name = 'Nachname';
|
|
||||||
$shipping_address = 'Adresse';
|
|
||||||
$shipping_city = 'Stadt';
|
|
||||||
$shipping_state = 'Region/Bundesland';
|
|
||||||
$shipping_zip = 'PLZ';
|
|
||||||
$shipping_country = 'Land';
|
|
||||||
$shipping_phone = 'Telefon';
|
|
||||||
$payment_method = 'Zahlungsmethode';
|
|
||||||
$payment_method_1 = 'Lastschrift (NL/BE-Kunden)';
|
|
||||||
$payment_method_2 = 'Zahlung bei Lieferung';
|
|
||||||
$h2_shoppingcart = 'Warenkorb';
|
|
||||||
$discount_label = 'Rabattcode';
|
|
||||||
$discount_message = 'Rabattcode angewendet!';
|
|
||||||
$discount_error_1 = 'Falscher Rabattcode!';
|
|
||||||
$discount_error_2 = 'Rabattcode abgelaufen!';
|
|
||||||
$order_consent_1 = 'Ich möchte E-Mail-Kommunikation über MorvalWatches Neuigkeiten, Produkte und Dienstleistungen erhalten';
|
|
||||||
$order_consent_2 = 'Ich stimme zu';
|
|
||||||
$order_consent_3 = 'AGB';
|
|
||||||
$btn_place_order = 'Bestellen';
|
|
||||||
$h1_order_succes_message = 'Ihre Bestellung wurde aufgegeben';
|
|
||||||
$order_succes_message = 'Vielen Dank für Ihre Bestellung! Wir werden Sie per E-Mail mit Ihren Bestelldetails kontaktieren.';
|
|
||||||
$error_myaccount = 'Falsche E-Mail/Passwort!';
|
|
||||||
$h1_login = 'Anmelden';
|
|
||||||
$h1_register = 'Registrieren';
|
|
||||||
$h1_myaccount = 'Mein Konto';
|
|
||||||
$h2_menu = 'Menü';
|
|
||||||
$menu_orders = 'Bestellungen';
|
|
||||||
$menu_downloads = 'Downloads';
|
|
||||||
$h2_myorders = 'Meine Bestellungen';
|
|
||||||
$myorders_message = 'Sie haben keine Bestellungen';
|
|
||||||
$myorders_order = 'Bestellung';
|
|
||||||
$myorders_date = 'Datum';
|
|
||||||
$myorders_status = 'Status';
|
|
||||||
$myorders_shipping = 'Versand';
|
|
||||||
$myorders_total = 'Gesamt';
|
|
||||||
$h2_mydownloads = 'Meine Downloads';
|
|
||||||
$mydownloads_message = 'Sie haben keine Downloads';
|
|
||||||
$mydownloads_product = 'Produkt';
|
|
||||||
$h2_settings = 'Einstellungen';
|
|
||||||
$settings_email = 'E-Mail';
|
|
||||||
$settings_new_password = 'Neues Passwort';
|
|
||||||
$btn_settings_save = 'Speichern';
|
|
||||||
$age_consent_h4 = 'Lass uns dein Alter überprüfen';
|
|
||||||
$age_consent_text = 'Um MorvalWatches zu besuchen, müssen Sie 18 Jahre oder älter sein.';
|
|
||||||
$age_consent_btn_allow = 'Zustimmen';
|
|
||||||
$age_consent_btn_deny = 'Ablehnen';
|
|
||||||
$maintenanceMode_h4 = 'Webshop befindet sich in Wartung';
|
|
||||||
$maintenanceMode_text = 'Unser Webshop befindet sich in Wartung. Wir freuen uns, Sie bald wieder zu sehen';
|
|
||||||
$maintenanceMode_btn = 'OK';
|
|
||||||
$subject_order_notification = 'MorvalWatches - Sie haben eine neue Bestellung erhalten!';
|
|
||||||
$subject_new_order = 'MorvalWatches - Bestelldetails';
|
|
||||||
$subject_out_of_stock = 'MorvalWatches - Nicht auf Lager';
|
|
||||||
$home_text = 'Startseite';
|
|
||||||
$products_text = 'Kollektion';
|
|
||||||
$about_text = 'Über uns';
|
|
||||||
$myaccount_text = 'Konto';
|
|
||||||
$social_punch_line = 'Verbinden Sie sich mit Morval über unsere Social-Media-Kanäle';
|
|
||||||
$privacy_text = 'Datenschutz';
|
|
||||||
$terms_text = 'Allgemeine Geschäftsbedingungen';
|
|
||||||
$faq_text = 'Häufig gestellte Fragen';
|
|
||||||
$order_email_title = 'MorvalWatches - Bestellung';
|
|
||||||
$order_email_message_1 = 'Vielen Dank für Ihre Bestellung';
|
|
||||||
$order_email_message_2 = 'Ihre Bestellung ist eingegangen und wird derzeit bearbeitet. Die Details zu Ihrer Bestellung finden Sie unten.';
|
|
||||||
$order_email_information = 'Ihre Details';
|
|
||||||
$h2_about_1 = 'Über Morval';
|
|
||||||
$about_header_1 = 'Über uns';
|
|
||||||
$about_1_p = 'Morval Watches wurde 2023 von Ralph van Wezel gegründet. Ralph ist Krankenhausapotheker und hat eine Faszination für Technologie. In seiner Arbeit ist er bestrebt, Medikamente verfügbar zu machen, die einen Unterschied für den Patienten machen. Die Herstellung eines Medikaments erfordert Wissen, Präzision, Genauigkeit, Technik, Qualität und Handwerkskunst. Hierin liegt die Ähnlichkeit mit der Herstellung einer hochwertigen Automatikuhr. Ralph hat sich zum Ziel gesetzt, eine Uhr zu entwickeln, die mit den renommierten Marken konkurrieren kann, aber zu einem akzeptablen Preis verkauft wird.';
|
|
||||||
$about_header_2 = 'Über unsere Uhren';
|
|
||||||
$about_2_p = 'Eine Morval-Uhr ist von den Vintage-Modellen und dem minimalistischen Design skandinavischer Uhren inspiriert. Dank der Farbvariationen von Zifferblatt und Armband kann eine Morval-Uhr zu jedem Anlass getragen werden – sowohl als Sport- als auch als elegante Uhr. Morval-Uhren erfüllen höchste Qualitätsanforderungen und können mit den bekannten Schweizer Marken mithalten. Die Komponenten stammen von renommierten Herstellern aus Europa und dem Ausland. Eine Morval verfügt über ein Schweizer Kaliber (STP), das für seine zuverlässige Qualität bekannt ist. Die Montage erfolgt in Amsterdam durch anerkannte Uhrmacher, und jede Uhr wird einer umfassenden Qualitätskontrolle hinsichtlich Funktionalität und Ästhetik unterzogen. Die Uhr wird manuell eingestellt und geprüft, um Abweichungen zu minimieren. Morval steht für ein hervorragendes Preis-Leistungs-Verhältnis! Mit dem Kauf einer Morval-Uhr erhalten Sie garantiert einen zeitlosen Zeitmesser, der Jahrzehnte hält. Viel Liebe zum Detail wurde auf Details gelegt, wie zum Beispiel ein gebürstetes Gehäuse aus Edelstahl 316, Superluminova auf den Zeigern, entspiegeltes Glas und ein stufenlos verstellbares Lederarmband. Dies spiegelt den luxuriösen Auftritt der Marke wider. Mit einer Morval-Uhr besitzen Sie eine einzigartige, robuste, stilvolle und zeitlose Uhr, die Generationen überdauert!';
|
|
||||||
$about_header_3 = 'Über Morval';
|
|
||||||
$about_morval_text = 'Lesen Sie mehr über die Geschichte von Morval';
|
|
||||||
$h2_about_morval_1 = 'Die Geschichte von Morval';
|
|
||||||
$h2_about_morval_2 = '';
|
|
||||||
$about_morval_header_1 = '';
|
|
||||||
$about_morval_header_2 = '';
|
|
||||||
$about_morval_header_3 = '';
|
|
||||||
$about_morval_2_p = 'Als die Trümmer beseitigt waren, blieb dieser große, leere Platz wie eine Wunde in den Herzen der Einwohner zurück. Drei Jahre später errichtete die Gemeinde einen kleinen Glockenturm, an dem die drei Glocken aufgehängt wurden, die für den Abriss heruntergelassen worden waren. Dank der Unterstützung der Bewohner der 1930er Jahre sind sie noch heute lebendig und läuten noch immer, um jedes glückliche oder unglückliche Ereignis zu markieren, wie wir es einst taten.';
|
|
||||||
$about_morval_3_p = 'Als die Trümmer beseitigt waren, blieb dieser große, leere Platz wie eine Wunde in den Herzen der Einwohner zurück. Drei Jahre später errichtete die Gemeinde einen kleinen Glockenturm, an dem die drei Glocken aufgehängt wurden, die für den Abriss heruntergelassen worden waren. Dank der Unterstützung der Einwohner der 1930er Jahre sind sie noch immer lebendig und läuten noch immer, um jedes glückliche oder unglückliche Ereignis zu markieren, wie wir es einst taten. Dank ihnen hat Morval seinen verlorenen Glockenturm nicht vergessen.';
|
|
||||||
$invoice_morval_subject = 'Morval Uhren - Rechnung';
|
|
||||||
$place_order_header = 'Bestellung aufgeben';
|
|
||||||
$checkout_header = 'Kasse';
|
|
||||||
$tax_text = 'Mehrwertsteuer';
|
|
||||||
$h2_cart_samples = 'Proben';
|
|
||||||
$products_filters_h2 = 'Filter';
|
|
||||||
$btn_filter = 'Filter';
|
|
||||||
$sort = 'Sortieren';
|
|
||||||
$order_number_text = 'Befehl';
|
|
||||||
$order_date_text = 'Datum';
|
|
||||||
$tr_options = 'Optionen';
|
|
||||||
$order_invoice_text = 'Rechnung';
|
|
||||||
$invoice_payment_paid_text = 'Der Gesamtbetrag dieser Rechnung ist bezahlt';
|
|
||||||
$highlight_1 = 'Sammlung';
|
|
||||||
$highlight_2 = 'Sammlung';
|
|
||||||
$home_timeless = 'Zeitlos';
|
|
||||||
$home_timeless_text = 'Morval-Uhren sind einzigartige, robuste, stilvolle und zeitlose Zeitmesser, die Generationen überdauern!';
|
|
||||||
$shop_action = 'Jetzt kaufen';
|
|
||||||
$home_quality = 'Qualität';
|
|
||||||
$home_quality_text = 'Morval Uhren erfüllen höchste Qualitätsansprüche und können mit den bekannten Schweizer Marken mithalten. Die Komponenten stammen von renommierten Herstellern aus Europa und dem Ausland. Eine Morval verfügt über ein Schweizer Kaliber (STP), das für seine zuverlässige Qualität bekannt ist.';
|
|
||||||
$home_price = 'Preis';
|
|
||||||
$home_price_text = 'Morval steht für ein hervorragendes Preis-Leistungs-Verhältnis';
|
|
||||||
$shopping_cart_header = 'Warenkorb';
|
|
||||||
$about_3_p = 'Morval hat seinen Namen vom Nachnamen eines von Ralphs Großeltern. Das Logo ist inspiriert vom Denkmal in der Stadt Morval in Nordfrankreich, das aus den Überresten einer Kirche und den drei Glocken des Turms errichtet wurde.';
|
|
||||||
$newuser_credential_text_1 = 'Ihr Konto wurde mit dem Benutzernamen erstellt';
|
|
||||||
$newuser_credential_text_2 = 'Klicken Sie bitte auf die Schaltfläche unten, um Ihre Registrierung abzuschließen.';
|
|
||||||
$verify_account = 'Konto verifizieren';
|
|
||||||
$newuser_signature = ' Mit freundlichen Grüße,';
|
|
||||||
$newuser_signature_name = 'MorvalUhren';
|
|
||||||
$changeuser_credential_text_1 = 'Klicken Sie bitte auf die Schaltfläche unten, um das Passwort Ihres Kontos zurückzusetzen.';
|
|
||||||
$changeuser_signature = ' Mit freundlichen Grüße,';
|
|
||||||
$changeuser_signature_name = 'MorvalUhren';
|
|
||||||
$bracelet_dark = 'Schwarz';
|
|
||||||
$bracelet_blue = 'Dunkelblau';
|
|
||||||
$bracelet_dark_brown = 'Dunkelbraun';
|
|
||||||
$bracelet_light_brown = 'Hellbraun';
|
|
||||||
$bracelet_steel = 'Stahl';
|
|
||||||
$MWTH1NB_description = '<p>Die Thomas-I strahlt Eleganz und Raffinesse aus. Klassische Maße kombiniert mit dezenten Details im Zifferblatt machen sie zu einer besonderen Automatikuhr, die zu jedem Anlass getragen werden kann.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Polierter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Datum: Arabische Zahlen (Tag)</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$MWTH2NB_description = '<p>Die Thomas-II bietet einen Blick auf das schlagende Herz der Schweizer Uhr. Sie steht für die Präzision und Perfektion, mit der die Zeit angezeigt wird.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Gebürsteter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$MWTH2IB_description = '<p>Die Thomas-II bietet einen Blick auf das schlagende Herz der Schweizer Uhr. Sie steht für die Präzision und Perfektion, mit der die Zeit angezeigt wird.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Gebürsteter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$MWTH2RG_description = '<p>Die Thomas-II bietet einen Blick auf das schlagende Herz der Schweizer Uhr. Sie steht für die Präzision und Perfektion, mit der die Zeit angezeigt wird.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Gebürsteter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$MWTH2DG_description = '<p>Die Thomas-II bietet einen Blick auf das schlagende Herz der Schweizer Uhr. Sie steht für die Präzision und Perfektion, mit der die Zeit angezeigt wird.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Gebürsteter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$MWTH2G_description = '<p>Die Thomas-II bietet einen Blick auf das schlagende Herz der Schweizer Uhr. Sie steht für die Präzision und Perfektion, mit der die Zeit angezeigt wird.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Gebürsteter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$MWABRB1_description = 'Armband Handgefertigtes italienisches Kalbsleder';
|
|
||||||
$MWABRDB1_description = 'Armband Handgefertigtes italienisches Kalbsleder';
|
|
||||||
$MWABRLB1_description = 'Armband Handgefertigtes italienisches Kalbsleder';
|
|
||||||
$MWABRBL1_description = 'Armband Handgefertigtes italienisches Kalbsleder';
|
|
||||||
$MWTH1IB_description = '<p>Die Thomas-I strahlt Eleganz und Raffinesse aus. Klassische Maße kombiniert mit dezenten Details im Zifferblatt machen sie zu einer besonderen Automatikuhr, die zu jedem Anlass getragen werden kann.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Polierter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Datum: Arabische Zahlen (Tag)</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$MWTH1RG_description = '<p>Die Thomas-I strahlt Eleganz und Raffinesse aus. Klassische Maße kombiniert mit dezenten Details im Zifferblatt machen sie zu einer besonderen Automatikuhr, die zu jedem Anlass getragen werden kann.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Polierter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Datum: Arabische Zahlen (Tag)</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$MWTH1DG_description = '<p>Die Thomas-I strahlt Eleganz und Raffinesse aus. Klassische Maße kombiniert mit dezenten Details im Zifferblatt machen sie zu einer besonderen Automatikuhr, die zu jedem Anlass getragen werden kann.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Polierter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Datum: Arabische Zahlen (Tag)</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$MWTH1G_description = '<p>Die Thomas-I strahlt Eleganz und Raffinesse aus. Klassische Maße kombiniert mit dezenten Details im Zifferblatt machen sie zu einer besonderen Automatikuhr, die zu jedem Anlass getragen werden kann.</p><h3><b>Technische Daten</b></h3><ul><li>Gehäusegröße: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 mit 26 Steinen</li><li>Gangreserve: 40 h</li><li>Ischronismus: < 10 Sek./Tag</li><li>Lünette: Polierter Edelstahl (316L)</li><li>Wasserdicht: 50 Meter (5 ATM)</li><li>Zifferblatt: Sonnenstrahlen-Muster</li><li>Datum: Arabische Zahlen (Tag)</li><li>Leuchtmasse: Superluminova (Blau)</li><li>Glas: Saphirglas mit Antireflexbeschichtung</li><li>Gehäuseboden: Verschraubt, gebürsteter Edelstahl mit Saphirglas</li><li>Armband (Stahl): Gebürsteter und polierter 316L Edelstahl</li><li>Armband (Leder): Handgefertigtes italienisches Kalbsleder</li><li>Schließe: Faltschließe für höchsten Komfort</li><li>Verpackung: Blaue Box mit Zertifikat und Bedienungsanleitung.</li></ul>';
|
|
||||||
$payment_status_0 = 'Offen';
|
|
||||||
$payment_status_1 = 'Bezahlt';
|
|
||||||
$payment_status_101 = 'Ausstehend';
|
|
||||||
$payment_status_102 = 'Fehlgeschlagen';
|
|
||||||
$payment_status_103 = 'Abgelaufen';
|
|
||||||
$payment_status_999 = 'Abgesagt';
|
|
||||||
$payment_method_3 = 'Soll/Haben';
|
|
||||||
$ad_watch_1 = 'Niederländisches Design und Schweizer Handwerkskunst';
|
|
||||||
$ad_watch_2 = 'Zeitlose Uhren, die Generationen überdauern!';
|
|
||||||
$ad_watch_btn = 'mehr lesen';
|
|
||||||
$newsletter_h2 = 'Melden Sie sich für den<br>Newsletter an';
|
|
||||||
$newsletter_p = 'Bleiben Sie mit unseren neuesten Updates, Tipps und exklusiven Angeboten auf dem Laufenden – direkt in Ihrem Posteingang.';
|
|
||||||
$newsletter_confirm = 'Ich habe die Datenschutzrichtlinie gelesen und stimme ihr zu';
|
|
||||||
$newsletter_submit = 'einreichen';
|
|
||||||
$header_manufacturing = 'Schweizer Qualität und niederländische Fertigung';
|
|
||||||
$header_shipping = 'Kostenloser Versand für alle unsere Uhren';
|
|
||||||
$header_delivery = 'Schneller Service und Lieferung';
|
|
||||||
$header_rating = 'Kundenbewertung 4.7/5.0';
|
|
||||||
?>
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
<?php
|
|
||||||
$h2_brand_name_1 = 'MorvalWatches';
|
|
||||||
$h2_brand_name_2 = 'una marca con historia';
|
|
||||||
$h2_brand_visit = 'Visite nuestra colección';
|
|
||||||
$h2_brand_wow = 'Morval reúne una combinación única de diseño minimalista, calidad suiza y fabricación holandesa.Te ofrecemos un reloj para llevar en cualquier ocasión.';
|
|
||||||
$h1_content_top = 'Nuestra colección de relojes';
|
|
||||||
$product_count_1 = 'Producto';
|
|
||||||
$product_count_2 = 's';
|
|
||||||
$main_filter_category = 'Categoría';
|
|
||||||
$main_category = 'Todos';
|
|
||||||
$main_filter_sort = 'Ordenar';
|
|
||||||
$sort1 = 'A-Z';
|
|
||||||
$sort2 = 'Z-A';
|
|
||||||
$sort3 = 'Más recientes';
|
|
||||||
$sort4 = 'Más antiguos';
|
|
||||||
$sort5 = 'Precio alto - bajo';
|
|
||||||
$sort6 = 'Precio bajo - alto';
|
|
||||||
$free_delivery = 'envío gratis';
|
|
||||||
$non_free_delivery = 'envío gratis a partir de';
|
|
||||||
$breadcrum_products = 'Colección';
|
|
||||||
$product_quantity = 'Cantidad';
|
|
||||||
$product_on_stock = 'En stock';
|
|
||||||
$out_of_stock_notify = 'Notifícame';
|
|
||||||
$out_of_stock_notify_2 = 'Visítanos @';
|
|
||||||
$out_of_stock = 'Agotado';
|
|
||||||
$add_to_basket = 'Añadir al carrito';
|
|
||||||
$h1_cart_name = 'Carrito de compra';
|
|
||||||
$h2_cart_suggestions = 'Sugerencias';
|
|
||||||
$h2_cart_sample_product = 'Muestras';
|
|
||||||
$tr_product = 'Producto';
|
|
||||||
$tr_price = 'Precio';
|
|
||||||
$tr_quantity = 'Cantidad';
|
|
||||||
$tr_total = 'Total';
|
|
||||||
$total_subtotal = 'Subtotal';
|
|
||||||
$total_note = '(los gastos de envío se calculan durante el pago)';
|
|
||||||
$total_vat = 'IVA';
|
|
||||||
$total_shipping = 'Envío';
|
|
||||||
$total_shipping_note = '(envío incluido)';
|
|
||||||
$total_discount = 'Descuento';
|
|
||||||
$total_total = 'Total';
|
|
||||||
$total_total_note = 'IVA incluido';
|
|
||||||
$btn_emptycart = 'vaciar';
|
|
||||||
$btn_update = 'Actualizar';
|
|
||||||
$btn_checkout = 'Finalizar compra';
|
|
||||||
$navigation_back_to_store = 'volver a la colección';
|
|
||||||
$cart_message_empty = 'No tienes productos en tu carrito de compra';
|
|
||||||
$error_account_name = 'La cuenta ya existe.';
|
|
||||||
$error_account_password_rules = 'La contraseña debe tener entre 5 y 20 caracteres.';
|
|
||||||
$error_account_password_match = 'Las contraseñas no coinciden.';
|
|
||||||
$error_account = 'Se requiere crear una cuenta.';
|
|
||||||
$h1_checkout = 'Finalizar compra';
|
|
||||||
$account_available = '¿Ya tienes una cuenta?';
|
|
||||||
$account_log_in = 'Iniciar sesión';
|
|
||||||
$account_create = 'Crear cuenta';
|
|
||||||
$account_create_optional = '(opcional)';
|
|
||||||
$account_create_email = 'Correo electrónico';
|
|
||||||
$account_create_password = 'Contraseña';
|
|
||||||
$account_create_password_confirm = 'Confirmar contraseña';
|
|
||||||
$h2_Shipping_details = 'Detalles de envío';
|
|
||||||
$h3_shipping_method = 'Método de envío';
|
|
||||||
$shipping_first_name = 'Nombre';
|
|
||||||
$shipping_last_name = 'Apellido';
|
|
||||||
$shipping_address = 'Dirección';
|
|
||||||
$shipping_city = 'Ciudad';
|
|
||||||
$shipping_state = 'Región/Estado';
|
|
||||||
$shipping_zip = 'Código postal';
|
|
||||||
$shipping_country = 'País';
|
|
||||||
$shipping_phone = 'Teléfono';
|
|
||||||
$payment_method = 'Método de pago';
|
|
||||||
$payment_method_1 = 'Débito (clientes NL/BE)';
|
|
||||||
$payment_method_2 = 'Pago contra entrega';
|
|
||||||
$h2_shoppingcart = 'Carrito de compra';
|
|
||||||
$discount_label = 'Código de descuento';
|
|
||||||
$discount_message = '¡Código de descuento aplicado!';
|
|
||||||
$discount_error_1 = '¡Código de descuento incorrecto!';
|
|
||||||
$discount_error_2 = '¡Código de descuento caducado!';
|
|
||||||
$order_consent_1 = 'Me gustaría recibir comunicaciones por correo electrónico sobre noticias, productos y servicios de MorvalWatches';
|
|
||||||
$order_consent_2 = 'Estoy de acuerdo con';
|
|
||||||
$order_consent_3 = 'Términos y condiciones';
|
|
||||||
$btn_place_order = 'Realizar pedido';
|
|
||||||
$h1_order_succes_message = 'Tu pedido ha sido realizado';
|
|
||||||
$order_succes_message = '¡Gracias por realizar tu pedido con nosotros! Te contactaremos por correo electrónico con los detalles de tu pedido.';
|
|
||||||
$error_myaccount = '¡Correo electrónico/contraseña incorrectos!';
|
|
||||||
$h1_login = 'Iniciar sesión';
|
|
||||||
$h1_register = 'Registrarse';
|
|
||||||
$h1_myaccount = 'Mi cuenta';
|
|
||||||
$h2_menu = 'Menú';
|
|
||||||
$menu_orders = 'Pedidos';
|
|
||||||
$menu_downloads = 'Descargas';
|
|
||||||
$h2_myorders = 'Mis pedidos';
|
|
||||||
$myorders_message = 'No tienes pedidos';
|
|
||||||
$myorders_order = 'Pedido';
|
|
||||||
$myorders_date = 'Fecha';
|
|
||||||
$myorders_status = 'Estado';
|
|
||||||
$myorders_shipping = 'Envío';
|
|
||||||
$myorders_total = 'Total';
|
|
||||||
$h2_mydownloads = 'Mis descargas';
|
|
||||||
$mydownloads_message = 'No tienes descargas';
|
|
||||||
$mydownloads_product = 'Producto';
|
|
||||||
$h2_settings = 'Configuración';
|
|
||||||
$settings_email = 'Correo electrónico';
|
|
||||||
$settings_new_password = 'Nueva contraseña';
|
|
||||||
$btn_settings_save = 'Guardar';
|
|
||||||
$age_consent_h4 = 'Comprobemos tu edad';
|
|
||||||
$age_consent_text = 'Para visitar MorvalWatches debes tener 18 años o más.';
|
|
||||||
$age_consent_btn_allow = 'Aceptar';
|
|
||||||
$age_consent_btn_deny = 'Rechazar';
|
|
||||||
$maintenanceMode_h4 = 'La tienda web está en mantenimiento';
|
|
||||||
$maintenanceMode_text = 'Nuestra tienda web está en mantenimiento. Esperamos verte pronto de nuevo';
|
|
||||||
$maintenanceMode_btn = 'OK';
|
|
||||||
$subject_order_notification = 'MorvalWatches - ¡Has recibido un nuevo pedido!';
|
|
||||||
$subject_new_order = 'MorvalWatches - Detalles del pedido';
|
|
||||||
$subject_out_of_stock = 'MorvalWatches - Agotado';
|
|
||||||
$home_text = 'Inicio';
|
|
||||||
$products_text = 'Colección';
|
|
||||||
$about_text = 'Sobre nosotros';
|
|
||||||
$myaccount_text = 'Cuenta';
|
|
||||||
$social_punch_line = 'Conéctate con Morval a través de nuestros canales de redes sociales';
|
|
||||||
$privacy_text = 'Privacidad';
|
|
||||||
$terms_text = 'Términos y condiciones';
|
|
||||||
$faq_text = 'Preguntas frecuentes';
|
|
||||||
$order_email_title = 'MorvalWatches - Pedido';
|
|
||||||
$order_email_message_1 = 'Gracias por tu pedido';
|
|
||||||
$order_email_message_2 = 'Tu pedido ha sido recibido y está siendo procesado. Los detalles de tu pedido se encuentran a continuación.';
|
|
||||||
$order_email_information = 'Tus detalles';
|
|
||||||
$h2_about_1 = 'Sobre Morval';
|
|
||||||
$about_header_1 = 'Sobre nosotros';
|
|
||||||
$about_1_p = 'Morval Watches fue fundada en 2023 por Ralph van Wezel. Ralph es farmacéutico hospitalario y tiene fascinación por la tecnología. En su trabajo se esfuerza por hacer disponibles medicamentos que marquen la diferencia para el paciente. Producir un medicamento requiere conocimiento, precisión, exactitud, técnica, calidad y artesanía. Aquí radica la similitud con la fabricación de un reloj automático de alta calidad. Ralph se ha fijado el objetivo de desarrollar un reloj que pueda competir con las marcas reconocidas, pero que se venda a un precio aceptable.';
|
|
||||||
$about_header_2 = 'Sobre nuestros relojes';
|
|
||||||
$about_2_p = 'Un reloj Morval se inspira en los modelos vintage y el diseño minimalista de los relojes escandinavos. Gracias a las variaciones de color de la esfera y las correas, un reloj Morval se puede usar en cualquier ocasión, tanto deportivo como de vestir. Los relojes Morval cumplen con los más altos estándares de calidad y pueden competir con las reconocidas marcas suizas. Las piezas son suministradas por fabricantes de renombre de Europa y el extranjero. Un Morval incorpora un calibre suizo (STP), reconocido por su calidad. El ensamblaje se realiza en Ámsterdam por relojeros reconocidos y cada reloj se somete a un exhaustivo control de calidad para garantizar su funcionalidad y estética. El reloj se ajusta y prueba manualmente para minimizar las desviaciones. ¡Morval ofrece una excelente relación calidad-precio! Al comprar un reloj Morval, tiene la garantía de un reloj atemporal que durará décadas. Se ha prestado especial atención a los detalles, como la caja cepillada de acero inoxidable 316, la superluminova en las agujas, el cristal antirreflejos y la correa de cuero infinitamente ajustable. Esto se traduce en la lujosa apariencia de la marca. ¡Con un reloj Morval tendrás un reloj único, robusto, elegante y atemporal que durará generaciones!';
|
|
||||||
$about_header_3 = 'Acerca de Morval';
|
|
||||||
$about_morval_text = 'Lea más sobre la historia de Morval';
|
|
||||||
$h2_about_morval_1 = 'La historia de Morval';
|
|
||||||
$h2_about_morval_2 = '';
|
|
||||||
$about_morval_header_1 = '';
|
|
||||||
$about_morval_header_2 = '';
|
|
||||||
$about_morval_header_3 = '';
|
|
||||||
$about_morval_2_p = 'Tras la limpieza de los escombros, esta gran plaza vacía quedó como una herida en el corazón de sus habitantes. Tres años después, el municipio construyó un pequeño campanario donde se colgaron las tres campanas que se bajaron para la demolición. Patrocinadas por los residentes de la década de 1930, siguen vivas y aún tocan la campana para conmemorar cualquier acontecimiento, ya sea feliz o desafortunado, como lo hacíamos nosotros antaño.';
|
|
||||||
$about_morval_3_p = 'Tras la limpieza de los escombros, esta gran plaza vacía quedó como una herida en el corazón de sus habitantes. Tres años después, el municipio construyó un pequeño campanario donde se colgaron las tres campanas que se bajaron para la demolición. Patrocinadas por los residentes de la década de 1930, siguen vivas y aún tocan la campana para conmemorar cualquier acontecimiento, feliz o desafortunado, como lo hacíamos nosotros antaño. Gracias a ellos, Morval no olvida su campanario desaparecido.';
|
|
||||||
$invoice_morval_subject = 'Relojes Morval - factura';
|
|
||||||
$place_order_header = 'Realizar pedido';
|
|
||||||
$checkout_header = 'Verificar';
|
|
||||||
$tax_text = 'TINA';
|
|
||||||
$h2_cart_samples = 'Muestras';
|
|
||||||
$products_filters_h2 = 'Filtros';
|
|
||||||
$btn_filter = 'Filtrar';
|
|
||||||
$sort = 'Clasificar';
|
|
||||||
$order_number_text = 'Orden';
|
|
||||||
$order_date_text = 'Fecha';
|
|
||||||
$tr_options = 'Opciones';
|
|
||||||
$order_invoice_text = 'Factura';
|
|
||||||
$invoice_payment_paid_text = 'El importe total de esta factura está pagado';
|
|
||||||
$highlight_1 = 'Recopilación';
|
|
||||||
$highlight_2 = 'Recopilación';
|
|
||||||
$home_timeless = 'Eterno';
|
|
||||||
$home_timeless_text = '¡Los relojes Morval son relojes únicos, robustos, elegantes y atemporales que durarán generaciones!';
|
|
||||||
$shop_action = 'Compra ahora';
|
|
||||||
$home_quality = 'Calidad';
|
|
||||||
$home_quality_text = 'Los relojes Morval cumplen con los más altos estándares de calidad y pueden competir con las reconocidas marcas suizas. Las piezas son suministradas por fabricantes de renombre de Europa y el extranjero. Un Morval incorpora un calibre de fabricación suiza (STP), reconocido por su fiabilidad.';
|
|
||||||
$home_price = 'Precio';
|
|
||||||
$home_price_text = 'Morval representa una excelente relación calidad-precio.';
|
|
||||||
$shopping_cart_header = 'Carro de la compra';
|
|
||||||
$about_3_p = 'Morval toma su nombre del apellido de uno de los abuelos de Ralph. El logotipo está inspirado en el monumento de la ciudad de Morval, en el norte de Francia, construido con los restos de una iglesia y las tres campanas de la torre.';
|
|
||||||
$newuser_credential_text_1 = 'Su cuenta ha sido creada con nombre de usuario';
|
|
||||||
$newuser_credential_text_2 = 'Por favor haga clic en el botón de abajo para completar su registro.';
|
|
||||||
$verify_account = 'Verificar cuenta';
|
|
||||||
$newuser_signature = ' Atentamente,';
|
|
||||||
$newuser_signature_name = 'Relojes Morval';
|
|
||||||
$changeuser_credential_text_1 = 'Haga clic en el botón a continuación para restablecer la contraseña de su cuenta.';
|
|
||||||
$changeuser_signature = ' Atentamente,';
|
|
||||||
$changeuser_signature_name = 'Relojes Morval';
|
|
||||||
$bracelet_dark = 'Negro';
|
|
||||||
$bracelet_blue = 'Azul oscuro';
|
|
||||||
$bracelet_dark_brown = 'Marrón oscuro';
|
|
||||||
$bracelet_light_brown = 'Marrón claro';
|
|
||||||
$bracelet_steel = 'Acero';
|
|
||||||
$MWTH1NB_description = '<p>El Thomas-I irradia elegancia y sofisticación. Dimensiones clásicas combinadas con detalles sutiles en la esfera hacen de este un reloj automático especial para cualquier ocasión.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable pulido (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Fecha: Números arábigos (día)</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$MWTH2NB_description = '<p>El Thomas-II ofrece una vista del corazón palpitante del reloj suizo. Representa la precisión y perfección con la que se muestra el tiempo.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable cepillado (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$MWTH2IB_description = '<p>El Thomas-II ofrece una vista del corazón palpitante del reloj suizo. Representa la precisión y perfección con la que se muestra el tiempo.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable cepillado (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$MWTH2RG_description = '<p>El Thomas-II ofrece una vista del corazón palpitante del reloj suizo. Representa la precisión y perfección con la que se muestra el tiempo.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable cepillado (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$MWTH2DG_description = '<p>El Thomas-II ofrece una vista del corazón palpitante del reloj suizo. Representa la precisión y perfección con la que se muestra el tiempo.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable cepillado (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$MWTH2G_description = '<p>El Thomas-II ofrece una vista del corazón palpitante del reloj suizo. Representa la precisión y perfección con la que se muestra el tiempo.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable cepillado (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$MWABRB1_description = 'Pulsera de piel de becerro italiana hecha a mano';
|
|
||||||
$MWABRDB1_description = 'Pulsera de piel de becerro italiana hecha a mano';
|
|
||||||
$MWABRLB1_description = 'Pulsera de piel de becerro italiana hecha a mano';
|
|
||||||
$MWABRBL1_description = 'Pulsera de piel de becerro italiana hecha a mano';
|
|
||||||
$MWTH1IB_description = '<p>El Thomas-I irradia elegancia y sofisticación. Dimensiones clásicas combinadas con detalles sutiles en la esfera hacen de este un reloj automático especial para cualquier ocasión.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable pulido (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Fecha: Números arábigos (día)</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$MWTH1RG_description = '<p>El Thomas-I irradia elegancia y sofisticación. Dimensiones clásicas combinadas con detalles sutiles en la esfera hacen de este un reloj automático especial para cualquier ocasión.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable pulido (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Fecha: Números arábigos (día)</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$MWTH1DG_description = '<p>El Thomas-I irradia elegancia y sofisticación. Dimensiones clásicas combinadas con detalles sutiles en la esfera hacen de este un reloj automático especial para cualquier ocasión.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable pulido (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Fecha: Números arábigos (día)</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$MWTH1G_description = '<p>El Thomas-I irradia elegancia y sofisticación. Dimensiones clásicas combinadas con detalles sutiles en la esfera hacen de este un reloj automático especial para cualquier ocasión.</p><h3><b>Especificaciones</b></h3><ul><li>Tamaño de la caja: 39 mm x 10,5 mm.</li><li>Calibre: STP1-11 con 26 rubíes</li><li>Reserva de marcha: 40 h</li><li>Isocronismo: < 10 seg./día</li><li>Bisel: Acero inoxidable pulido (316L)</li><li>Resistente al agua: 50 metros (5 ATM)</li><li>Esfera: Efecto rayo de sol</li><li>Fecha: Números arábigos (día)</li><li>Lumen: Superluminova (Azul)</li><li>Cristal: Zafiro con recubrimiento antirreflectante</li><li>Tapa trasera: Atornillada, acero inoxidable cepillado con cristal de zafiro</li><li>Brazalete (acero): Acero inoxidable 316L cepillado y pulido</li><li>Brazalete (cuero): Cuero de becerro italiano hecho a mano</li><li>Cierre: Mecanismo plegable para máxima comodidad</li><li>Embalaje: Caja azul con certificado y manual.</li></ul>';
|
|
||||||
$payment_status_0 = 'Abierto';
|
|
||||||
$payment_status_1 = 'Pagado';
|
|
||||||
$payment_status_101 = 'Pendiente';
|
|
||||||
$payment_status_102 = 'Fallido';
|
|
||||||
$payment_status_103 = 'Venció';
|
|
||||||
$payment_status_999 = 'Cancelado';
|
|
||||||
$payment_method_3 = 'Débito/Crédito';
|
|
||||||
$ad_watch_1 = 'Diseño holandés y artesanía suiza';
|
|
||||||
$ad_watch_2 = '¡Relojes atemporales que durarán generaciones!';
|
|
||||||
$ad_watch_btn = 'leer más';
|
|
||||||
$newsletter_h2 = 'Suscríbete al boletín informativo';
|
|
||||||
$newsletter_p = 'Manténgase conectado con nuestras últimas actualizaciones, consejos y ofertas exclusivas, directamente en su bandeja de entrada.';
|
|
||||||
$newsletter_confirm = 'He leído y estoy de acuerdo con la política de privacidad.';
|
|
||||||
$newsletter_submit = 'entregar';
|
|
||||||
$header_manufacturing = 'Calidad suiza y fabricación holandesa';
|
|
||||||
$header_shipping = 'Envío gratuito en todos nuestros relojes.';
|
|
||||||
$header_delivery = 'Servicio y entrega rápidos';
|
|
||||||
$header_rating = 'Calificación del cliente 4.7/5.0';
|
|
||||||
?>
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
<?php
|
|
||||||
$h2_brand_name_1 = 'MorvalWatches';
|
|
||||||
$h2_brand_name_2 = 'une marque avec une histoire';
|
|
||||||
$h2_brand_visit = 'Visitez notre collection';
|
|
||||||
$h2_brand_wow = 'Morval réunit une combinaison unique de design minimaliste, qualité suisse et fabrication néerlandaise.Nous vous offrons une montre à porter en toute occasion.';
|
|
||||||
$h1_content_top = 'Notre collection de montres';
|
|
||||||
$product_count_1 = 'Produit';
|
|
||||||
$product_count_2 = 's';
|
|
||||||
$main_filter_category = 'Catégorie';
|
|
||||||
$main_category = 'Tous';
|
|
||||||
$main_filter_sort = 'Trier';
|
|
||||||
$sort1 = 'A-Z';
|
|
||||||
$sort2 = 'Z-A';
|
|
||||||
$sort3 = 'Plus récents';
|
|
||||||
$sort4 = 'Plus anciens';
|
|
||||||
$sort5 = 'Prix décroissant';
|
|
||||||
$sort6 = 'Prix croissant';
|
|
||||||
$free_delivery = 'livraison gratuite';
|
|
||||||
$non_free_delivery = 'livraison gratuite à partir de';
|
|
||||||
$breadcrum_products = 'Collection';
|
|
||||||
$product_quantity = 'Quantité';
|
|
||||||
$product_on_stock = 'En stock';
|
|
||||||
$out_of_stock_notify = 'Prévenez-moi';
|
|
||||||
$out_of_stock_notify_2 = 'Visitez-nous @';
|
|
||||||
$out_of_stock = 'En rupture de stock';
|
|
||||||
$add_to_basket = 'Ajouter au panier';
|
|
||||||
$h1_cart_name = 'Panier';
|
|
||||||
$h2_cart_suggestions = 'Suggestions';
|
|
||||||
$h2_cart_sample_product = 'Échantillons';
|
|
||||||
$tr_product = 'Produit';
|
|
||||||
$tr_price = 'Prix';
|
|
||||||
$tr_quantity = 'Quantité';
|
|
||||||
$tr_total = 'Total';
|
|
||||||
$total_subtotal = 'Sous-total';
|
|
||||||
$total_note = '(les frais d\'expédition sont calculés lors du paiement)';
|
|
||||||
$total_vat = 'TVA';
|
|
||||||
$total_shipping = 'Expédition';
|
|
||||||
$total_shipping_note = '(expédition incluse)';
|
|
||||||
$total_discount = 'Remise';
|
|
||||||
$total_total = 'Total';
|
|
||||||
$total_total_note = 'TVA incluse';
|
|
||||||
$btn_emptycart = 'vider';
|
|
||||||
$btn_update = 'Mettre à jour';
|
|
||||||
$btn_checkout = 'Paiement';
|
|
||||||
$navigation_back_to_store = 'retour à la collection';
|
|
||||||
$cart_message_empty = 'Vous n\'avez pas de produits dans votre panier';
|
|
||||||
$error_account_name = 'Le compte existe déjà.';
|
|
||||||
$error_account_password_rules = 'Le mot de passe doit comporter entre 5 et 20 caractères.';
|
|
||||||
$error_account_password_match = 'Les mots de passe ne correspondent pas.';
|
|
||||||
$error_account = 'Création de compte requise.';
|
|
||||||
$h1_checkout = 'Paiement';
|
|
||||||
$account_available = 'Vous avez déjà un compte?';
|
|
||||||
$account_log_in = 'Se connecter';
|
|
||||||
$account_create = 'Créer un compte';
|
|
||||||
$account_create_optional = '(facultatif)';
|
|
||||||
$account_create_email = 'Email';
|
|
||||||
$account_create_password = 'Mot de passe';
|
|
||||||
$account_create_password_confirm = 'Confirmer le mot de passe';
|
|
||||||
$h2_Shipping_details = 'Détails de livraison';
|
|
||||||
$h3_shipping_method = 'Méthode d\'expédition';
|
|
||||||
$shipping_first_name = 'Prénom';
|
|
||||||
$shipping_last_name = 'Nom';
|
|
||||||
$shipping_address = 'Adresse';
|
|
||||||
$shipping_city = 'Ville';
|
|
||||||
$shipping_state = 'Région/État';
|
|
||||||
$shipping_zip = 'Code postal';
|
|
||||||
$shipping_country = 'Pays';
|
|
||||||
$shipping_phone = 'Téléphone';
|
|
||||||
$payment_method = 'Méthode de paiement';
|
|
||||||
$payment_method_1 = 'Débit (clients NL/BE)';
|
|
||||||
$payment_method_2 = 'Paiement à la livraison';
|
|
||||||
$h2_shoppingcart = 'Panier';
|
|
||||||
$discount_label = 'Code de réduction';
|
|
||||||
$discount_message = 'Code de réduction appliqué!';
|
|
||||||
$discount_error_1 = 'Code de réduction incorrect!';
|
|
||||||
$discount_error_2 = 'Code de réduction expiré!';
|
|
||||||
$order_consent_1 = 'Je souhaite recevoir des communications par email concernant les actualités, produits et services de MorvalWatches';
|
|
||||||
$order_consent_2 = 'J\'accepte';
|
|
||||||
$order_consent_3 = 'Conditions générales';
|
|
||||||
$btn_place_order = 'Commander';
|
|
||||||
$h1_order_succes_message = 'Votre commande a été passée';
|
|
||||||
$order_succes_message = 'Merci d\'avoir commandé chez nous! Nous vous contacterons par email avec les détails de votre commande.';
|
|
||||||
$error_myaccount = 'Email/Mot de passe incorrect!';
|
|
||||||
$h1_login = 'Connexion';
|
|
||||||
$h1_register = 'S\'inscrire';
|
|
||||||
$h1_myaccount = 'Mon compte';
|
|
||||||
$h2_menu = 'Menu';
|
|
||||||
$menu_orders = 'Commandes';
|
|
||||||
$menu_downloads = 'Téléchargements';
|
|
||||||
$h2_myorders = 'Mes commandes';
|
|
||||||
$myorders_message = 'Vous n\'avez pas de commandes';
|
|
||||||
$myorders_order = 'Commande';
|
|
||||||
$myorders_date = 'Date';
|
|
||||||
$myorders_status = 'Statut';
|
|
||||||
$myorders_shipping = 'Expédition';
|
|
||||||
$myorders_total = 'Total';
|
|
||||||
$h2_mydownloads = 'Mes téléchargements';
|
|
||||||
$mydownloads_message = 'Vous n\'avez pas de téléchargements';
|
|
||||||
$mydownloads_product = 'Produit';
|
|
||||||
$h2_settings = 'Paramètres';
|
|
||||||
$settings_email = 'Email';
|
|
||||||
$settings_new_password = 'Nouveau mot de passe';
|
|
||||||
$btn_settings_save = 'Enregistrer';
|
|
||||||
$age_consent_h4 = 'Vérifions votre âge';
|
|
||||||
$age_consent_text = 'Pour visiter MorvalWatches, vous devez avoir 18 ans ou plus.';
|
|
||||||
$age_consent_btn_allow = 'J\'accepte';
|
|
||||||
$age_consent_btn_deny = 'Je refuse';
|
|
||||||
$maintenanceMode_h4 = 'La boutique en ligne est en maintenance';
|
|
||||||
$maintenanceMode_text = 'Notre boutique en ligne est en maintenance. Nous espérons vous revoir bientôt';
|
|
||||||
$maintenanceMode_btn = 'OK';
|
|
||||||
$subject_order_notification = 'MorvalWatches - Vous avez reçu une nouvelle commande!';
|
|
||||||
$subject_new_order = 'MorvalWatches - Détails de la commande';
|
|
||||||
$subject_out_of_stock = 'MorvalWatches - Rupture de stock';
|
|
||||||
$home_text = 'Accueil';
|
|
||||||
$products_text = 'Collection';
|
|
||||||
$about_text = 'À propos';
|
|
||||||
$myaccount_text = 'Compte';
|
|
||||||
$social_punch_line = 'Connectez-vous avec Morval via nos réseaux sociaux';
|
|
||||||
$privacy_text = 'Confidentialité';
|
|
||||||
$terms_text = 'Conditions générales';
|
|
||||||
$faq_text = 'Questions fréquemment posées';
|
|
||||||
$order_email_title = 'MorvalWatches - Commande';
|
|
||||||
$order_email_message_1 = 'Merci pour votre commande';
|
|
||||||
$order_email_message_2 = 'Votre commande a été reçue et est en cours de traitement. Les détails de votre commande sont ci-dessous.';
|
|
||||||
$order_email_information = 'Vos détails';
|
|
||||||
$h2_about_1 = 'À propos de Morval';
|
|
||||||
$about_header_1 = 'À propos';
|
|
||||||
$about_1_p = 'Morval Watches a été fondée en 2023 par Ralph van Wezel. Ralph est pharmacien hospitalier et a une fascination pour la technologie. Dans son travail, il s\'efforce de rendre disponibles des médicaments qui font une différence pour le patient. La production d\'un médicament nécessite des connaissances, de la précision, de l\'exactitude, de la technique, de la qualité et du savoir-faire. C\'est là que réside la similitude avec la fabrication d\'une montre automatique de haute qualité. Ralph s\'est fixé comme objectif de développer une montre capable de rivaliser avec les marques renommées, mais vendue à un prix acceptable.';
|
|
||||||
$about_header_2 = 'À propos de nos montres';
|
|
||||||
$about_2_p = 'Une montre Morval s\'inspire des modèles vintage et du design minimaliste des montres scandinaves. Grâce aux variations de couleurs du cadran et du bracelet, une montre Morval peut être portée en toute occasion, aussi bien pour le sport que pour une tenue habillée. Les montres Morval répondent aux plus hautes exigences de qualité et rivalisent avec les grandes marques suisses. Les composants proviennent de fabricants renommés d\'Europe et d\'ailleurs. Une Morval est équipée d\'un calibre de fabrication suisse (STP), reconnu pour sa fiabilité. L\'assemblage est réalisé à Amsterdam par des horlogers reconnus et chaque montre est soumise à des contrôles qualité rigoureux garantissant sa fonctionnalité et son esthétique. La montre est réglée et testée manuellement afin de minimiser les écarts de couleur. Morval est synonyme d\'un excellent rapport qualité-prix ! En achetant une montre Morval, vous avez l\'assurance d\'une montre intemporelle qui durera des décennies. Une attention particulière a été portée aux détails, tels qu\'un boîtier brossé en acier inoxydable 316, des aiguilles Superluminova, un verre antireflet et un bracelet en cuir réglable en continu. Cela reflète l\'allure luxueuse de la marque. Avec une montre Morval, vous disposez d\'un garde-temps unique, robuste, élégant et intemporel qui durera des générations !';
|
|
||||||
$about_header_3 = 'À propos de Morval';
|
|
||||||
$about_morval_text = 'En savoir plus sur l\'histoire de Morval';
|
|
||||||
$h2_about_morval_1 = 'L\'histoire de Morval';
|
|
||||||
$h2_about_morval_2 = '';
|
|
||||||
$about_morval_header_1 = '';
|
|
||||||
$about_morval_header_2 = '';
|
|
||||||
$about_morval_header_3 = '';
|
|
||||||
$about_morval_2_p = 'Une fois les décombres dégagés, cette grande place vide demeurait comme une blessure au cœur des habitants. Trois ans plus tard, la municipalité construisit un petit campanile où furent accrochées les trois cloches descendues pour la démolition. Parrainées par les habitants des années 1930, elles sont toujours vivantes et sonnent encore la cloche pour commémorer chaque événement heureux ou malheureux, comme nous le faisions autrefois.';
|
|
||||||
$about_morval_3_p = 'Une fois les décombres dégagés, cette grande place vide demeura comme une plaie dans le cœur des habitants. Trois ans plus tard, la municipalité construisit un petit campanile où furent accrochées les trois cloches descendues pour la démolition. Parrainées par les habitants des années 1930, elles sont toujours vivantes et sonnent encore la cloche pour commémorer chaque événement heureux ou malheureux, comme nous le faisions autrefois. Grâce à eux, Morval n\'oublie pas son clocher disparu.';
|
|
||||||
$invoice_morval_subject = 'Montres Morval - facture';
|
|
||||||
$place_order_header = 'Passer commande';
|
|
||||||
$checkout_header = 'Vérifier';
|
|
||||||
$tax_text = 'T.V.A.';
|
|
||||||
$h2_cart_samples = 'Échantillons';
|
|
||||||
$products_filters_h2 = 'Filtres';
|
|
||||||
$btn_filter = 'Filtre';
|
|
||||||
$sort = 'Trier';
|
|
||||||
$order_number_text = 'Commande';
|
|
||||||
$order_date_text = 'Date';
|
|
||||||
$tr_options = 'Options';
|
|
||||||
$order_invoice_text = 'Facture';
|
|
||||||
$invoice_payment_paid_text = 'Le montant total de cette facture est payé';
|
|
||||||
$highlight_1 = 'Collection';
|
|
||||||
$highlight_2 = 'Collection';
|
|
||||||
$home_timeless = 'Intemporel';
|
|
||||||
$home_timeless_text = 'Les montres Morval sont des garde-temps uniques, robustes, élégants et intemporels qui dureront des générations !';
|
|
||||||
$shop_action = 'achetez maintenant';
|
|
||||||
$home_quality = 'Qualité';
|
|
||||||
$home_quality_text = 'Les montres Morval répondent aux plus hautes exigences de qualité et rivalisent avec les grandes marques suisses. Les composants proviennent de fabricants renommés d\'Europe et d\'ailleurs. Une Morval est équipée d\'un calibre suisse (STP), reconnu pour sa fiabilité.';
|
|
||||||
$home_price = 'Prix';
|
|
||||||
$home_price_text = 'Morval est synonyme d\'un excellent rapport qualité-prix';
|
|
||||||
$shopping_cart_header = 'Panier';
|
|
||||||
$about_3_p = 'Morval tire son nom du nom de famille de l\'un des grands-parents de Ralph. Le logo s\'inspire du monument de la ville de Morval, dans le nord de la France, construit à partir des vestiges d\'une église et des trois cloches de son clocher.';
|
|
||||||
$newuser_credential_text_1 = 'Votre compte a été créé avec le nom d\'utilisateur';
|
|
||||||
$newuser_credential_text_2 = 'Veuillez cliquer sur le bouton ci-dessous pour terminer votre inscription.';
|
|
||||||
$verify_account = 'Vérifier le compte';
|
|
||||||
$newuser_signature = ' Cordialement,';
|
|
||||||
$newuser_signature_name = 'Montres Morval';
|
|
||||||
$changeuser_credential_text_1 = 'Veuillez cliquer sur le bouton ci-dessous pour réinitialiser le mot de passe de votre compte.';
|
|
||||||
$changeuser_signature = ' Cordialement,';
|
|
||||||
$changeuser_signature_name = 'Montres Morval';
|
|
||||||
$bracelet_dark = 'Noir';
|
|
||||||
$bracelet_blue = 'Bleu foncé';
|
|
||||||
$bracelet_dark_brown = 'Brun foncé';
|
|
||||||
$bracelet_light_brown = 'Marron clair';
|
|
||||||
$bracelet_steel = 'Acier';
|
|
||||||
$MWTH1NB_description = '<p>La Thomas-I dégage élégance et sophistication. Des dimensions classiques combinées à des détails subtils sur le cadran en font une montre automatique spéciale à porter en toute occasion.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable poli (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Date : Chiffres arabes (jour)</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$MWTH2NB_description = '<p>La Thomas-II offre une vue sur le cœur battant de la montre suisse. Elle incarne la précision et la perfection avec lesquelles l’heure est affichée.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable brossé (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$MWTH2IB_description = '<p>La Thomas-II offre une vue sur le cœur battant de la montre suisse. Elle incarne la précision et la perfection avec lesquelles l’heure est affichée.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable brossé (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$MWTH2RG_description = '<p>La Thomas-II offre une vue sur le cœur battant de la montre suisse. Elle incarne la précision et la perfection avec lesquelles l’heure est affichée.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable brossé (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$MWTH2DG_description = '<p>La Thomas-II offre une vue sur le cœur battant de la montre suisse. Elle incarne la précision et la perfection avec lesquelles l’heure est affichée.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable brossé (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$MWTH2G_description = '<p>La Thomas-II offre une vue sur le cœur battant de la montre suisse. Elle incarne la précision et la perfection avec lesquelles l’heure est affichée.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable brossé (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$MWABRB1_description = 'Bracelet en cuir de veau italien fait main';
|
|
||||||
$MWABRDB1_description = 'Bracelet en cuir de veau italien fait main';
|
|
||||||
$MWABRLB1_description = 'Bracelet en cuir de veau italien fait main';
|
|
||||||
$MWABRBL1_description = 'Bracelet en cuir de veau italien fait main';
|
|
||||||
$MWTH1IB_description = '<p>La Thomas-I dégage élégance et sophistication. Des dimensions classiques combinées à des détails subtils sur le cadran en font une montre automatique spéciale à porter en toute occasion.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable poli (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Date : Chiffres arabes (jour)</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$MWTH1RG_description = '<p>La Thomas-I dégage élégance et sophistication. Des dimensions classiques combinées à des détails subtils sur le cadran en font une montre automatique spéciale à porter en toute occasion.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable poli (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Date : Chiffres arabes (jour)</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$MWTH1DG_description = '<p>La Thomas-I dégage élégance et sophistication. Des dimensions classiques combinées à des détails subtils sur le cadran en font une montre automatique spéciale à porter en toute occasion.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable poli (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Date : Chiffres arabes (jour)</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$MWTH1G_description = '<p>La Thomas-I dégage élégance et sophistication. Des dimensions classiques combinées à des détails subtils sur le cadran en font une montre automatique spéciale à porter en toute occasion.</p><h3><b>Caractéristiques</b></h3><ul><li>Taille du boîtier : 39 mm x 10,5 mm.</li><li>Calibre : STP1-11 avec 26 rubis</li><li>Réserve de marche : 40 h</li><li>Isochronisme : < 10 sec./jour</li><li>Lunette : Acier inoxydable poli (316L)</li><li>Étanchéité : 50 mètres (5 ATM)</li><li>Cadran : Cadran effet rayon de soleil</li><li>Date : Chiffres arabes (jour)</li><li>Luminescence : Superluminova (Bleu)</li><li>Verre : Saphir avec revêtement antireflet</li><li>Fond du boîtier : Vissé, acier inoxydable brossé avec verre saphir</li><li>Bracelet (acier) : Acier inoxydable 316L brossé et poli</li><li>Bracelet (cuir) : Cuir de veau italien fait main</li><li>Boucle : Mécanisme déployant pour un confort optimal</li><li>Emballage : Boîte bleue avec certificat et manuel.</li></ul>';
|
|
||||||
$payment_status_0 = 'Ouvrir';
|
|
||||||
$payment_status_1 = 'Payé';
|
|
||||||
$payment_status_101 = 'En attente';
|
|
||||||
$payment_status_102 = 'Échoué';
|
|
||||||
$payment_status_103 = 'Expiré';
|
|
||||||
$payment_status_999 = 'Annulé';
|
|
||||||
$payment_method_3 = 'Débit/Crédit';
|
|
||||||
$ad_watch_1 = 'Design néerlandais et artisanat suisse';
|
|
||||||
$ad_watch_2 = 'Des montres intemporelles qui dureront des générations !';
|
|
||||||
$ad_watch_btn = 'En savoir plus';
|
|
||||||
$newsletter_h2 = 'Inscrivez-vous à la newsletter';
|
|
||||||
$newsletter_p = 'Restez connecté avec nos dernières mises à jour, conseils et offres exclusives, directement dans votre boîte de réception.';
|
|
||||||
$newsletter_confirm = 'J\'ai lu et j\'accepte la politique de confidentialité';
|
|
||||||
$newsletter_submit = 'soumettre';
|
|
||||||
$header_manufacturing = 'Qualité suisse et fabrication néerlandaise';
|
|
||||||
$header_shipping = 'Livraison gratuite sur toutes nos montres';
|
|
||||||
$header_delivery = 'Service et livraison rapides';
|
|
||||||
$header_rating = 'Note client 4,7/5,0';
|
|
||||||
?>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?php
|
|
||||||
?>
|
|
||||||
@@ -1,219 +0,0 @@
|
|||||||
<?php
|
|
||||||
$h2_brand_name_1 = 'MorvalWatches';
|
|
||||||
$h2_brand_name_2 = 'een merk met een verhaal';
|
|
||||||
$h2_brand_visit = 'Bezoek onze collectie';
|
|
||||||
$h2_brand_wow = 'Morval brengt een unieke combinatie samen van minimalistisch design, Zwitserse kwaliteit en Nederlandse productie.Wij bieden u een horloge dat bij elke gelegenheid gedragen kan worden.';
|
|
||||||
$h1_content_top = 'Onze horlogecollectie';
|
|
||||||
$product_count_1 = 'Product';
|
|
||||||
$product_count_2 = 'en';
|
|
||||||
$main_filter_category = 'Categorie';
|
|
||||||
$main_category = 'Alle';
|
|
||||||
$main_filter_sort = 'Sorteren';
|
|
||||||
$sort1 = 'A-Z';
|
|
||||||
$sort2 = 'Z-A';
|
|
||||||
$sort3 = 'Nieuwste';
|
|
||||||
$sort4 = 'Oudste';
|
|
||||||
$sort5 = 'Prijs hoog - laag';
|
|
||||||
$sort6 = 'Prijs laag - hoog';
|
|
||||||
$free_delivery = 'gratis verzending';
|
|
||||||
$non_free_delivery = 'gratis verzending vanaf';
|
|
||||||
$breadcrum_products = 'Collectie';
|
|
||||||
$product_quantity = 'Aantal';
|
|
||||||
$product_on_stock = 'Op voorraad';
|
|
||||||
$out_of_stock_notify = 'Breng me op de hoogte';
|
|
||||||
$out_of_stock_notify_2 = 'Bezoek ons @';
|
|
||||||
$out_of_stock = 'Niet op voorraad';
|
|
||||||
$add_to_basket = 'Toevoegen aan winkelwagen';
|
|
||||||
$h1_cart_name = 'Winkelwagen';
|
|
||||||
$h2_cart_suggestions = 'Suggesties';
|
|
||||||
$h2_cart_sample_product = 'Voorbeelden';
|
|
||||||
$tr_product = 'Product';
|
|
||||||
$tr_price = 'Prijs';
|
|
||||||
$tr_quantity = 'Aantal';
|
|
||||||
$tr_total = 'Totaal';
|
|
||||||
$total_subtotal = 'Subtotaal';
|
|
||||||
$total_note = '(verzendkosten worden berekend tijdens het afrekenen)';
|
|
||||||
$total_vat = 'BTW';
|
|
||||||
$total_shipping = 'Verzending';
|
|
||||||
$total_shipping_note = '(verzending inbegrepen)';
|
|
||||||
$total_discount = 'Korting';
|
|
||||||
$total_total = 'Totaal';
|
|
||||||
$total_total_note = 'BTW inbegrepen';
|
|
||||||
$btn_emptycart = 'leegmaken';
|
|
||||||
$btn_update = 'Bijwerken';
|
|
||||||
$btn_checkout = 'Afrekenen';
|
|
||||||
$navigation_back_to_store = 'terug naar collectie';
|
|
||||||
$cart_message_empty = 'U heeft geen producten in uw winkelwagen';
|
|
||||||
$error_account_name = 'Account bestaat al.';
|
|
||||||
$error_account_password_rules = 'Wachtwoord moet tussen 5 en 20 tekens lang zijn.';
|
|
||||||
$error_account_password_match = 'Wachtwoorden komen niet overeen.';
|
|
||||||
$error_account = 'Account aanmaken vereist.';
|
|
||||||
$h1_checkout = 'Afrekenen';
|
|
||||||
$account_available = 'Heeft u al een account?';
|
|
||||||
$account_log_in = 'Inloggen';
|
|
||||||
$account_create = 'Account aanmaken';
|
|
||||||
$account_create_optional = '(optioneel)';
|
|
||||||
$account_create_email = 'E-mail';
|
|
||||||
$account_create_password = 'Wachtwoord';
|
|
||||||
$account_create_password_confirm = 'Bevestig wachtwoord';
|
|
||||||
$h2_Shipping_details = 'Verzendgegevens';
|
|
||||||
$h3_shipping_method = 'Verzendmethode';
|
|
||||||
$shipping_first_name = 'Voornaam';
|
|
||||||
$shipping_last_name = 'Achternaam';
|
|
||||||
$shipping_address = 'Adres';
|
|
||||||
$shipping_city = 'Stad';
|
|
||||||
$shipping_state = 'Regio/Provincie';
|
|
||||||
$shipping_zip = 'Postcode';
|
|
||||||
$shipping_country = 'Land';
|
|
||||||
$shipping_phone = 'Telefoon';
|
|
||||||
$payment_method = 'Betaalmethode';
|
|
||||||
$payment_method_1 = 'Incasso (NL/BE klanten)';
|
|
||||||
$payment_method_2 = 'Betaling bij levering';
|
|
||||||
$h2_shoppingcart = 'Winkelwagen';
|
|
||||||
$discount_label = 'Kortingscode';
|
|
||||||
$discount_message = 'Kortingscode toegepast!';
|
|
||||||
$discount_error_1 = 'Onjuiste kortingscode!';
|
|
||||||
$discount_error_2 = 'Kortingscode verlopen!';
|
|
||||||
$order_consent_1 = 'Ik wil graag e-mailcommunicatie ontvangen over MorvalWatches nieuws, producten en diensten';
|
|
||||||
$order_consent_2 = 'Ik ga akkoord met';
|
|
||||||
$order_consent_3 = 'Algemene voorwaarden';
|
|
||||||
$btn_place_order = 'Bestellen';
|
|
||||||
$h1_order_succes_message = 'Uw bestelling is geplaatst';
|
|
||||||
$order_succes_message = 'Bedankt voor uw bestelling! We nemen contact met u op via e-mail met uw bestelgegevens.';
|
|
||||||
$error_myaccount = 'Onjuiste e-mail/wachtwoord!';
|
|
||||||
$h1_login = 'Inloggen';
|
|
||||||
$h1_register = 'Registreren';
|
|
||||||
$h1_myaccount = 'Mijn account';
|
|
||||||
$h2_menu = 'Menu';
|
|
||||||
$menu_orders = 'Bestellingen';
|
|
||||||
$menu_downloads = 'Downloads';
|
|
||||||
$menu_settings = 'Instellingen';
|
|
||||||
$h2_myorders = 'Mijn bestellingen';
|
|
||||||
$myorders_message = 'U heeft geen bestellingen';
|
|
||||||
$myorders_order = 'Bestelling';
|
|
||||||
$myorders_date = 'Datum';
|
|
||||||
$myorders_status = 'Status';
|
|
||||||
$myorders_shipping = 'Verzending';
|
|
||||||
$myorders_total = 'Totaal';
|
|
||||||
$h2_mydownloads = 'Mijn downloads';
|
|
||||||
$mydownloads_message = 'U heeft geen downloads';
|
|
||||||
$mydownloads_product = 'Product';
|
|
||||||
$h2_settings = 'Instellingen';
|
|
||||||
$settings_email = 'E-mail';
|
|
||||||
$settings_new_password = 'Nieuw wachtwoord';
|
|
||||||
$btn_settings_save = 'Opslaan';
|
|
||||||
$age_consent_h4 = 'Laten we uw leeftijd controleren';
|
|
||||||
$age_consent_text = 'Om MorvalWatches te bezoeken moet u 18 jaar of ouder zijn.';
|
|
||||||
$age_consent_btn_allow = 'Akkoord';
|
|
||||||
$age_consent_btn_deny = 'Weigeren';
|
|
||||||
$maintenanceMode_h4 = 'Webshop is in onderhoud';
|
|
||||||
$maintenanceMode_text = 'Onze webshop is in onderhoud. We zien u graag snel terug';
|
|
||||||
$maintenanceMode_btn = 'OK';
|
|
||||||
$subject_order_notification = 'MorvalWatches - U heeft een nieuwe bestelling ontvangen!';
|
|
||||||
$subject_new_order = 'MorvalWatches - Bestelgegevens';
|
|
||||||
$subject_out_of_stock = 'MorvalWatches - Niet op voorraad';
|
|
||||||
$home_text = 'Home';
|
|
||||||
$products_text = 'Collectie';
|
|
||||||
$about_text = 'Over ons';
|
|
||||||
$myaccount_text = 'Account';
|
|
||||||
$social_punch_line = 'Verbind met Morval via onze social media kanalen';
|
|
||||||
$privacy_text = 'Privacy';
|
|
||||||
$terms_text = 'Algemene voorwaarden';
|
|
||||||
$faq_text = 'Veelgestelde vragen';
|
|
||||||
$order_email_title = 'MorvalWatches - Bestelling';
|
|
||||||
$order_email_message_1 = 'Bedankt voor uw bestelling';
|
|
||||||
$order_email_message_2 = 'Uw bestelling is ontvangen en wordt momenteel verwerkt. De details van uw bestelling vindt u hieronder.';
|
|
||||||
$order_email_information = 'Uw gegevens';
|
|
||||||
$h2_about_1 = 'Over Morval';
|
|
||||||
$h2_about_2 = '';
|
|
||||||
$about_header_1 = 'Over ons';
|
|
||||||
$about_1_p = 'Morval Watches werd in 2023 opgericht door Ralph van Wezel. Ralph is ziekenhuisapotheker en heeft een fascinatie voor technologie. In zijn werk streeft hij ernaar om geneesmiddelen beschikbaar te maken die een verschil maken voor de patiënt. Het produceren van een geneesmiddel vereist kennis, precisie, nauwkeurigheid, techniek, kwaliteit en vakmanschap. Hierin ligt de overeenkomst met de vervaardiging van een hoogwaardige automatische horloge. Ralph heeft zich tot doel gesteld een horloge te ontwikkelen dat kan concurreren met de gerenommeerde merken, maar tegen een acceptabele prijs wordt verkocht.';
|
|
||||||
$about_header_2 = 'Over onze horloges';
|
|
||||||
$about_2_p = 'Een Morval horloge is geïnspireerd op de vintage modellen en het minimalistische design van Scandinavische horloges. Door de kleurvariaties van de wijzerplaat en banden kan een Morval horloge bij elke gelegenheid gedragen worden, zowel als sport- als dresshorloge. Morval horloges voldoen aan de hoogste kwaliteitseisen en kunnen wedijveren met de bekende Zwitserse merken. De onderdelen worden geleverd door gerenommeerde fabrikanten uit Europa en daarbuiten. Een Morval bevat een Swiss made kaliber (STP) dat bekend staat om zijn betrouwbare kwaliteit. De assemblage vindt plaats in Amsterdam door erkende horlogemakers en elk horloge ondergaat een uitgebreide kwaliteitscontrole op functionaliteit en esthetiek. Het horloge wordt handmatig afgesteld en getest om de afwijking te minimaliseren. Morval staat voor een uitstekende prijs-kwaliteitverhouding! Wanneer u een Morval horloge koopt, bent u verzekerd van een tijdloos uurwerk dat tientallen jaren meegaat. Er is veel aandacht besteed aan details, zoals een geborstelde kast van roestvrij staal 316, superluminova op de wijzers, ontspiegeld glas en traploos verstelbare leren band. Dit vertaalt zich in de luxe uitstraling van het merk. Met een Morval Horloge heeft u een uniek, robuust, stijlvol en tijdloos horloge dat generaties lang meegaat!';
|
|
||||||
$about_header_3 = 'Over Morval';
|
|
||||||
$about_morval_text = 'Lees meer over de geschiedenis van Morval';
|
|
||||||
$h2_about_morval_1 = 'De geschiedenis van Morval';
|
|
||||||
$h2_about_morval_2 = '';
|
|
||||||
$about_morval_header_1 = '';
|
|
||||||
$about_morval_header_2 = '';
|
|
||||||
$about_morval_header_3 = '';
|
|
||||||
$about_morval_1_p = ' Morval, een dorp met 96 inwoners, ligt tussen 4 gemeenten van de Somme als een schiereiland van Pas-de-Calais aan het einde van het kanton Bapaume. Vóór 1914 telde het 220 tot 250 inwoners, maar het werd volledig verwoest tijdens de Slag bij Morval in de Eerste Wereldoorlog (1914-18). De herbouwde kerk was qua stijl, allure en verhoudingen (45 meter hoog, 40 meter lang) een bijna exacte kopie van de vorige. De klokkentoren herbergde 3 prachtige klokken, wat vrij zeldzaam is voor een klein dorp. Het werd ingehuldigd in oktober 1932. Helaas was het geen goede wederopbouw en na de Tweede Wereldoorlog was het noodzakelijk om het dak te repareren, scheuren rond de klokkentoren te dichten, glas-in-loodramen te vervangen, enz. Al snel konden opeenvolgende gemeenten de achteruitgang niet meer aan. Een volledige renovatie zou minstens 1.500.000 frank hebben gekost, terwijl het jaarlijkse budget van de gemeente slechts 120.000 frank bedroeg. In november 1973 stortte tijdens een begrafenis een deel van de kerk in tijdens het offer. Het gebouw was niet langer veilig en werd gesloten voor erediensten. In 1985 besloten de burgemeester, afgevaardigden, raadsleden en bestuurders de kerk te vernietigen. Voor deze zeer trieste operatie werd een bedrag van 66.000 frank gereserveerd, dat werd verlicht door een subsidie verkregen van de algemene raad.';
|
|
||||||
$about_morval_2_p = 'Toen het puin was geruimd, bleef dit grote lege plein als een wond achter in de harten van de inwoners. Drie jaar later bouwde de gemeente een kleine klokkentoren waar de drie klokken werden opgehangen die voor de sloop waren neergelaten. Gesponsord door inwoners uit de jaren 30, leven ze nog steeds en luiden ze nog steeds de klok om elke gelukkige of ongelukkige gebeurtenis te vieren, zoals wij vroeger deden.';
|
|
||||||
$about_morval_3_p = 'Toen het puin was geruimd, bleef dit grote lege plein als een wond achter in de harten van de inwoners. Drie jaar later bouwde de gemeente een kleine klokkentoren waar de drie klokken werden opgehangen die voor de sloop waren neergelaten. Gesponsord door inwoners uit de jaren 30, leven ze nog steeds en luiden ze nog steeds de klokken om elke gelukkige of ongelukkige gebeurtenis te vieren, zoals wij dat vroeger deden. Dankzij hen vergeet Morval zijn verdwenen klokkentoren niet.';
|
|
||||||
$invoice_morval_subject = 'Morval horloges - factuur';
|
|
||||||
$place_order_header = 'Bestelling plaatsen';
|
|
||||||
$checkout_header = 'Uitchecken';
|
|
||||||
$tax_text = 'VAT';
|
|
||||||
$h2_cart_samples = 'Monsters';
|
|
||||||
$products_filters_h2 = 'Filters';
|
|
||||||
$btn_filter = 'Filter';
|
|
||||||
$sort = 'Soort';
|
|
||||||
$order_number_text = 'Volgorde';
|
|
||||||
$order_date_text = 'Datum';
|
|
||||||
$tr_options = 'Opties';
|
|
||||||
$order_invoice_text = 'Factuur';
|
|
||||||
$invoice_payment_paid_text = 'Het totaalbedrag van deze factuur wordt betaald';
|
|
||||||
$highlight_1 = 'Verzameling';
|
|
||||||
$highlight_2 = 'Verzameling';
|
|
||||||
$home_timeless = 'Tijdloos';
|
|
||||||
$home_timeless_text = 'Morval Horloges zijn unieke, robuuste, stijlvolle en tijdloze horloges die generaties lang meegaan!';
|
|
||||||
$shop_action = 'nu winkelen';
|
|
||||||
$home_quality = 'Kwaliteit';
|
|
||||||
$home_quality_text = 'Morval horloges voldoen aan de hoogste kwaliteitseisen en kunnen wedijveren met de bekende Zwitserse merken. De onderdelen worden geleverd door gerenommeerde fabrikanten uit Europa en daarbuiten. Een Morval bevat een Swiss made kaliber (STP) dat bekend staat om zijn betrouwbare kwaliteit.';
|
|
||||||
$home_price = 'Prijs';
|
|
||||||
$home_price_text = 'Morval staat voor een uitstekende prijs-kwaliteitverhouding';
|
|
||||||
$shopping_cart_header = 'Winkelwagen';
|
|
||||||
$about_3_p = 'Morval ontleent zijn naam aan de achternaam van een van Ralphs grootouders. Het logo is geïnspireerd op het monument in het Noord-Franse stadje Morval, dat gebouwd is uit de resten van een kerk en de drie klokken van de toren.';
|
|
||||||
$newuser_subject = 'MorvalWatches - gebruiker aangemaakt';
|
|
||||||
$newuser_header = 'Beste gebruiker';
|
|
||||||
$newuser_text = 'Uw beheerder heeft toegang verleend tot het Klantenportaal.';
|
|
||||||
$newuser_credential_text_1 = 'Uw account is aangemaakt met gebruikersnaam';
|
|
||||||
$newuser_credential_text_2 = 'Klik op onderstaande knop om uw registratie te voltooien.';
|
|
||||||
$newuser_closure = 'Om veiligheidsredenen is deze link slechts 10 minuten actief.';
|
|
||||||
$verify_account = 'Account verifiëren';
|
|
||||||
$newuser_signature = ' Met vriendelijke groeten,';
|
|
||||||
$newuser_signature_name = 'MorvalWatches';
|
|
||||||
$changeuser_subject = 'MorvalWatches - wachtwoord reset aangevraagd';
|
|
||||||
$changeuser_header = 'Beste gebruiker';
|
|
||||||
$changeuser_credential_text_1 = 'Klik op de onderstaande knop om het wachtwoord van uw account opnieuw in te stellen.';
|
|
||||||
$changeuser_closure = 'Om veiligheidsredenen is deze link slechts 10 minuten actief.';
|
|
||||||
$changeuser_signature = ' Met vriendelijke groeten,';
|
|
||||||
$changeuser_signature_name = 'MorvalWatches';
|
|
||||||
$bracelet_dark = 'Zwart';
|
|
||||||
$bracelet_blue = 'Donkerblauw';
|
|
||||||
$bracelet_dark_brown = 'Donkerbruin';
|
|
||||||
$bracelet_light_brown = 'Lichtbruin';
|
|
||||||
$bracelet_steel = 'Staal';
|
|
||||||
$MWTH1NB_description = '<p>De Thomas-I straalt elegantie en verfijning uit. Klassieke afmetingen gecombineerd met subtiele details in de wijzerplaat maken het een bijzondere automatische horloge dat bij elke gelegenheid gedragen kan worden.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Gepolijst roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Datum: Arabische cijfers (dag)</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$MWTH2NB_description = '<p>De Thomas-II biedt een blik op het kloppende hart van het Zwitserse uurwerk. Het benadrukt de precisie en perfectie waarmee de tijd wordt weergegeven.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Geborsteld roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$MWTH2IB_description = '<p>De Thomas-II biedt een blik op het kloppende hart van het Zwitserse uurwerk. Het benadrukt de precisie en perfectie waarmee de tijd wordt weergegeven.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Geborsteld roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$MWTH2RG_description = '<p>De Thomas-II biedt een blik op het kloppende hart van het Zwitserse uurwerk. Het benadrukt de precisie en perfectie waarmee de tijd wordt weergegeven.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Geborsteld roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$MWTH2DG_description = '<p>De Thomas-II biedt een blik op het kloppende hart van het Zwitserse uurwerk. Het benadrukt de precisie en perfectie waarmee de tijd wordt weergegeven.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Geborsteld roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$MWTH2G_description = '<p>De Thomas-II biedt een blik op het kloppende hart van het Zwitserse uurwerk. Het benadrukt de precisie en perfectie waarmee de tijd wordt weergegeven.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Geborsteld roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$MWABRB1_description = 'Armband Handgemaakt Italiaans kalfsleer';
|
|
||||||
$MWABRDB1_description = 'Armband Handgemaakt Italiaans kalfsleer';
|
|
||||||
$MWABRLB1_description = 'Armband Handgemaakt Italiaans kalfsleer';
|
|
||||||
$MWABRBL1_description = 'Armband Handgemaakt Italiaans kalfsleer';
|
|
||||||
$MWTH1IB_description = '<p>De Thomas-I straalt elegantie en verfijning uit. Klassieke afmetingen gecombineerd met subtiele details in de wijzerplaat maken het een bijzondere automatische horloge dat bij elke gelegenheid gedragen kan worden.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Gepolijst roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Datum: Arabische cijfers (dag)</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$MWTH1RG_description = '<p>De Thomas-I straalt elegantie en verfijning uit. Klassieke afmetingen gecombineerd met subtiele details in de wijzerplaat maken het een bijzondere automatische horloge dat bij elke gelegenheid gedragen kan worden.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Gepolijst roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Datum: Arabische cijfers (dag)</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$MWTH1DG_description = '<p>De Thomas-I straalt elegantie en verfijning uit. Klassieke afmetingen gecombineerd met subtiele details in de wijzerplaat maken het een bijzondere automatische horloge dat bij elke gelegenheid gedragen kan worden.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Gepolijst roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Datum: Arabische cijfers (dag)</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$MWTH1G_description = '<p>De Thomas-I straalt elegantie en verfijning uit. Klassieke afmetingen gecombineerd met subtiele details in de wijzerplaat maken het een bijzondere automatische horloge dat bij elke gelegenheid gedragen kan worden.</p><h3><b>Specificaties</b></h3><ul><li>Kastgrootte: 39 mm x 10,5 mm.</li><li>Kaliber: STP1-11 met 26 juwelen</li><li>Energiereserve: 40 u</li><li>Isocronisme: < 10 sec./dag</li><li>Lunette: Gepolijst roestvrij staal (316L)</li><li>Waterdicht: 50 meter (5 ATM)</li><li>Wijzerplaat: Zonnestraal-patroon</li><li>Datum: Arabische cijfers (dag)</li><li>Lumen: Superluminova (Blauw)</li><li>Glas: Saffierglas met antireflecterende coating</li><li>Achterkant kast: Geschroefd, geborsteld roestvrij staal met saffierglas</li><li>Band (staal): Geborsteld en gepolijst 316L roestvrij staal</li><li>Band (leer): Handgemaakt Italiaans kalfsleer</li><li>Sluiting: Vouwmechanisme voor ultiem comfort</li><li>Verpakking: Blauwe doos met certificaat en handleiding.</li></ul>';
|
|
||||||
$payment_status_0 = 'Open';
|
|
||||||
$payment_status_1 = 'Betaald';
|
|
||||||
$payment_status_101 = 'In behandeling';
|
|
||||||
$payment_status_102 = 'Mislukt';
|
|
||||||
$payment_status_103 = 'Verlopen';
|
|
||||||
$payment_status_999 = 'Geannuleerd';
|
|
||||||
$payment_method_3 = 'Debet/Credit';
|
|
||||||
$ad_watch_1 = 'Nederlands design en Zwitsers vakmanschap';
|
|
||||||
$ad_watch_2 = 'Tijdloze uurwerken die generaties lang meegaan!';
|
|
||||||
$ad_watch_btn = 'lees verder';
|
|
||||||
$newsletter_h2 = 'Meld u aan voor de nieuwsbrief';
|
|
||||||
$newsletter_p = 'Blijf op de hoogte van onze laatste updates, tips en exclusieve aanbiedingen, rechtstreeks in uw inbox.';
|
|
||||||
$newsletter_confirm = 'Ik heb het privacybeleid gelezen en ga ermee akkoord';
|
|
||||||
$newsletter_submit = 'indienen';
|
|
||||||
$header_manufacturing = 'Zwitserse kwaliteit en Nederlandse makelij';
|
|
||||||
$header_shipping = 'Gratis verzending op al onze horloges';
|
|
||||||
$header_delivery = 'Snelle service en levering';
|
|
||||||
$header_rating = 'Klantbeoordeling 4,7/5,0';
|
|
||||||
?>
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
<?php
|
|
||||||
$h2_brand_name_1 = 'MorvalWatches';
|
|
||||||
$h2_brand_name_2 = 'a brand with a story';
|
|
||||||
$h2_brand_visit = 'Visit our collection';
|
|
||||||
$h2_brand_wow = 'Morval brings together a unique combination of Minimalistic design, Swiss quality and Dutch manufacturing.We give you a watch to wear in any occasion.';
|
|
||||||
$h1_content_top = 'Our watch collection';
|
|
||||||
$product_count_1 = 'Product';
|
|
||||||
$product_count_2 = 's';
|
|
||||||
$main_filter_category = 'Category';
|
|
||||||
$main_category = 'All';
|
|
||||||
$main_filter_sort = 'Sort';
|
|
||||||
$sort1 = 'A-Z';
|
|
||||||
$sort2 = 'Z-A';
|
|
||||||
$sort3 = 'Latest';
|
|
||||||
$sort4 = 'Oldest';
|
|
||||||
$sort5 = 'Price High - Low';
|
|
||||||
$sort6 = 'Price Low - High';
|
|
||||||
$free_delivery = 'free delivery';
|
|
||||||
$non_free_delivery = 'free delivery from';
|
|
||||||
$breadcrum_products = 'Collection';
|
|
||||||
$product_quantity = 'Quantity';
|
|
||||||
$product_on_stock = 'In Stock';
|
|
||||||
$out_of_stock_notify = 'Notify Me';
|
|
||||||
$out_of_stock_notify_2 = 'Visit us @';
|
|
||||||
$out_of_stock = 'Out of stock';
|
|
||||||
$add_to_basket = 'Add To Cart';
|
|
||||||
$h1_cart_name = 'Shopping Cart';
|
|
||||||
$h2_cart_suggestions = 'Suggestions';
|
|
||||||
$h2_cart_sample_product = 'Samples';
|
|
||||||
$tr_product = 'Product';
|
|
||||||
$tr_price = 'Price';
|
|
||||||
$tr_quantity = 'Quantity';
|
|
||||||
$tr_total = 'Total';
|
|
||||||
$total_subtotal = 'Subtotal';
|
|
||||||
$total_note = '(shipping is calculated during checkout)';
|
|
||||||
$total_vat = 'VAT';
|
|
||||||
$total_shipping = 'Shipping';
|
|
||||||
$total_shipping_note = '(shipping included)';
|
|
||||||
$total_discount = 'Discount';
|
|
||||||
$total_total = 'Total';
|
|
||||||
$total_total_note = 'VAT included';
|
|
||||||
$btn_emptycart = 'clear';
|
|
||||||
$btn_update = 'Update';
|
|
||||||
$btn_checkout = 'Checkout';
|
|
||||||
$navigation_back_to_store = 'return to collection';
|
|
||||||
$cart_message_empty = 'You have no products added in your Shopping Cart';
|
|
||||||
$error_account_name = 'Account already exists.';
|
|
||||||
$error_account_password_rules = 'Password must be between 5 and 20 characters long.';
|
|
||||||
$error_account_password_match = 'Passwords do not match.';
|
|
||||||
$error_account = 'Account creation required.';
|
|
||||||
$h1_checkout = 'Checkout';
|
|
||||||
$account_available = 'Already have an account?';
|
|
||||||
$account_log_in = 'Log In';
|
|
||||||
$account_create = 'Create Account';
|
|
||||||
$account_create_optional = '(optional)';
|
|
||||||
$account_create_email = 'Email';
|
|
||||||
$account_create_password = 'Password';
|
|
||||||
$account_create_password_confirm = 'Confirm Password';
|
|
||||||
$h2_Shipping_details = 'Shipping Details';
|
|
||||||
$h3_shipping_method = 'Shipping Method';
|
|
||||||
$shipping_first_name = 'First Name';
|
|
||||||
$shipping_last_name = 'Last Name';
|
|
||||||
$shipping_address = 'Address';
|
|
||||||
$shipping_city = 'City';
|
|
||||||
$shipping_state = 'Region/State';
|
|
||||||
$shipping_zip = 'Zip';
|
|
||||||
$shipping_country = 'Country';
|
|
||||||
$shipping_phone = 'Phone';
|
|
||||||
$payment_method = 'Payment Method';
|
|
||||||
$payment_method_1 = 'Debit (NL/BE customers)';
|
|
||||||
$payment_method_2 = 'Pay on delivery';
|
|
||||||
$h2_shoppingcart = 'Shopping Cart';
|
|
||||||
$discount_label = 'Discount Code';
|
|
||||||
$discount_message = 'Discount code applied!';
|
|
||||||
$discount_error_1 = 'Incorrect discount code!';
|
|
||||||
$discount_error_2 = 'Discount code expired!';
|
|
||||||
$order_consent_1 = 'I would like to recieve email communication about MorvalWatches news, products and services';
|
|
||||||
$order_consent_2 = 'I agree with';
|
|
||||||
$order_consent_3 = 'Terms & Conditions';
|
|
||||||
$btn_place_order = 'Order';
|
|
||||||
$h1_order_succes_message = 'Your Order Has Been Placed';
|
|
||||||
$order_succes_message = 'Thank you for ordering with us! We will contact you by email with your order details.';
|
|
||||||
$error_myaccount = 'Incorrect Email/Password!';
|
|
||||||
$h1_login = 'Login';
|
|
||||||
$h1_register = 'Register';
|
|
||||||
$h1_myaccount = 'My Account';
|
|
||||||
$h2_menu = 'Menu';
|
|
||||||
$menu_orders = 'Orders';
|
|
||||||
$menu_downloads = 'Downloads';
|
|
||||||
$menu_settings = 'Settings';
|
|
||||||
$h2_myorders = 'My orders';
|
|
||||||
$myorders_message = 'You have no orders';
|
|
||||||
$myorders_order = 'Order';
|
|
||||||
$myorders_date = 'Date';
|
|
||||||
$myorders_status = 'Status';
|
|
||||||
$myorders_shipping = 'Shipping';
|
|
||||||
$myorders_total = 'Total';
|
|
||||||
$h2_mydownloads = 'My downloads';
|
|
||||||
$mydownloads_message = 'You have no downloads';
|
|
||||||
$mydownloads_product = 'Product';
|
|
||||||
$h2_settings = 'Settings';
|
|
||||||
$settings_email = 'Email';
|
|
||||||
$settings_new_password = 'New Password';
|
|
||||||
$btn_settings_save = 'Save';
|
|
||||||
$age_consent_h4 = 'Lets check your age';
|
|
||||||
$age_consent_text = 'To visit MorvalWatches you need to be 18 years or older.';
|
|
||||||
$age_consent_btn_allow = 'Agree';
|
|
||||||
$age_consent_btn_deny = 'disagree';
|
|
||||||
$maintenanceMode_h4 = 'Webshop is in maintenance';
|
|
||||||
$maintenanceMode_text = 'Our webshop is in maintenance. We like to see you back soon';
|
|
||||||
$maintenanceMode_btn = 'OK';
|
|
||||||
$subject_order_notification = 'MorvalWatches - You have received a new order!';
|
|
||||||
$subject_new_order = 'MorvalWatches - Order Details';
|
|
||||||
$subject_out_of_stock = 'MorvalWatches - Out of Stock';
|
|
||||||
$home_text = 'Home';
|
|
||||||
$products_text = 'Collection';
|
|
||||||
$about_text = 'About Us';
|
|
||||||
$myaccount_text = 'Account';
|
|
||||||
$social_punch_line = 'Connect with Morval via our social media channels';
|
|
||||||
$privacy_text = 'Privacy';
|
|
||||||
$terms_text = 'Terms and Conditions';
|
|
||||||
$faq_text = 'Frequent asked questions';
|
|
||||||
$order_email_title = 'MorvalWatches - Order';
|
|
||||||
$order_email_message_1 = 'Thank you for your order';
|
|
||||||
$order_email_message_2 = 'Your order has been received and is currently being processed. The details for your order are below.';
|
|
||||||
$order_email_information = 'Your Details';
|
|
||||||
$h2_about_1 = 'About Morval';
|
|
||||||
$h2_about_2 = '';
|
|
||||||
$about_header_1 = 'About US';
|
|
||||||
$about_1_p = 'Morval Watches was founded in 2023 by Ralph van Wezel. Ralph is a hospital pharmacist and has a fascination for technology. In his work he strives to make medicines available that make a difference for the patient. Producing a medicine requires knowledge, precision, accuracy, technique, quality and craftsmanship. Herein lies the similarity with the manufacture of a high-quality automatic watch. Ralph has set itself the goal of developing a watch that can compete with the renowned brands, but is sold at an acceptable price.';
|
|
||||||
$about_header_2 = 'About our watches';
|
|
||||||
$about_2_p = 'A Morval Watch is inspired by the vintage models and minimalistic design of Scandinavian watches. Due to variations in the color of the dial and straps, a Morval watch can be worn on any occasion, both as sport and dress watch.Morval watches meet the highest quality requirements and can compete with the well-known Swiss brands. The parts are supplied by renowned manufacturers from Europe and beyond. A Morval contains a Swiss-made caliber (STP) that is known for its reliable quality. The assemblies take place in Amsterdam by recognized watchmakers and each watch undergoes extensive quality control for functionality and aesthetics. The watch is manually adjusted and tested to minimize the deviation. Morval stands for an excellent price-quality ratio! When you purchase a Morval watch, you are assured of a timeless timepiece that will last for decades.A lot of attention has been paid to details, such as a brushed case of stainless steel 316 steel, superluminova on the hands, anti-reflective glass and infinitely adjustable leather strap. This translates into the luxurious appearance of the brand. With a Morval Watch you have a unique, robust, stylish and timeless timepiece that will last for generations!';
|
|
||||||
$about_header_3 = 'About Morval';
|
|
||||||
$about_morval_text = 'Read more about the history of Morval';
|
|
||||||
$h2_about_morval_1 = 'The history of Morval';
|
|
||||||
$h2_about_morval_2 = '';
|
|
||||||
$about_morval_header_1 = '';
|
|
||||||
$about_morval_header_2 = '';
|
|
||||||
$about_morval_header_3 = '';
|
|
||||||
$about_morval_1_p = '"Morval, a village of 96 inhabitants, is located between 4 communes of the Somme as a peninsula of Pas-de-Calais at the end of the canton of Bapaume.';
|
|
||||||
$about_morval_2_p = 'When the rubble was cleared, this large empty square remained like a wound in the hearts of the inhabitants. Three years later the municipality built a small campanile where the three bells that were lowered for demolition were hung. Sponsored by 1930s residents, they remain alive and still ring the bell to mark every happy or unfortunate event as we once did.';
|
|
||||||
$about_morval_3_p = 'When the rubble was cleared, this large empty square remained like a wound in the hearts of the inhabitants. Three years later the municipality built a small campanile where the three bells that were lowered for demolition were hung. Sponsored by 1930s residents, they remain alive and still ring the bell to mark every happy or unfortunate event as we once did. Thanks to them, Morval does not forget its missing bell tower.';
|
|
||||||
$invoice_morval_subject = 'Morval watches - invoice';
|
|
||||||
$place_order_header = 'Place order';
|
|
||||||
$checkout_header = 'Checkout';
|
|
||||||
$tax_text = 'VAT';
|
|
||||||
$h2_cart_samples = 'Samples';
|
|
||||||
$products_filters_h2 = 'Filters';
|
|
||||||
$btn_filter = 'Filter';
|
|
||||||
$sort = 'Sort';
|
|
||||||
$order_number_text = 'Order';
|
|
||||||
$order_date_text = 'Date';
|
|
||||||
$tr_options = 'Options';
|
|
||||||
$order_invoice_text = 'Invoice';
|
|
||||||
$invoice_payment_paid_text = 'The total amount of this invoice is paid';
|
|
||||||
$highlight_1 = 'Collection';
|
|
||||||
$highlight_2 = 'Collection';
|
|
||||||
$home_timeless = 'Timeless';
|
|
||||||
$home_timeless_text = 'Morval Watches are unique, robust, stylish and timeless timepieces that will last for generations!';
|
|
||||||
$shop_action = 'shop now';
|
|
||||||
$home_quality = 'Quality';
|
|
||||||
$home_quality_text = 'Morval watches meet the highest quality requirements and can compete with the well-known Swiss brands. The parts are supplied by renowned manufacturers from Europe and beyond. A Morval contains a Swiss-made caliber (STP) that is known for its reliable quality.';
|
|
||||||
$home_price = 'Price';
|
|
||||||
$home_price_text = 'Morval stands for an excellent price-quality ratio';
|
|
||||||
$shopping_cart_header = 'Shopping Cart';
|
|
||||||
$about_3_p = 'Morval takes its name from the surname of one of Ralphs grandparents. The logo is inspired by the monument in the town of Morval in northern France, which was built from the remains of a church and the three bells from the tower.';
|
|
||||||
$newuser_subject = 'MorvalWatches - user created';
|
|
||||||
$newuser_header = 'Dear user';
|
|
||||||
$newuser_text = 'Your administrator has provided access to the CustomerPortal.';
|
|
||||||
$newuser_credential_text_1 = 'Your account has been created with username';
|
|
||||||
$newuser_credential_text_2 = 'Please click the button below to complete your registration.';
|
|
||||||
$newuser_closure = 'For security reasons this link is only active for 10 minutes.';
|
|
||||||
$verify_account = 'Verify account';
|
|
||||||
$newuser_signature = 'Kind regards, ';
|
|
||||||
$newuser_signature_name = 'MorvalWatches';
|
|
||||||
$changeuser_subject = 'MorvalWatches - password reset requested';
|
|
||||||
$changeuser_header = 'Dear user';
|
|
||||||
$changeuser_credential_text_1 = 'Please click the button below to reset the password of your account.';
|
|
||||||
$changeuser_closure = 'For security reasons this link is only active for 10 minutes.';
|
|
||||||
$changeuser_signature = 'Kind regards, ';
|
|
||||||
$changeuser_signature_name = 'MorvalWatches';
|
|
||||||
$bracelet_dark = 'Black';
|
|
||||||
$bracelet_blue = 'Dark Blue';
|
|
||||||
$bracelet_dark_brown = 'Dark brown';
|
|
||||||
$bracelet_light_brown = 'Light brown';
|
|
||||||
$bracelet_steel = 'Steel';
|
|
||||||
$MWTH1NB_description = '<p>The Thomas-I exudes elegance and sophistication. Classic dimensions combined with subtle details in the dial make it an special automatic watch that can be worn on all occasions.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h</li><li>Isochronism: < 10 sec./day</li><li>Bezel: Polished stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Date: Arabic numbers (day)</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating</li><li>Back Case: Screwed, brushed stainless steel with sapphire crystal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$MWTH1NB_description = 'Le Thomas-I respire l\'élégance et la sophistication. Des dimensions classiques combinées à des détails subtils sur le cadran en font une montre automatique spéciale qui peut être portée en toutes occasions.SpécificationsTaille du boîtier : 39 mm x 10,5 mm.Calibre : STP1-11 avec 26 rubisRéserve de marche : 40 hIsochronisme : < 10 sec./jourLunette : Acier inoxydable poli (316L)Étanchéité : 50 mètres (5 ATM)Cadran : Cadran soleilléDate : Chiffres arabes (jour)Lumen : Superluminova (bleu)Verre : Saphir avec traitement antirefletFond du boîtier : Acier inoxydable brossé vissé avec verre saphirBracelet (acier) : Brossé et poli Acier inoxydable 316LBracelet (cuir) : Cuir de veau italien fait mainFermoir : Mécanisme pliant pour un confort ultimeEmballage : Boîte bleue avec certificat et manuel.';
|
|
||||||
$MWTH2NB_description = '<p>The Thomas-II provides a view of the beating heart of the Swiss timepiece. It marks the precision and perfection with which the time is displayed.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h </li><li>Isochronism: < 10 sec./day</li><li>Bezel: Brushed stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating </li><li>Back Case: Screwed, brushed stainless steel with sapphire crytal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$MWTH2IB_description = '<p>The Thomas-II provides a view of the beating heart of the Swiss timepiece. It marks the precision and perfection with which the time is displayed.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h </li><li>Isochronism: < 10 sec./day</li><li>Bezel: Brushed stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating </li><li>Back Case: Screwed, brushed stainless steel with sapphire crytal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$MWTH2RG_description = '<p>The Thomas-II provides a view of the beating heart of the Swiss timepiece. It marks the precision and perfection with which the time is displayed.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h </li><li>Isochronism: < 10 sec./day</li><li>Bezel: Brushed stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating </li><li>Back Case: Screwed, brushed stainless steel with sapphire crytal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$MWTH2DG_description = '<p>The Thomas-II provides a view of the beating heart of the Swiss timepiece. It marks the precision and perfection with which the time is displayed.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h </li><li>Isochronism: < 10 sec./day</li><li>Bezel: Brushed stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating </li><li>Back Case: Screwed, brushed stainless steel with sapphire crytal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$MWTH2G_description = '<p>The Thomas-II provides a view of the beating heart of the Swiss timepiece. It marks the precision and perfection with which the time is displayed.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h </li><li>Isochronism: < 10 sec./day</li><li>Bezel: Brushed stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating </li><li>Back Case: Screwed, brushed stainless steel with sapphire crytal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$MWABRB1_description = 'Bracelet Handmade Italian Calf leather';
|
|
||||||
$MWABRDB1_description = 'Bracelet Handmade Italian Calf leather';
|
|
||||||
$MWABRLB1_description = 'Bracelet Handmade Italian Calf leather';
|
|
||||||
$MWABRBL1_description = 'Bracelet Handmade Italian Calf leather';
|
|
||||||
$MWTH1IB_description = '<p>The Thomas-I exudes elegance and sophistication. Classic dimensions combined with subtle details in the dial make it an special automatic watch that can be worn on all occasions.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h</li><li>Isochronism: < 10 sec./day</li><li>Bezel: Polished stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Date: Arabic numbers (day)</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating</li><li>Back Case: Screwed, brushed stainless steel with sapphire crystal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$MWTH1RG_description = '<p>The Thomas-I exudes elegance and sophistication. Classic dimensions combined with subtle details in the dial make it an special automatic watch that can be worn on all occasions.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h</li><li>Isochronism: < 10 sec./day</li><li>Bezel: Polished stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Date: Arabic numbers (day)</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating</li><li>Back Case: Screwed, brushed stainless steel with sapphire crystal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$MWTH1DG_description = '<p>The Thomas-I exudes elegance and sophistication. Classic dimensions combined with subtle details in the dial make it an special automatic watch that can be worn on all occasions.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h</li><li>Isochronism: < 10 sec./day</li><li>Bezel: Polished stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Date: Arabic numbers (day)</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating</li><li>Back Case: Screwed, brushed stainless steel with sapphire crystal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$MWTH1G_description = '<p>The Thomas-I exudes elegance and sophistication. Classic dimensions combined with subtle details in the dial make it an special automatic watch that can be worn on all occasions.</p><h3><b>Specifications</b></h3><ul><li>Case Size: 39 mm x 10,5 mm.</li><li>Caliber: STP1-11 with 26 jewels</li><li>Power reserve: 40 h</li><li>Isochronism: < 10 sec./day</li><li>Bezel: Polished stainless steel (316L)</li><li>Waterproof: 50 meters (5 ATM)</li><li>Dial: Sunburst dial</li><li>Date: Arabic numbers (day)</li><li>Lumen: Superluminova (Blue)</li><li>Crystal: Sapphire with anti-reflective coating</li><li>Back Case: Screwed, brushed stainless steel with sapphire crystal</li><li>Bracelet (steel): Brushed and polished 316L stainless steel</li><li>Bracelet (Leather): Handmade Italian Calf leather</li><li>Clasp: Folding mechanism for ultimate comfort</li><li>Packaging: Blue box with certificate and manual.</li></ul>';
|
|
||||||
$payment_status_0 = 'Open';
|
|
||||||
$payment_status_1 = 'Paid';
|
|
||||||
$payment_status_101 = 'Pending';
|
|
||||||
$payment_status_102 = 'Failed';
|
|
||||||
$payment_status_103 = 'Expired';
|
|
||||||
$payment_status_999 = 'Cancelled';
|
|
||||||
$payment_method_3 = 'Debit/Credit';
|
|
||||||
$ad_watch_1 = 'Dutch design and Swiss craftsmanship';
|
|
||||||
$ad_watch_2 = 'Timeless timepieces that will last for generations!';
|
|
||||||
$ad_watch_btn = 'read more';
|
|
||||||
$newsletter_h2 = 'Sign up for<br>the newsletter';
|
|
||||||
$newsletter_p = 'Stay connected with our latest updates, tips, and exclusive offers—straight to your inbox.';
|
|
||||||
$newsletter_confirm = 'I have read and agree with the privacy policy';
|
|
||||||
$newsletter_submit = 'submit';
|
|
||||||
$header_manufacturing = 'Swiss quality and Dutch manufacturing';
|
|
||||||
$header_shipping = 'Free shipping on all of our watches';
|
|
||||||
$header_delivery = 'Fast service and delivery';
|
|
||||||
$header_rating = 'Client rate 4.7/5.0';
|
|
||||||
?>
|
|
||||||
213
placeorder.php
@@ -1,38 +1,205 @@
|
|||||||
<?php
|
<?php
|
||||||
// Prevent direct access to file
|
// Prevent direct access to file
|
||||||
defined(security_key) or exit;
|
defined(security_key) or exit;
|
||||||
// Remove all the products in cart, the variable is no longer needed as the order has been processed
|
|
||||||
if (isset($_SESSION['cart'])) {
|
// Get order ID and payment status
|
||||||
unset($_SESSION['cart']);
|
$order_id = $_SESSION['pending_order_id'] ?? $_GET['order_id'] ?? null;
|
||||||
}
|
$payment_status = $_GET['payment'] ?? 'processing';
|
||||||
// Remove discount code
|
|
||||||
if (isset($_SESSION['discount'])) {
|
$view = template_header(($place_order_header ?? 'Order Status'),'');
|
||||||
unset($_SESSION['discount']);
|
|
||||||
|
// Check payment status if we have an order ID
|
||||||
|
// Only check API if payment status is not already set to 'failed' from retry timeout
|
||||||
|
if ($order_id && $payment_status !== 'failed') {
|
||||||
|
$transaction_data = ioAPIv2('/v2/transactions/txn_id='.$order_id,'',$clientsecret);
|
||||||
|
$transaction = json_decode($transaction_data, true);
|
||||||
|
|
||||||
|
if ($transaction && isset($transaction[0])) {
|
||||||
|
$payment_status_code = $transaction[0]['payment_status'] ?? 0;
|
||||||
|
|
||||||
|
// Map payment status codes: 1 = Paid, 101 = Pending, 102 = Failed, 103 = Expired, 999 = Cancelled
|
||||||
|
if ($payment_status_code == 1) {
|
||||||
|
$payment_status = 'success';
|
||||||
|
} elseif ($payment_status_code == 101) {
|
||||||
|
$payment_status = 'pending';
|
||||||
|
} elseif (in_array($payment_status_code, [102, 103, 999])) {
|
||||||
|
$payment_status = 'failed';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$view = template_header(($place_order_header ?? 'Place order'),'');
|
// Display appropriate message based on payment status
|
||||||
|
if ($payment_status === 'success') {
|
||||||
|
// Payment successful - clear cart and show success
|
||||||
|
if (isset($_SESSION['cart'])) {
|
||||||
|
unset($_SESSION['cart']);
|
||||||
|
}
|
||||||
|
if (isset($_SESSION['discount'])) {
|
||||||
|
unset($_SESSION['discount']);
|
||||||
|
}
|
||||||
|
if (isset($_SESSION['pending_order_id'])) {
|
||||||
|
unset($_SESSION['pending_order_id']);
|
||||||
|
}
|
||||||
|
|
||||||
if ($error){
|
|
||||||
$view .= '
|
$view .= '
|
||||||
<p class="content-wrapper error">'.$error.'</p>';
|
<div class="status-container">
|
||||||
}
|
<div class="status-card success">
|
||||||
else{
|
<div class="status-icon success-icon">
|
||||||
$view .= '
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="80" height="80">
|
||||||
<div class="order-confirmation">
|
<circle cx="12" cy="12" r="11" fill="#10b981" stroke="" stroke-width="2"/>
|
||||||
<div class="order-confirmation__container">
|
<path d="M7 12l3.5 3.5L17 8" stroke="white" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<div class="order-confirmation__icon">
|
</svg>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="48" height="48" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
</div>
|
||||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
<h1 class="status-title success-title">'.($payment_success_title ?? 'Payment Successful!').'</h1>
|
||||||
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
<p class="status-message">'.($payment_success_message ?? 'Your order has been confirmed and an email confirmation has been sent to your email address.').'</p>
|
||||||
</svg>
|
'.($order_id ? '<div class="order-number">'.($order_number_label ?? 'Order number').': <strong>#'.$order_id.'</strong></div>' : '').'
|
||||||
|
<div class="status-actions">
|
||||||
|
<a href="'.url('index.php').'" class="btn btn-primary">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M7.5 15L2.5 10L7.5 5M3 10H17.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
'.($continue_shopping_btn ?? 'Continue Shopping').'
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
} elseif ($payment_status === 'pending') {
|
||||||
|
// Payment pending
|
||||||
|
$view .= '
|
||||||
|
<div class="status-container">
|
||||||
|
<div class="status-card pending">
|
||||||
|
<div class="status-icon pending-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="80" height="80">
|
||||||
|
<circle cx="12" cy="12" r="11" fill="#f59e0b" stroke="" stroke-width="2"/>
|
||||||
|
<circle cx="12" cy="12" r="3" fill="white"/>
|
||||||
|
<path d="M12 6v6l4 2" stroke="white" stroke-width="2.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h1 class="status-title pending-title">'.($payment_pending_title ?? 'Payment Pending').'</h1>
|
||||||
|
<p class="status-message">'.($payment_pending_message ?? 'Your order has been received and is awaiting payment confirmation. You will receive an email once the payment is confirmed.').'</p>
|
||||||
|
'.($order_id ? '<div class="order-number">'.($order_number_label ?? 'Order number').': <strong>#'.$order_id.'</strong></div>' : '').'
|
||||||
|
<div class="status-actions">
|
||||||
|
<a href="'.url('index.php').'" class="btn btn-primary">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M7.5 15L2.5 10L7.5 5M3 10H17.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
'.($continue_shopping_btn ?? 'Continue Shopping').'
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="order-confirmation__title">'.$h1_order_succes_message.'</h1>
|
|
||||||
<p class="order-confirmation__message">'.$order_succes_message.'</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
let checkInterval;
|
||||||
|
let checkCount = 0;
|
||||||
|
const maxChecks = 5;
|
||||||
|
|
||||||
|
function checkPaymentStatus() {
|
||||||
|
if (checkCount >= maxChecks) {
|
||||||
|
clearInterval(checkInterval);
|
||||||
|
window.location.href = "'.url('placeorder/'.$order_id).'?payment=failed";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCount++;
|
||||||
|
|
||||||
|
fetch("'.base_url.'api_check_payment_status.php?order_id='.$order_id.'")
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status !== "pending") {
|
||||||
|
clearInterval(checkInterval);
|
||||||
|
window.location.href = "'.url('placeorder/'.$order_id).'?payment=" + data.status;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("Error checking payment status:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check immediately, then every 3 seconds
|
||||||
|
checkPaymentStatus();
|
||||||
|
checkInterval = setInterval(checkPaymentStatus, 3000);
|
||||||
|
</script>';
|
||||||
|
|
||||||
|
} elseif ($payment_status === 'processing') {
|
||||||
|
// Payment is being processed
|
||||||
|
$view .= '
|
||||||
|
<div class="status-container">
|
||||||
|
<div class="status-card processing">
|
||||||
|
<div class="status-icon processing-icon">
|
||||||
|
<svg class="spinner" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="80" height="80">
|
||||||
|
<circle cx="12" cy="12" r="10" stroke="#3b82f6" stroke-width="4" fill="none" stroke-dasharray="60" stroke-linecap="round">
|
||||||
|
<animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite"/>
|
||||||
|
</circle>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h1 class="status-title processing-title">'.($payment_processing_title ?? 'Processing Payment...').'</h1>
|
||||||
|
<p class="status-message">'.($payment_processing_message ?? 'Please wait while we confirm your payment. This may take a few moments.').'</p>
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress-fill"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
';
|
<script>
|
||||||
|
let checkInterval;
|
||||||
|
let checkCount = 0;
|
||||||
|
const maxChecks = 5;
|
||||||
|
|
||||||
|
function checkPaymentStatus() {
|
||||||
|
if (checkCount >= maxChecks) {
|
||||||
|
clearInterval(checkInterval);
|
||||||
|
window.location.href = "'.url('placeorder/'.$order_id).'?payment=failed";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCount++;
|
||||||
|
|
||||||
|
fetch("'.base_url.'api_check_payment_status.php?order_id='.$order_id.'")
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status !== "processing") {
|
||||||
|
clearInterval(checkInterval);
|
||||||
|
window.location.href = "'.url('placeorder/'.$order_id).'?payment=" + data.status;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("Error checking payment status:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check immediately, then every 3 seconds
|
||||||
|
checkPaymentStatus();
|
||||||
|
checkInterval = setInterval(checkPaymentStatus, 3000);
|
||||||
|
</script>';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Payment failed
|
||||||
|
$view .= '
|
||||||
|
<div class="status-container">
|
||||||
|
<div class="status-card failed">
|
||||||
|
<div class="status-icon failed-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="80" height="80">
|
||||||
|
<circle cx="12" cy="12" r="11" fill="#ef4444" stroke="" stroke-width="2"/>
|
||||||
|
<path d="M8 8l8 8M16 8l-8 8" stroke="white" stroke-width="3" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h1 class="status-title failed-title">'.($payment_failed_title ?? 'Payment Not Successful').'</h1>
|
||||||
|
<p class="status-message">'.($payment_failed_message ?? 'Unfortunately, your payment could not be processed. Please try again or choose a different payment method.').'</p>
|
||||||
|
'.($order_id ? '<div class="order-number">'.($order_number_label ?? 'Order reference').': <strong>#'.$order_id.'</strong></div>' : '').'
|
||||||
|
<div class="status-actions">
|
||||||
|
<a href="'.url('index.php?page=checkout').'" class="btn btn-primary">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||||
|
<path d="M7.5 15L2.5 10L7.5 5M3 10H17.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
'.($return_to_checkout_btn ?? 'Return to Checkout').'
|
||||||
|
</a>
|
||||||
|
<a href="'.url('index.php?page=cart').'" class="btn btn-secondary">'.($view_cart_btn ?? 'View Cart').'</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$view .= template_footer();
|
$view .= template_footer();
|
||||||
|
|
||||||
echo $view;
|
echo $view;
|
||||||
|
?>
|
||||||
442
product.php
@@ -5,10 +5,17 @@ defined(security_key) or exit;
|
|||||||
// Check to make sure the id parameter is specified in the URL
|
// Check to make sure the id parameter is specified in the URL
|
||||||
if (isset($_GET['id'])) {
|
if (isset($_GET['id'])) {
|
||||||
|
|
||||||
//GET CATALOG DATA
|
//GET CATALOG DATA FROM CACHE
|
||||||
$product = ioAPIv2('/v2/catalog/product_id='.$_GET['id'],'',$clientsecret);
|
$all_products = $GLOBALS['cached_catalog'];
|
||||||
$product = json_decode($product,true);
|
|
||||||
$product = $product[0] ?? '';
|
// Find the specific product by ID or slug
|
||||||
|
$product = null;
|
||||||
|
foreach ($all_products as $prod) {
|
||||||
|
if ($prod['rowID'] == $_GET['id'] || (isset($prod['url_slug']) && $prod['url_slug'] == $_GET['id'])) {
|
||||||
|
$product = $prod;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the product exists (array is not empty)
|
// Check if the product exists (array is not empty)
|
||||||
if (!$product) {
|
if (!$product) {
|
||||||
@@ -89,42 +96,76 @@ $view .='<p class="content-wrapper error">'.$error.'</p>';
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$view .='
|
$view .='
|
||||||
<div class="product content-wrapper">
|
<div class="product content-wrapper">
|
||||||
<div class="product-imgs">';
|
<div class="product-mobile-header">
|
||||||
if (isset($_GET['option_id']) && !empty($_GET['option_id']) && $_GET['option_id'] !=''){
|
<div class="breadcrum">
|
||||||
|
<a href="'.$products_link.'">'.$breadcrum_products.'</a> <p>/ '.(${$product['productname']} ?? $product['productname']).'</p>
|
||||||
|
</div>
|
||||||
|
<h1 class="name">'.(${$product['productname']} ?? $product['productname']).'</h1>
|
||||||
|
</div>
|
||||||
|
<div class="product-imgs carousel-container">';
|
||||||
|
// Determine the main image source
|
||||||
|
$mainImageSrc = '';
|
||||||
|
$mainImageAlt = '';
|
||||||
|
|
||||||
$fullPath = null;
|
if (isset($_GET['option_id']) && !empty($_GET['option_id']) && $_GET['option_id'] !=''){
|
||||||
foreach ($product['configurations'] as $configuration) {
|
foreach ($product['configurations'] as $configuration) {
|
||||||
if (isset($configuration['attributes'])) {
|
if (isset($configuration['attributes'])) {
|
||||||
foreach ($configuration['attributes'] as $attribute) {
|
foreach ($configuration['attributes'] as $attribute) {
|
||||||
if ($attribute['attribute_id'] == $_GET['option_id']) {
|
if ($attribute['attribute_id'] == $_GET['option_id']) {
|
||||||
$fullPath = $attribute['alternative_media_full_path'] ?? $attribute['full_path'];
|
$mainImageSrc = img_url . ($attribute['alternative_media_full_path'] ?? $attribute['full_path']);
|
||||||
$altTitle = $attribute['alternative_media_title'] ?? $attribute['title'];
|
$mainImageAlt = $attribute['alternative_media_title'] ?? $attribute['title'];
|
||||||
$view .='
|
break 2;
|
||||||
<div class="product-img-large">
|
|
||||||
<img src="'.img_url.$fullPath.'" id="'.$product['rowID'].'" alt="'.$altTitle.'">
|
|
||||||
</div>';
|
|
||||||
break 2; // Exit all loops once found
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} elseif (isset($product['full_path']) && $product['full_path'] != ''){
|
// Fallback to product main image if no option_id or not found
|
||||||
|
if (empty($mainImageSrc) && isset($product['full_path']) && $product['full_path'] != '') {
|
||||||
|
$mainImageSrc = img_url . $product['full_path'];
|
||||||
|
$mainImageAlt = ${$product['productname']} ?? $product['productname'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render carousel with arrows if we have an image
|
||||||
|
if (!empty($mainImageSrc)) {
|
||||||
$view .='
|
$view .='
|
||||||
<div class="product-img-large">
|
<div class="product-img-large carousel-main">
|
||||||
<img src="'.img_url.$product['full_path'].'" id="'.$product['rowID'].'" alt="'.(${$product['productname']} ?? $product['productname']).'">
|
<button class="carousel-arrow left" aria-label="Previous image">←</button>
|
||||||
|
<img src="'.$mainImageSrc.'" id="'.$product['rowID'].'" alt="'.$mainImageAlt.'">
|
||||||
|
<button class="carousel-arrow right" aria-label="Next image">→</button>
|
||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
$view .='
|
$view .='
|
||||||
<div class="product-small-imgs">';
|
<div class="product-small-imgs carousel-thumbnails">';
|
||||||
//Show small images
|
// Add the main product image as the first thumbnail
|
||||||
foreach ($product_media as $media){
|
$thumbs = [];
|
||||||
|
if (isset($_GET['option_id']) && !empty($_GET['option_id']) && $_GET['option_id'] !=''){
|
||||||
$view .=' <div class="product-img-small '.($media['position']==1?' selected':'').'">
|
foreach ($product['configurations'] as $configuration) {
|
||||||
<img src="'.img_url.$media['full_path'].'" width="150" height="150" alt="">
|
if (isset($configuration['attributes'])) {
|
||||||
</div>';
|
foreach ($configuration['attributes'] as $attribute) {
|
||||||
|
if ($attribute['attribute_id'] == $_GET['option_id']) {
|
||||||
|
$mainPath = $attribute['alternative_media_full_path'] ?? $attribute['full_path'];
|
||||||
|
$mainAltTitle = $attribute['alternative_media_title'] ?? $attribute['title'];
|
||||||
|
$thumbs[] = ['src' => img_url.$mainPath, 'alt' => $mainAltTitle, 'selected' => true];
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} elseif (isset($product['full_path']) && $product['full_path'] != ''){
|
||||||
|
$thumbs[] = ['src' => img_url.$product['full_path'], 'alt' => (${$product['productname']} ?? $product['productname']), 'selected' => true];
|
||||||
|
}
|
||||||
|
foreach ($product_media as $media){
|
||||||
|
$thumbs[] = ['src' => img_url.$media['full_path'], 'alt' => '', 'selected' => false];
|
||||||
|
}
|
||||||
|
foreach ($thumbs as $i => $thumb) {
|
||||||
|
$sel = $thumb['selected'] ? ' selected' : '';
|
||||||
|
$view .= ' <div class="product-img-small'.$sel.'" data-index="'.$i.'">
|
||||||
|
<img src="'.$thumb['src'].'" width="80" height="80" alt="'.$thumb['alt'].'">
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
$view .='
|
$view .='
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -178,6 +219,8 @@ $view .='<form id="product-form" action="" method="post">';
|
|||||||
$output ='';
|
$output ='';
|
||||||
|
|
||||||
foreach ($configuration['attributes'] as $attribute){
|
foreach ($configuration['attributes'] as $attribute){
|
||||||
|
// Check if this option should be pre-selected
|
||||||
|
$isChecked = (isset($_GET['option_id']) && $_GET['option_id'] == $attribute['attribute_id']) ? ' checked' : '';
|
||||||
|
|
||||||
if(isset($attribute['full_path']) && $attribute['full_path'] !=''){
|
if(isset($attribute['full_path']) && $attribute['full_path'] !=''){
|
||||||
|
|
||||||
@@ -193,14 +236,14 @@ $view .='<form id="product-form" action="" method="post">';
|
|||||||
|
|
||||||
$output .= '
|
$output .= '
|
||||||
<label class="picture_select_label">
|
<label class="picture_select_label">
|
||||||
<input id="'.$attribute['attribute_id'].'" class="option radio" value="'.$attribute['attribute_id'].'" name="product[option]['.$configuration['assignment'].'][]" type="radio" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').'>
|
<input id="'.$attribute['attribute_id'].'" class="option radio" value="'.$attribute['attribute_id'].'" name="product[option]['.$configuration['assignment'].'][]" type="radio" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').$isChecked.'>
|
||||||
<span class="picture_select"><img '.$onclick.' src="'.$IMG_small_id.'"></span>
|
<span class="picture_select"><img '.$onclick.' src="'.$IMG_small_id.'"></span>
|
||||||
</label>';
|
</label>';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$output .= '
|
$output .= '
|
||||||
<label>
|
<label>
|
||||||
<input id="'.$attribute['attribute_id'].'>" class="option radio" value="'.$attribute['attribute_id'].'" name="product[option]['.$configuration['assignment'].'][]" type="radio" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').'>'.(${$attribute['item_name']} ?? $attribute['item_name']).'
|
<input id="'.$attribute['attribute_id'].'>" class="option radio" value="'.$attribute['attribute_id'].'" name="product[option]['.$configuration['assignment'].'][]" type="radio" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').$isChecked.'>'.(${$attribute['item_name']} ?? $attribute['item_name']).'
|
||||||
</label>';
|
</label>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +256,8 @@ $view .='<form id="product-form" action="" method="post">';
|
|||||||
$output ='';
|
$output ='';
|
||||||
|
|
||||||
foreach ($configuration['attributes'] as $attribute){
|
foreach ($configuration['attributes'] as $attribute){
|
||||||
|
// Check if this option should be pre-selected
|
||||||
|
$isChecked = (isset($_GET['option_id']) && $_GET['option_id'] == $attribute['attribute_id']) ? ' checked' : '';
|
||||||
|
|
||||||
if(isset($attribute['full_path']) && $attribute['full_path'] !=''){
|
if(isset($attribute['full_path']) && $attribute['full_path'] !=''){
|
||||||
|
|
||||||
@@ -228,14 +273,14 @@ $view .='<form id="product-form" action="" method="post">';
|
|||||||
|
|
||||||
$output .= '
|
$output .= '
|
||||||
<label class="picture_select_label">
|
<label class="picture_select_label">
|
||||||
<input id="'.$attribute['attribute_id'].'>" class="option checkbox" value="'.$attribute['attribute_id'].'" name="product[option]['.$configuration['assignment'].'][]" type="checkbox" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').'>
|
<input id="'.$attribute['attribute_id'].'>" class="option checkbox" value="'.$attribute['attribute_id'].'" name="product[option]['.$configuration['assignment'].'][]" type="checkbox" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').$isChecked.'>
|
||||||
<span class="picture_select"><img '.$onclick.' src="'.$IMG_small_id.'"></span>
|
<span class="picture_select"><img '.$onclick.' src="'.$IMG_small_id.'"></span>
|
||||||
</label>';
|
</label>';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$output .= '
|
$output .= '
|
||||||
<label>
|
<label>
|
||||||
<input id="'.$attribute['attribute_id'].'>" class="option checkbox" value="'.$attribute['attribute_id'].'" name="product[option]['.$configuration['assignment'].'][]" type="checkbox" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').'>'.(${$attribute['item_name']} ?? $attribute['item_name']).'
|
<input id="'.$attribute['attribute_id'].'>" class="option checkbox" value="'.$attribute['attribute_id'].'" name="product[option]['.$configuration['assignment'].'][]" type="checkbox" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').$isChecked.'>'.(${$attribute['item_name']} ?? $attribute['item_name']).'
|
||||||
</label>';
|
</label>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,12 +291,17 @@ $view .='<form id="product-form" action="" method="post">';
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: //Dropdown
|
case 2: //Dropdown
|
||||||
|
// Check if any option is pre-selected via URL
|
||||||
|
$hasPreselection = isset($_GET['option_id']) && !empty($_GET['option_id']);
|
||||||
|
|
||||||
$output ='
|
$output ='
|
||||||
<select id="'.$configuration['assignment'].'" class="option select" name="product[option]['.$configuration['assignment'].']" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').'>
|
<select id="'.$configuration['assignment'].'" class="option select" name="product[option]['.$configuration['assignment'].']" '.(($configuration['group_mandatory'] == 1 ) ? ' required' : '').'>
|
||||||
<option value="" selected disabled style="display:none">'.$configuration['assignment_name'].'</option>
|
<option value=""'.($hasPreselection ? '' : ' selected').' disabled style="display:none">'.$configuration['assignment_name'].'</option>
|
||||||
';
|
';
|
||||||
|
|
||||||
foreach ($configuration['attributes'] as $attribute){
|
foreach ($configuration['attributes'] as $attribute){
|
||||||
|
// Check if this option should be pre-selected
|
||||||
|
$isSelected = (isset($_GET['option_id']) && $_GET['option_id'] == $attribute['attribute_id']) ? ' selected' : '';
|
||||||
|
|
||||||
if(isset($attribute['full_path']) && $attribute['full_path'] !=''){
|
if(isset($attribute['full_path']) && $attribute['full_path'] !=''){
|
||||||
|
|
||||||
@@ -266,12 +316,12 @@ $view .='<form id="product-form" action="" method="post">';
|
|||||||
$IMG_small_id = img_url.$attribute['full_path']; //URL TO SMALL IMAGE
|
$IMG_small_id = img_url.$attribute['full_path']; //URL TO SMALL IMAGE
|
||||||
|
|
||||||
$output .= '
|
$output .= '
|
||||||
<option id="'.$attribute['attribute_id'].'" value="'.$attribute['attribute_id'].'" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'">'.(${$attribute['item_name']} ?? $attribute['item_name']).'</option>';
|
<option id="'.$attribute['attribute_id'].'" value="'.$attribute['attribute_id'].'" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'"'.$isSelected.'>'.(${$attribute['item_name']} ?? $attribute['item_name']).'</option>';
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$output .= '
|
$output .= '
|
||||||
<option id="'.$attribute['attribute_id'].'" value="'.$attribute['attribute_id'].'" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'">'.(${$attribute['item_name']} ?? $attribute['item_name']).'</option>';
|
<option id="'.$attribute['attribute_id'].'" value="'.$attribute['attribute_id'].'" data-price="'.($attribute['price'] ?? 0).'" data-rrp="'.($attribute['rrp'] ?? 0).'" data-modifier="'.($attribute['price_modifier'] ?? 1).'"'.$isSelected.'>'.(${$attribute['item_name']} ?? $attribute['item_name']).'</option>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -290,16 +340,325 @@ $view .='
|
|||||||
<input id="product" type="hidden" name="product[product]" value="'.$product['rowID'].'">
|
<input id="product" type="hidden" name="product[product]" value="'.$product['rowID'].'">
|
||||||
<input id="product" type="hidden" name="product[version]" value="'.($product['version_id'] ?? '').'">
|
<input id="product" type="hidden" name="product[version]" value="'.($product['version_id'] ?? '').'">
|
||||||
|
|
||||||
<input type="submit" value="'.$add_to_basket.'" class="btn">
|
<input type="submit" value="'.$add_to_basket.'" class="btn add-to-basket-sticky">
|
||||||
</form>
|
</form>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
'.(${$product['productdescription']} ?? $product['productdescription']).'
|
'.(${$product['productdescription']} ?? $product['productdescription']).'
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>';
|
</div>';
|
||||||
|
|
||||||
|
$view .= '<style>
|
||||||
|
/* Mobile Header - Hidden on desktop */
|
||||||
|
.product-mobile-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carousel Container */
|
||||||
|
.carousel-container {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Image Area */
|
||||||
|
.carousel-main {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1rem;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-main img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 450px;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Carousel Arrows */
|
||||||
|
.carousel-arrow {
|
||||||
|
background: rgba(255, 255, 255, 0);
|
||||||
|
border: none;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
z-index: 10;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
color: #1a3a5f;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-arrow:hover {
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||||
|
transform: translateY(-50%) scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-arrow.left { left: 10px; }
|
||||||
|
.carousel-arrow.right { right: 10px; }
|
||||||
|
|
||||||
|
/* Thumbnails Container */
|
||||||
|
.carousel-thumbnails {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 10px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 10px 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #ccc transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-thumbnails::-webkit-scrollbar {
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-thumbnails::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-thumbnails::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #ccc;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Thumbnail Items */
|
||||||
|
.product-img-small {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-img-small:hover {
|
||||||
|
border-color: #1a3a5f;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-img-small.selected {
|
||||||
|
border-color: #1a3a5f;
|
||||||
|
opacity: 1;
|
||||||
|
box-shadow: 0 2px 8px rgba(26, 58, 95, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-img-small img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sticky Add to Basket Button */
|
||||||
|
.add-to-basket-sticky {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-to-basket-sticky.is-sticky {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1000;
|
||||||
|
border-radius: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tablet/Mobile Responsive Styles (< 993px) */
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
/* Hide info bar on tablet/mobile */
|
||||||
|
.top-info-bar,
|
||||||
|
.info-bar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show mobile header on tablet/mobile */
|
||||||
|
.product-mobile-header {
|
||||||
|
display: block;
|
||||||
|
order: 0;
|
||||||
|
padding: 1rem;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-mobile-header .breadcrum {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-mobile-header .name {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide original breadcrumb and name on tablet/mobile */
|
||||||
|
.product-wrapper > .breadcrum,
|
||||||
|
.product-wrapper > .name {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reorder product page layout */
|
||||||
|
.product.content-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
gap: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Full width carousel */
|
||||||
|
.carousel-container,
|
||||||
|
.product-imgs {
|
||||||
|
order: 1;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-main {
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-height: auto;
|
||||||
|
max-height: 60vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-main img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 60vh;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-arrow {
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-arrow.left { left: 5px; }
|
||||||
|
.carousel-arrow.right { right: 5px; }
|
||||||
|
|
||||||
|
/* Thumbnails */
|
||||||
|
.carousel-thumbnails {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-img-small {
|
||||||
|
width: 55px;
|
||||||
|
height: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Product wrapper */
|
||||||
|
.product-wrapper {
|
||||||
|
order: 2;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Breadcrumb - smaller on tablet/mobile */
|
||||||
|
.breadcrum {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Always sticky add to basket on tablet/mobile */
|
||||||
|
.add-to-basket-sticky {
|
||||||
|
position: fixed !important;
|
||||||
|
left: 0 !important;
|
||||||
|
right: 0 !important;
|
||||||
|
bottom: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
z-index: 1000 !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 1rem !important;
|
||||||
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.15) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add padding at bottom for sticky button */
|
||||||
|
.product.content-wrapper {
|
||||||
|
padding-bottom: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prices/stock spacing */
|
||||||
|
.product-wrapper .prices,
|
||||||
|
.product-wrapper .stock {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extra small screens */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.carousel-main img {
|
||||||
|
max-height: 50vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-img-small {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-arrow {
|
||||||
|
padding: 0.4rem 0.6rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>';
|
||||||
|
}
|
||||||
|
|
||||||
$view .= '
|
$view .= '
|
||||||
<script>
|
<script>
|
||||||
|
// Push viewContent event to dataLayer
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
window.dataLayer.push({
|
||||||
|
"event": "viewContent",
|
||||||
|
"ecommerce": {
|
||||||
|
"detail": {
|
||||||
|
"products": [{
|
||||||
|
"id": "' . $product['rowID'] . '",
|
||||||
|
"name": "' . addslashes(${$product['productname']} ?? $product['productname']) . '",
|
||||||
|
"price": "' . $product['price'] . '",
|
||||||
|
"category": "' . ($product['category_name'] ?? '') . '"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content_type": "product",
|
||||||
|
"content_ids": ["' . $product['rowID'] . '"],
|
||||||
|
"content_name": "' . addslashes(${$product['productname']} ?? $product['productname']) . '",
|
||||||
|
"value": "' . $product['price'] . '",
|
||||||
|
"currency": "EUR"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Pre-select option from URL
|
||||||
|
(function() {
|
||||||
//Read urlstring
|
//Read urlstring
|
||||||
const queryString = window.location.href;
|
const queryString = window.location.href;
|
||||||
const option_id = queryString.substring(queryString.lastIndexOf(\'/\') + 1);
|
const option_id = queryString.substring(queryString.lastIndexOf(\'/\') + 1);
|
||||||
@@ -308,20 +667,21 @@ $view .= '
|
|||||||
|
|
||||||
//Check for option_id
|
//Check for option_id
|
||||||
if (option_id != url_slug){
|
if (option_id != url_slug){
|
||||||
document.getElementById(option_id).checked = true;
|
const optionElement = document.getElementById(option_id);
|
||||||
|
if (optionElement) {
|
||||||
|
optionElement.checked = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Get all radio buttons
|
// Get all radio buttons
|
||||||
const radioButtons = document.querySelectorAll(\'.picture_select_label input[type="radio"]\');
|
const radioButtons = document.querySelectorAll(\'.picture_select_label input[type="radio"]\');
|
||||||
|
|
||||||
// Select the first radio button if any exist
|
// Select the first radio button if any exist
|
||||||
if (radioButtons.length > 0) {
|
if (radioButtons.length > 0) {
|
||||||
radioButtons[0].checked = true;
|
radioButtons[0].checked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
</script>';
|
</script>';
|
||||||
}
|
|
||||||
|
|
||||||
$view .= template_footer();
|
$view .= template_footer();
|
||||||
|
|
||||||
|
|||||||
188
products.php
@@ -9,37 +9,66 @@ $num_products_on_each_page = 25;
|
|||||||
//GET Details from URL
|
//GET Details from URL
|
||||||
$GET_VALUES = urlGETdetails($_GET) ?? '';
|
$GET_VALUES = urlGETdetails($_GET) ?? '';
|
||||||
|
|
||||||
//Get all the categories from the database
|
//Get all the categories from cached data
|
||||||
$categories = ioAPIv2('/v2/categories/','',$clientsecret);
|
$categories = $GLOBALS['cached_categories'];
|
||||||
$categories = json_decode($categories,true);
|
|
||||||
|
|
||||||
//IF CATEGORY IS RECEIVED ONLY GET RELATED PRODUCTS
|
// Deduplicate categories by rowID (since categories repeat for each product)
|
||||||
$url_input = '';
|
$unique_categories = [];
|
||||||
if(isset($_GET['category']) && !isset($_POST['category'])){
|
foreach ($categories as $cat) {
|
||||||
$url_input = 'category='.$_GET['category'];
|
$unique_categories[$cat['rowID']] = $cat;
|
||||||
}
|
}
|
||||||
|
$categories = array_values($unique_categories);
|
||||||
|
|
||||||
if (isset($_POST['category'])){
|
//Get all products from cached data
|
||||||
|
$products = $GLOBALS['cached_catalog'];
|
||||||
|
|
||||||
$filter_input = '';
|
// Build product-to-categories mapping for filtering
|
||||||
|
$product_categories_map = [];
|
||||||
foreach (array_keys($_POST['category']) as $cat_filter){
|
foreach ($GLOBALS['cached_categories'] as $cat) {
|
||||||
$filter_input .= $cat_filter.',';
|
if (isset($cat['product_id'])) {
|
||||||
}
|
$product_id = $cat['product_id'];
|
||||||
|
if (!isset($product_categories_map[$product_id])) {
|
||||||
if ($url_input != ''){
|
$product_categories_map[$product_id] = [];
|
||||||
$url_input = $url_input.','.substr($filter_input,0, -1);
|
}
|
||||||
|
// Only add categories that have status=1 and filter=1
|
||||||
} else {
|
if (isset($cat['status']) && $cat['status'] == 1) {
|
||||||
$url_input = 'category='.substr($filter_input,0, -1);
|
$product_categories_map[$product_id][] = $cat['rowID'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//GET CATALOG DATA
|
// Add categories array to each product for JavaScript filtering
|
||||||
$products = ioAPIv2('/v2/catalog/'.$url_input,'',$clientsecret);
|
foreach ($products as &$product) {
|
||||||
$products = json_decode($products,true);
|
$product_id = $product['rowID'];
|
||||||
|
$product['category_ids'] = isset($product_categories_map[$product_id])
|
||||||
|
? array_unique($product_categories_map[$product_id])
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
unset($product);
|
||||||
|
|
||||||
$total_products = count($products);
|
$total_products = count($products);
|
||||||
|
|
||||||
|
// Get URL category filter if present
|
||||||
|
$url_category_filter = isset($_GET['category']) ? explode(',', $_GET['category']) : [];
|
||||||
|
|
||||||
|
// Expand parent categories to include all their children
|
||||||
|
$expanded_filters = [];
|
||||||
|
foreach ($url_category_filter as $cat_id) {
|
||||||
|
$expanded_filters[] = $cat_id;
|
||||||
|
// Find all children of this category
|
||||||
|
foreach ($unique_categories as $cat) {
|
||||||
|
if ($cat['parent_id'] == $cat_id && $cat['status'] == 1 && $cat['filter'] == 1) {
|
||||||
|
$expanded_filters[] = $cat['rowID'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$url_category_filter = array_unique($expanded_filters);
|
||||||
|
|
||||||
|
// Debug: log what category was received
|
||||||
|
if (debug && !empty($url_category_filter)) {
|
||||||
|
debuglog('URL category filter (expanded): ' . implode(',', $url_category_filter));
|
||||||
|
}
|
||||||
|
|
||||||
//SORT BY NAME
|
//SORT BY NAME
|
||||||
usort($products, function($a, $b) {
|
usort($products, function($a, $b) {
|
||||||
return strcmp($a['productname'], $b['productname']);
|
return strcmp($a['productname'], $b['productname']);
|
||||||
@@ -50,7 +79,7 @@ $view = template_header($products_text,'');
|
|||||||
|
|
||||||
$view .= '
|
$view .= '
|
||||||
<!-- Hero Section -->
|
<!-- Hero Section -->
|
||||||
<section class="hero" style="background-image:url('.base_url.featured_store_image.');">
|
<section class="hero hero-products" style="background-image:url('.base_url.featured_store_image.');">
|
||||||
<div class="hero-content">
|
<div class="hero-content">
|
||||||
<h1>'.$h1_content_top.'</h1>
|
<h1>'.$h1_content_top.'</h1>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +93,7 @@ $view .= '
|
|||||||
<div class="filters-products-container">
|
<div class="filters-products-container">
|
||||||
|
|
||||||
<div class="filters" id="filters">
|
<div class="filters" id="filters">
|
||||||
<form action="" method="post">';
|
<div class="filter-container">';
|
||||||
|
|
||||||
if (count($categories) > 0){
|
if (count($categories) > 0){
|
||||||
//BUILD UP FILTERS BASED ON CATEGORY ASSIGNMENTS
|
//BUILD UP FILTERS BASED ON CATEGORY ASSIGNMENTS
|
||||||
@@ -77,10 +106,11 @@ $view .= '
|
|||||||
//Iterate through categories for subfilters
|
//Iterate through categories for subfilters
|
||||||
foreach ($categories as $subfilter){
|
foreach ($categories as $subfilter){
|
||||||
if ($filters['rowID'] == $subfilter['parent_id'] && $subfilter['status'] == 1 && $subfilter['filter'] == 1){
|
if ($filters['rowID'] == $subfilter['parent_id'] && $subfilter['status'] == 1 && $subfilter['filter'] == 1){
|
||||||
|
$checked = in_array($subfilter['rowID'], $url_category_filter) ? 'checked' : '';
|
||||||
$view .= '
|
$view .= '
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<input type="checkbox" id="'.$subfilter['name'].'" name="category['.$subfilter['rowID'].']">
|
<input type="checkbox" class="filter-checkbox" id="cat_'.$subfilter['rowID'].'" data-category="'.$subfilter['rowID'].'" '.$checked.'>
|
||||||
<label for="'.$subfilter['name'].'">'.(${$subfilter['name']} ?? $subfilter['name']).'</label>
|
<label for="cat_'.$subfilter['rowID'].'">'.(${$subfilter['name']} ?? $subfilter['name']).'</label>
|
||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,10 +120,10 @@ $view .= '
|
|||||||
}
|
}
|
||||||
$view .= '
|
$view .= '
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<input type="submit" value="'.($btn_filter ?? 'Filter').'" class="btn" >
|
<button type="button" id="clearFilters" class="btn" style="display:none;">'.($btn_clear_filters ?? 'Clear Filters').'</button>
|
||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
$view .= '</form>
|
$view .= '</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="products">
|
<div class="products">
|
||||||
<div class="product-grid">';
|
<div class="product-grid">';
|
||||||
@@ -105,7 +135,7 @@ $view .= '</form>
|
|||||||
|
|
||||||
|
|
||||||
$view .= '
|
$view .= '
|
||||||
<div class="product-card">
|
<div class="product-card" data-categories="'.implode(',', $product['category_ids']).'" data-product-id="'.$product['rowID'].'">
|
||||||
<a href="'.url('index.php?page=product&rowID=' . ($product['url_slug'] ? ($product['url_slug'] ) : $product['rowID'])).(!empty($product['main_option_for_display']) ? '/'.$product['main_option_for_display']:'').'" id="'.$product['rowID'].'A" class="product">
|
<a href="'.url('index.php?page=product&rowID=' . ($product['url_slug'] ? ($product['url_slug'] ) : $product['rowID'])).(!empty($product['main_option_for_display']) ? '/'.$product['main_option_for_display']:'').'" id="'.$product['rowID'].'A" class="product">
|
||||||
<img src="'.img_url.$product['full_path'].'" id="'.$product['rowID'].'" width="" height="250" alt="'.(${$product['productname']} ?? $product['productname']).'">
|
<img src="'.img_url.$product['full_path'].'" id="'.$product['rowID'].'" width="" height="250" alt="'.(${$product['productname']} ?? $product['productname']).'">
|
||||||
</a>';
|
</a>';
|
||||||
@@ -223,7 +253,7 @@ $view .= '
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
// Simple filter toggle for mobile
|
// Filter toggle for mobile
|
||||||
const filterToggle = document.getElementById(\'filterToggle\');
|
const filterToggle = document.getElementById(\'filterToggle\');
|
||||||
const filters = document.getElementById(\'filters\');
|
const filters = document.getElementById(\'filters\');
|
||||||
|
|
||||||
@@ -231,6 +261,104 @@ $view .= '
|
|||||||
filters.classList.toggle(\'show\');
|
filters.classList.toggle(\'show\');
|
||||||
filterToggle.textContent = filters.classList.contains(\'show\') ? \'Hide Filters\' : \'Show Filters\';
|
filterToggle.textContent = filters.classList.contains(\'show\') ? \'Hide Filters\' : \'Show Filters\';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Client-side product filtering
|
||||||
|
const filterCheckboxes = document.querySelectorAll(\'.filter-checkbox\');
|
||||||
|
const productCards = document.querySelectorAll(\'.product-card\');
|
||||||
|
const clearFiltersBtn = document.getElementById(\'clearFilters\');
|
||||||
|
let activeFilters = new Set();
|
||||||
|
|
||||||
|
console.log(\'Filter system initialized\');
|
||||||
|
console.log(\'Total checkboxes:\', filterCheckboxes.length);
|
||||||
|
console.log(\'Total product cards:\', productCards.length);
|
||||||
|
|
||||||
|
// Debug: Log all product categories
|
||||||
|
productCards.forEach((card, idx) => {
|
||||||
|
if (idx < 3) {
|
||||||
|
console.log(\'Product\', idx, \'categories:\', card.getAttribute(\'data-categories\'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Debug: Log all filter categories
|
||||||
|
const filterCategories = [];
|
||||||
|
filterCheckboxes.forEach(checkbox => {
|
||||||
|
filterCategories.push(checkbox.getAttribute(\'data-category\'));
|
||||||
|
});
|
||||||
|
console.log(\'Filter categories:\', filterCategories);
|
||||||
|
|
||||||
|
// Initialize filters from pre-checked checkboxes (from URL params)
|
||||||
|
filterCheckboxes.forEach(checkbox => {
|
||||||
|
if (checkbox.checked) {
|
||||||
|
const category = checkbox.getAttribute(\'data-category\');
|
||||||
|
activeFilters.add(category);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run initial filter if there are pre-selected categories
|
||||||
|
if (activeFilters.size > 0) {
|
||||||
|
filterProducts();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter products based on selected categories
|
||||||
|
function filterProducts() {
|
||||||
|
let visibleCount = 0;
|
||||||
|
|
||||||
|
console.log(\'Active filters:\', Array.from(activeFilters));
|
||||||
|
|
||||||
|
productCards.forEach(card => {
|
||||||
|
const productCategoriesStr = card.getAttribute(\'data-categories\');
|
||||||
|
const productCategories = productCategoriesStr ? productCategoriesStr.split(\',\') : [];
|
||||||
|
|
||||||
|
// If no filters active, show all products
|
||||||
|
if (activeFilters.size === 0) {
|
||||||
|
card.style.display = \'\';
|
||||||
|
visibleCount++;
|
||||||
|
} else {
|
||||||
|
// Show product if ANY of its categories match the active filters
|
||||||
|
const hasMatch = productCategories.some(cat => activeFilters.has(cat));
|
||||||
|
if (hasMatch) {
|
||||||
|
card.style.display = \'\';
|
||||||
|
visibleCount++;
|
||||||
|
} else {
|
||||||
|
card.style.display = \'none\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show/hide clear button
|
||||||
|
if (clearFiltersBtn) {
|
||||||
|
clearFiltersBtn.style.display = activeFilters.size > 0 ? \'inline-block\' : \'none\';
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(\'Showing \' + visibleCount + \' of \' + productCards.length + \' products\');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listeners to checkboxes
|
||||||
|
filterCheckboxes.forEach(checkbox => {
|
||||||
|
checkbox.addEventListener(\'change\', function() {
|
||||||
|
const category = this.getAttribute(\'data-category\');
|
||||||
|
console.log(\'Checkbox changed:\', category, \'checked:\', this.checked);
|
||||||
|
|
||||||
|
if (this.checked) {
|
||||||
|
activeFilters.add(category);
|
||||||
|
} else {
|
||||||
|
activeFilters.delete(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
filterProducts();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clear all filters
|
||||||
|
if (clearFiltersBtn) {
|
||||||
|
clearFiltersBtn.addEventListener(\'click\', () => {
|
||||||
|
filterCheckboxes.forEach(checkbox => {
|
||||||
|
checkbox.checked = false;
|
||||||
|
});
|
||||||
|
activeFilters.clear();
|
||||||
|
filterProducts();
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
';
|
';
|
||||||
|
|
||||||
|
|||||||
263
script.js
@@ -1,17 +1,193 @@
|
|||||||
if (document.querySelector('.product-img-small')) {
|
// Initialize dataLayer for Google Tag Manager
|
||||||
let imgs = document.querySelectorAll('.product-img-small img');
|
window.dataLayer = window.dataLayer || [];
|
||||||
let mainImg = document.querySelector('.product-img-large img');
|
|
||||||
|
|
||||||
imgs.forEach(img => {
|
// Push virtual page view event on page load
|
||||||
img.onclick = () => {
|
window.dataLayer.push({
|
||||||
// Update main image
|
'event': 'virtualPageview',
|
||||||
document.querySelector('.product-img-large img').src = img.src;
|
'pagePath': window.location.pathname + window.location.search,
|
||||||
// Update selection
|
'pageTitle': document.title
|
||||||
imgs.forEach(i => i.parentElement.classList.remove('selected'));
|
});
|
||||||
img.parentElement.classList.add('selected');
|
|
||||||
};
|
// --- Product Carousel Logic ---
|
||||||
|
document.addEventListener('DOMContentLoaded', function initProductCarousel() {
|
||||||
|
const carouselMain = document.querySelector('.carousel-main');
|
||||||
|
if (!carouselMain) return;
|
||||||
|
|
||||||
|
const mainImg = carouselMain.querySelector('img');
|
||||||
|
const thumbs = Array.from(document.querySelectorAll('.carousel-thumbnails .product-img-small'));
|
||||||
|
const leftArrow = document.querySelector('.carousel-arrow.left');
|
||||||
|
const rightArrow = document.querySelector('.carousel-arrow.right');
|
||||||
|
|
||||||
|
if (!mainImg || thumbs.length === 0) return;
|
||||||
|
|
||||||
|
let current = thumbs.findIndex(t => t.classList.contains('selected'));
|
||||||
|
if (current === -1) current = 0;
|
||||||
|
let isAnimating = false;
|
||||||
|
|
||||||
|
function updateCarousel(idx, smooth = true) {
|
||||||
|
if (isAnimating || thumbs.length === 0) return;
|
||||||
|
|
||||||
|
// Infinite loop logic
|
||||||
|
if (idx < 0) idx = thumbs.length - 1;
|
||||||
|
if (idx >= thumbs.length) idx = 0;
|
||||||
|
|
||||||
|
// Animate transition
|
||||||
|
if (smooth) {
|
||||||
|
isAnimating = true;
|
||||||
|
mainImg.style.opacity = '0.5';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update selected thumbnail
|
||||||
|
thumbs.forEach(t => t.classList.remove('selected'));
|
||||||
|
thumbs[idx].classList.add('selected');
|
||||||
|
|
||||||
|
// Update main image
|
||||||
|
const newSrc = thumbs[idx].querySelector('img').src;
|
||||||
|
|
||||||
|
if (smooth) {
|
||||||
|
setTimeout(() => {
|
||||||
|
mainImg.src = newSrc;
|
||||||
|
mainImg.style.opacity = '1';
|
||||||
|
isAnimating = false;
|
||||||
|
}, 150);
|
||||||
|
} else {
|
||||||
|
mainImg.src = newSrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = idx;
|
||||||
|
|
||||||
|
// Scroll thumbnail into view (centered)
|
||||||
|
const thumbContainer = document.querySelector('.carousel-thumbnails');
|
||||||
|
if (thumbContainer) {
|
||||||
|
const thumbElement = thumbs[idx];
|
||||||
|
const containerRect = thumbContainer.getBoundingClientRect();
|
||||||
|
const thumbRect = thumbElement.getBoundingClientRect();
|
||||||
|
const scrollLeft = thumbElement.offsetLeft - (containerRect.width / 2) + (thumbRect.width / 2);
|
||||||
|
thumbContainer.scrollTo({ left: scrollLeft, behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrow click handlers
|
||||||
|
if (leftArrow) {
|
||||||
|
leftArrow.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
updateCarousel(current - 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightArrow) {
|
||||||
|
rightArrow.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
updateCarousel(current + 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thumbnail click handlers
|
||||||
|
thumbs.forEach((thumb, idx) => {
|
||||||
|
thumb.addEventListener('click', () => updateCarousel(idx));
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
// Swipe support for touch devices
|
||||||
|
let touchStartX = null;
|
||||||
|
|
||||||
|
carouselMain.addEventListener('touchstart', (e) => {
|
||||||
|
touchStartX = e.touches[0].clientX;
|
||||||
|
}, { passive: true });
|
||||||
|
|
||||||
|
carouselMain.addEventListener('touchend', (e) => {
|
||||||
|
if (touchStartX === null) return;
|
||||||
|
|
||||||
|
const endX = e.changedTouches[0].clientX;
|
||||||
|
const diffX = endX - touchStartX;
|
||||||
|
|
||||||
|
// Require minimum swipe distance
|
||||||
|
if (Math.abs(diffX) > 50) {
|
||||||
|
if (diffX > 0) {
|
||||||
|
updateCarousel(current - 1); // Swipe right = previous
|
||||||
|
} else {
|
||||||
|
updateCarousel(current + 1); // Swipe left = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
touchStartX = null;
|
||||||
|
}, { passive: true });
|
||||||
|
|
||||||
|
// Keyboard navigation
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
// Only if carousel is visible in viewport
|
||||||
|
const rect = carouselMain.getBoundingClientRect();
|
||||||
|
const inViewport = rect.top < window.innerHeight && rect.bottom > 0;
|
||||||
|
|
||||||
|
if (!inViewport) return;
|
||||||
|
|
||||||
|
if (e.key === 'ArrowLeft') {
|
||||||
|
e.preventDefault();
|
||||||
|
updateCarousel(current - 1);
|
||||||
|
} else if (e.key === 'ArrowRight') {
|
||||||
|
e.preventDefault();
|
||||||
|
updateCarousel(current + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize first thumbnail as selected
|
||||||
|
updateCarousel(current, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Sticky Add to Basket Button ---
|
||||||
|
(function handleStickyButton() {
|
||||||
|
const btn = document.querySelector('.add-to-basket-sticky');
|
||||||
|
if (!btn) return;
|
||||||
|
|
||||||
|
// Store original position after page load
|
||||||
|
let originalBottom = null;
|
||||||
|
let isInitialized = false;
|
||||||
|
|
||||||
|
function initPosition() {
|
||||||
|
const rect = btn.getBoundingClientRect();
|
||||||
|
originalBottom = window.scrollY + rect.bottom;
|
||||||
|
isInitialized = true;
|
||||||
|
checkSticky();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkSticky() {
|
||||||
|
if (!isInitialized) return;
|
||||||
|
|
||||||
|
// On tablet/mobile (992px and below), always keep sticky
|
||||||
|
if (window.innerWidth <= 992) {
|
||||||
|
btn.classList.add('is-sticky');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On desktop: sticky while user hasn't scrolled past the button's original position
|
||||||
|
const viewportBottom = window.scrollY + window.innerHeight;
|
||||||
|
|
||||||
|
if (viewportBottom < originalBottom) {
|
||||||
|
// User hasn't scrolled enough to see the button naturally
|
||||||
|
btn.classList.add('is-sticky');
|
||||||
|
} else {
|
||||||
|
// User has scrolled past where the button would naturally be
|
||||||
|
btn.classList.remove('is-sticky');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleResize() {
|
||||||
|
// Recalculate position on resize
|
||||||
|
btn.classList.remove('is-sticky');
|
||||||
|
setTimeout(() => {
|
||||||
|
initPosition();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize after DOM is ready and images are loaded
|
||||||
|
if (document.readyState === 'complete') {
|
||||||
|
initPosition();
|
||||||
|
} else {
|
||||||
|
window.addEventListener('load', initPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('scroll', checkSticky, { passive: true });
|
||||||
|
window.addEventListener('resize', handleResize, { passive: true });
|
||||||
|
})();
|
||||||
if (document.querySelector('.product #product-form')) {
|
if (document.querySelector('.product #product-form')) {
|
||||||
let updatePrice = () => {
|
let updatePrice = () => {
|
||||||
let price = parseFloat(document.querySelector('.product .price').dataset.price);
|
let price = parseFloat(document.querySelector('.product .price').dataset.price);
|
||||||
@@ -45,6 +221,40 @@ if (document.querySelector('.product #product-form')) {
|
|||||||
};
|
};
|
||||||
document.querySelectorAll('.product #product-form .option').forEach(ele => ele.onchange = () => updatePrice());
|
document.querySelectorAll('.product #product-form .option').forEach(ele => ele.onchange = () => updatePrice());
|
||||||
updatePrice();
|
updatePrice();
|
||||||
|
|
||||||
|
// Add to cart event
|
||||||
|
document.querySelector('.product #product-form').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault(); // Prevent immediate submission
|
||||||
|
|
||||||
|
let productId = document.querySelector('input[name="product[product]"]').value;
|
||||||
|
let quantity = parseInt(document.querySelector('input[name="product[quantity]"]').value);
|
||||||
|
let productName = document.querySelector('.product .name').textContent;
|
||||||
|
let price = parseFloat(document.querySelector('.product .price').dataset.price);
|
||||||
|
|
||||||
|
window.dataLayer.push({
|
||||||
|
'event': 'addToCart',
|
||||||
|
'ecommerce': {
|
||||||
|
'add': {
|
||||||
|
'products': [{
|
||||||
|
'id': productId,
|
||||||
|
'name': productName,
|
||||||
|
'price': price,
|
||||||
|
'quantity': quantity
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'content_type': 'product',
|
||||||
|
'content_ids': [productId],
|
||||||
|
'content_name': productName,
|
||||||
|
'value': price * quantity,
|
||||||
|
'currency': 'EUR'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Submit form after a short delay
|
||||||
|
setTimeout(() => {
|
||||||
|
e.target.submit();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (document.querySelector('.products-form')) {
|
if (document.querySelector('.products-form')) {
|
||||||
let products_form_submit = () => {
|
let products_form_submit = () => {
|
||||||
@@ -74,6 +284,11 @@ if (document.querySelector('.cart .ajax-update')) {
|
|||||||
document.querySelectorAll('.product-total').forEach((e,i) => {
|
document.querySelectorAll('.product-total').forEach((e,i) => {
|
||||||
e.innerHTML = doc.querySelectorAll('.product-total')[i].innerHTML;
|
e.innerHTML = doc.querySelectorAll('.product-total')[i].innerHTML;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Push cart update event
|
||||||
|
window.dataLayer.push({
|
||||||
|
'event': 'updateCart'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -94,6 +309,12 @@ const checkoutHandler = () => {
|
|||||||
document.querySelector('.total').innerHTML = doc.querySelector('.total').innerHTML;
|
document.querySelector('.total').innerHTML = doc.querySelector('.total').innerHTML;
|
||||||
document.querySelector('.discount-code .result').innerHTML = doc.querySelector('.discount-code .result').innerHTML;
|
document.querySelector('.discount-code .result').innerHTML = doc.querySelector('.discount-code .result').innerHTML;
|
||||||
document.querySelector('.shipping-methods-container').innerHTML = doc.querySelector('.shipping-methods-container').innerHTML;
|
document.querySelector('.shipping-methods-container').innerHTML = doc.querySelector('.shipping-methods-container').innerHTML;
|
||||||
|
|
||||||
|
// Push checkout update event
|
||||||
|
window.dataLayer.push({
|
||||||
|
'event': 'checkoutUpdate'
|
||||||
|
});
|
||||||
|
|
||||||
checkoutHandler();
|
checkoutHandler();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -130,6 +351,13 @@ function update(id_large, IMG_large, option_id, price){
|
|||||||
function updateOption(id_large, IMG_large){
|
function updateOption(id_large, IMG_large){
|
||||||
//change picture
|
//change picture
|
||||||
document.getElementById(id_large).src = IMG_large;
|
document.getElementById(id_large).src = IMG_large;
|
||||||
|
|
||||||
|
// Update the first thumbnail to match the new main image
|
||||||
|
let firstThumbnail = document.querySelector('.product-img-small img');
|
||||||
|
if (firstThumbnail) {
|
||||||
|
firstThumbnail.src = IMG_large;
|
||||||
|
firstThumbnail.parentElement.classList.add('selected');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -217,12 +445,5 @@ function initializeCarousels() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize carousels when DOM is loaded
|
// Only initialize carousels once DOM is loaded
|
||||||
document.addEventListener('DOMContentLoaded', initializeCarousels);
|
// (No duplicate or stray HTML allowed)
|
||||||
|
|
||||||
// Also initialize if DOM is already loaded
|
|
||||||
if (document.readyState === 'loading') {
|
|
||||||
document.addEventListener('DOMContentLoaded', initializeCarousels);
|
|
||||||
} else {
|
|
||||||
initializeCarousels();
|
|
||||||
}
|
|
||||||
@@ -87,7 +87,7 @@ try {
|
|||||||
$invoice_language = 'US'; // Default fallback
|
$invoice_language = 'US'; // Default fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
list($data,$customer_email,$order_id) = generateInvoice($invoice_cust,$orderId,$invoice_language);
|
list($data,$invoice_customer_email,$order_id) = generateInvoice($invoice_cust,$orderId,$invoice_language);
|
||||||
|
|
||||||
//CREATE PDF
|
//CREATE PDF
|
||||||
$dompdf->loadHtml($data);
|
$dompdf->loadHtml($data);
|
||||||
@@ -102,7 +102,7 @@ try {
|
|||||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
//Send to PHPMailer
|
//Send to PHPMailer
|
||||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
send_mail_by_PHPMailer($customer_email, $subject, $data, $attachment, $subject);
|
send_mail_by_PHPMailer($invoice_customer_email, $subject, $data, $attachment, $subject);
|
||||||
|
|
||||||
if(invoice_bookkeeping){
|
if(invoice_bookkeeping){
|
||||||
send_mail_by_PHPMailer(email_bookkeeping, $subject, $data, $attachment, $subject);
|
send_mail_by_PHPMailer(email_bookkeeping, $subject, $data, $attachment, $subject);
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ if($token !=''){
|
|||||||
$invoice_language = 'US'; // Default fallback
|
$invoice_language = 'US'; // Default fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
list($data,$customer_email,$order_id) = generateInvoice($invoice_cust,$orderId,$invoice_language);
|
list($data,$invoice_customer_email,$order_id) = generateInvoice($invoice_cust,$orderId,$invoice_language);
|
||||||
|
|
||||||
//CREATE PDF
|
//CREATE PDF
|
||||||
$dompdf->loadHtml($data);
|
$dompdf->loadHtml($data);
|
||||||
@@ -97,7 +97,7 @@ if($token !=''){
|
|||||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
//Send to PHPMailer
|
//Send to PHPMailer
|
||||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
send_mail_by_PHPMailer($customer_email, $subject, $data, $attachment, $subject);
|
send_mail_by_PHPMailer($invoice_customer_email, $subject, $data, $attachment, $subject);
|
||||||
|
|
||||||
if(invoice_bookkeeping){
|
if(invoice_bookkeeping){
|
||||||
send_mail_by_PHPMailer(email_bookkeeping, $subject, $data, $attachment, $subject);
|
send_mail_by_PHPMailer(email_bookkeeping, $subject, $data, $attachment, $subject);
|
||||||
|
|||||||