diff --git a/assets/js/custom-image-sizes.js b/assets/js/custom-image-sizes.js new file mode 100644 index 0000000..f11f33c --- /dev/null +++ b/assets/js/custom-image-sizes.js @@ -0,0 +1,32 @@ +function lcpUpdateImageSizes(imageSizes) { + // Validate the input to ensure it's an array + if (!Array.isArray(imageSizes)) { + console.error('Invalid image sizes data'); + return; + } + + // Prepare the form data to send to WordPress to update the theme settings + const updateData = new FormData(); + updateData.append('action', 'update_lcp_theme_settings'); // WordPress action hook + updateData.append('image_sizes', JSON.stringify(imageSizes)); // Send image sizes as a JSON string + updateData.append('nonce', customImageSizeAjax.nonce); // Send the nonce + + console.log('Sending data to AJAX:', updateData); // Log the data for debugging + + // Send the AJAX request + fetch(customImageSizeAjax.ajax_url, { + method: 'POST', + body: updateData, // Send form data directly + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + console.log('Theme settings updated successfully.'); + } else { + console.error('Failed to update theme settings:', data.message); + } + }) + .catch(error => { + console.error('Error updating theme settings:', error); + }); +} diff --git a/assets/js/demo-posts-import.js b/assets/js/demo-posts-import.js index 7cbea3e..0fd32db 100644 --- a/assets/js/demo-posts-import.js +++ b/assets/js/demo-posts-import.js @@ -1,5 +1,4 @@ document.addEventListener('DOMContentLoaded', function () { - console.log("I Tried"); // This will log the button element to the console // Check if the 'Import Demo Posts' button exists const importButton = document.getElementById('import-demo-posts'); @@ -42,9 +41,7 @@ document.addEventListener('DOMContentLoaded', function () { }); }); } - } else { - console.warn('Import button not found.'); - } + } // Check if the 'Delete Demo Posts' button exists const deleteButton = document.getElementById('delete-demo-posts'); diff --git a/assets/js/lcp-ui.js b/assets/js/lcp-ui.js index 5f5ce53..c7be16b 100644 --- a/assets/js/lcp-ui.js +++ b/assets/js/lcp-ui.js @@ -94,3 +94,157 @@ document.addEventListener('DOMContentLoaded', function () { }); }); + +/* REPEATER */ +document.addEventListener('DOMContentLoaded', function() { + // Function to initialize each repeater instance + function initRepeater(repeater) { + const firstRow = repeater.querySelector('.lcp-repeater-row'); + + // Function to check if all required fields are filled + function isRequiredFieldsFilled(row) { + const requiredFields = row.querySelectorAll('[data-lcp-required="true"], [data-lcp-required-for-new-row="true"]'); + let valid = true; + + requiredFields.forEach(input => { + // Check input type and value for validation + if (input.type === 'number' && (input.value === '' || isNaN(input.value))) { + valid = false; + } else if (input.type === 'checkbox' && !input.checked) { + valid = false; + } + }); + + return valid; + } + + // Function to create a new row by cloning the first row + function addRepeaterRow() { + const newRow = firstRow.cloneNode(true); // true means deep cloning (includes children) + + const inputs = newRow.querySelectorAll('input'); + inputs.forEach(input => input.value = ''); // Reset value for input fields + newRow.querySelector('input[type="checkbox"]').checked = false; // Uncheck the checkbox + + repeater.insertBefore(newRow, repeater.querySelector('.lcp-repeater-add-row')); + + toggleAddRowButton(); + toggleSubmitButton(); + } + + // Function to toggle the "Add Row" button based on the required field for new rows + function toggleAddRowButton() { + const addRowButton = repeater.querySelector('.lcp-repeater-add-row'); + const rows = repeater.querySelectorAll('.lcp-repeater-row'); + + let validForNewRow = true; + + rows.forEach(row => { + const requiredForNewRowFields = row.querySelectorAll('[data-lcp-required-for-new-row="true"]'); + requiredForNewRowFields.forEach(input => { + if (input.value === '' || (input.type === 'checkbox' && !input.checked)) { + validForNewRow = false; + } + }); + }); + + addRowButton.disabled = !validForNewRow; + } + + // Function to toggle the "Submit" button based on the validation of all rows + function toggleSubmitButton() { + const submitButton = repeater.querySelector('.lcp-repeater-submit'); + const rows = repeater.querySelectorAll('.lcp-repeater-row'); + + let allValid = true; + + rows.forEach(row => { + if (!isRequiredFieldsFilled(row)) { + allValid = false; + } + }); + + submitButton.disabled = !allValid; + } + + // Function to handle form submission, ensuring all required fields are filled + function handleSubmit(event) { + const submitButton = event.target; + const actionType = submitButton.getAttribute('data-lcp-action'); // This will be used to pass data to the handler + const rows = repeater.querySelectorAll('.lcp-repeater-row'); + let allValid = true; + + rows.forEach(row => { + if (!isRequiredFieldsFilled(row)) { + allValid = false; + } + }); + + if (allValid) { + const repeaterData = []; + + rows.forEach(function(row) { + const rowData = {}; + const inputs = row.querySelectorAll('input'); + + inputs.forEach(function(input) { + const key = input.getAttribute('data-lcp-repeater-key'); + let value; + + if (input.type === 'checkbox') { + value = input.checked; // Boolean value for checkbox + } else { + value = input.value; // Text or number inputs + } + + rowData[key] = value; // Add key-value pair to rowData + }); + + repeaterData.push(rowData); // Add rowData to the repeaterData array + }); + + // Now just pass the data off to the handler + if (typeof window[actionType] === 'function') { + window[actionType](repeaterData); // Calls the function (e.g., `lcpUpdateImageSizes`) + } + } else { + alert("Please fill in all required fields."); + } + } + + // Event listener for adding a new row when a user clicks the "Add Row" button + const addRowButtons = repeater.querySelectorAll('.lcp-repeater-add-row'); + addRowButtons.forEach(button => { + button.addEventListener('click', function() { + if (isRequiredFieldsFilled(firstRow)) { + addRepeaterRow(); + } else { + alert('Please fill in the required fields to add a new row.'); + } + }); + }); + + // Event listener for submitting the repeater form + const submitButton = repeater.querySelector('.lcp-repeater-submit'); + submitButton.addEventListener('click', handleSubmit); + + // Initial validation for the add row button + toggleAddRowButton(); + + // Initial validation for the submit button + toggleSubmitButton(); + + // Added event listeners to handle any changes in input and trigger validation + repeater.addEventListener('input', function() { + toggleAddRowButton(); // Revalidate Add Row button + toggleSubmitButton(); // Revalidate Submit button + }); + } + + // Initialize each repeater on the page + const repeaters = document.querySelectorAll('.lcp-repeater'); + repeaters.forEach(repeater => { + initRepeater(repeater); + }); +}); + diff --git a/functions.php b/functions.php index 4b6216e..15736e4 100644 --- a/functions.php +++ b/functions.php @@ -575,3 +575,120 @@ function lcp_delete_demo_posts_ajax_handler() { // Send a success response back to the browser wp_send_json_success('Demo posts deleted successfully.'); } + + + +// Set a visited post cookies + // Hooked into send_headers via wp-hooks.php + + function lcp_set_visited_posts_cookie() { + // Only track posts on single post pages + if (is_single()) { + // Get the current post's ID and post type + $current_post_id = get_the_ID(); + $post_type = get_post_type(); + $visit_time = time(); // Get the current time as a Unix timestamp + + // Check if the cookie exists + if (isset($_COOKIE['lcp_visited_posts'])) { + // Decode the cookie's JSON value + $visited_posts = json_decode(stripslashes($_COOKIE['lcp_visited_posts']), true); + + // Check if decoding was successful and if the format is correct + if (json_last_error() !== JSON_ERROR_NONE || !is_array($visited_posts)) { + // If the cookie is not valid, delete the cookie and start over + setcookie('lcp_visited_posts', '', time() - 3600, '/'); // Expire the cookie + $visited_posts = []; // Initialize an empty array + } + } else { + // Initialize an empty array if the cookie doesn't exist + $visited_posts = []; + } + + // If the post type is not already in the cookie, initialize it as an empty array + if (!isset($visited_posts[$post_type])) { + $visited_posts[$post_type] = []; + } + + // Add the current post ID and the visit timestamp as an array entry + // Ensure that the post ID isn't already added for this post type + $found = false; + foreach ($visited_posts[$post_type] as &$post) { + if (array_key_exists($current_post_id, $post)) { + $post[$current_post_id] = $visit_time; // Update the timestamp if post already exists + $found = true; + break; + } + } + + // If post wasn't found, add it as a new entry + if (!$found) { + $visited_posts[$post_type][] = [$current_post_id => $visit_time]; + } + + // Encode the updated visited posts array to JSON + $cookie_value = json_encode($visited_posts); + + // Set the cookie with a 30-day expiration time (this must be done before any output) + setcookie('lcp_visited_posts', $cookie_value, time() + (30 * 24 * 60 * 60), '/'); // '/' makes the cookie available across the whole site + } +} + + +/* CUSTOM IMAGE SIZES */ +function lcp_update_image_sizes() { + // Verify nonce for security + if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'custom_image_sizes_nonce')) { + wp_send_json_error(array('message' => 'Nonce validation failed.')); + return; + } + + // Check if image_sizes data is provided + if (isset($_POST['image_sizes'])) { + $image_sizes = json_decode(stripslashes($_POST['image_sizes']), true); // Decode JSON data + + // Make sure that the image_sizes data is valid + if (!is_array($image_sizes)) { + wp_send_json_error(array('message' => 'Invalid image sizes data.')); + return; + } + + // Process the data (e.g., update options) + update_option('lcp_image_sizes', $image_sizes); + + // Return success message + wp_send_json_success(array('message' => 'Image sizes updated successfully.')); + } else { + wp_send_json_error(array('message' => 'No image sizes data received.')); + } +} + +add_action('wp_ajax_update_lcp_theme_settings', 'lcp_update_image_sizes'); +add_action('wp_ajax_nopriv_update_lcp_theme_settings', 'lcp_update_image_sizes'); + +function lcp_register_custom_image_sizes() { + // Retrieve the 'lcp_image_sizes' option, which is already unserialized by WordPress + $custom_image_sizes = get_option('lcp_image_sizes'); + + // Check if the option exists and is an array (because WordPress auto-unserializes the data) + if ($custom_image_sizes && is_array($custom_image_sizes)) { + // Loop through the array and register each image size + foreach ($custom_image_sizes as $size) { + // Ensure the size has the correct keys and valid values + if (isset($size['name'], $size['width'], $size['height'], $size['crop']) && !empty($size['name'])) { + // Sanitize the name, but ensure it's not just a number like '1' + $name = sanitize_key($size['name']); + $width = (int) $size['width']; // Cast to integer + $height = (int) $size['height']; // Cast to integer + $crop = (bool) $size['crop']; // Convert to boolean + + // Register the custom image size + add_image_size($name, $width, $height, $crop); + } + } + } +} + + +// Hook into WordPress to register custom sizes +add_action('after_setup_theme', 'lcp_register_custom_image_sizes'); diff --git a/includes/classes/backend.php b/includes/classes/backend.php index 7082783..ecd32fb 100644 --- a/includes/classes/backend.php +++ b/includes/classes/backend.php @@ -47,7 +47,16 @@ function lcp_custom_svgs_field() { Custom Meta + @@ -302,6 +312,24 @@ function render_lcp_theme_settings_page() { +
+

Image Sizes

+ + +
+
+ + + + + +
+ + +
+
+ +

Miscellaneous Settings

diff --git a/includes/classes/wp-hooks.php b/includes/classes/wp-hooks.php index 4dbd0a3..5c72147 100644 --- a/includes/classes/wp-hooks.php +++ b/includes/classes/wp-hooks.php @@ -55,6 +55,31 @@ function lcp_backend_enqueue() { 'ajax_url' => admin_url('admin-ajax.php'), // This is the URL that we’ll send the AJAX request to 'nonce' => wp_create_nonce('lcp_import_demo_posts_nonce') // Security nonce for validation )); + + /* --- Image Sizes --- */ + // Enqueue the JavaScript file + wp_enqueue_script('custom-image-sizes', get_template_directory_uri() . '/assets/js/custom-image-sizes.js', array(), null, true); + + // Localize script to pass the nonce and ajaxurl to JavaScript + wp_localize_script('custom-image-sizes', 'customImageSizeAjax', array( + 'ajax_url' => admin_url('admin-ajax.php'), // The URL to send the request to + 'nonce' => wp_create_nonce('custom_image_sizes_nonce') // Create the nonce and pass it + )); + } -add_action('admin_enqueue_scripts', 'lcp_backend_enqueue'); \ No newline at end of file +add_action('admin_enqueue_scripts', 'lcp_backend_enqueue'); + + + +function lcp_send_headers_hooks(){ + lcp_set_visited_posts_cookie(); +} +add_action('send_headers','lcp_send_headers_hooks'); + + +function lcp_after_setup_theme() { + lcp_register_custom_image_sizes(); + +} +add_action('after_setup_theme', 'lcp_after_setup_theme'); \ No newline at end of file diff --git a/style.css b/style.css index 10c68f3..26e8735 100644 --- a/style.css +++ b/style.css @@ -322,7 +322,7 @@ Version: 0.0.1 #lcp-sidecontent { - overflow: scroll; + scrollbar-color: red orange; scrollbar-width: thin; border-radius:5px diff --git a/theme.zip b/theme.zip deleted file mode 100644 index c61c35e..0000000 Binary files a/theme.zip and /dev/null differ