Changes to repeater ui, and completed MVP for custom image sizes

This commit is contained in:
Jeremy Rangel
2025-01-04 14:58:58 -08:00
parent 63e181109c
commit ceb37fc5af
8 changed files with 360 additions and 7 deletions

View File

@ -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);
});
}

View File

@ -1,5 +1,4 @@
document.addEventListener('DOMContentLoaded', function () { 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 // Check if the 'Import Demo Posts' button exists
const importButton = document.getElementById('import-demo-posts'); 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 // Check if the 'Delete Demo Posts' button exists
const deleteButton = document.getElementById('delete-demo-posts'); const deleteButton = document.getElementById('delete-demo-posts');

View File

@ -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);
});
});

View File

@ -575,3 +575,120 @@ function lcp_delete_demo_posts_ajax_handler() {
// Send a success response back to the browser // Send a success response back to the browser
wp_send_json_success('Demo posts deleted successfully.'); 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');

View File

@ -47,7 +47,16 @@ function lcp_custom_svgs_field() {
<?php <?php
} }
function custom_image_size_settings_page() {
add_options_page(
'Custom Image Sizes', // Page title
'Custom Image Sizes', // Menu title
'manage_options', // Capability
'custom-image-sizes', // Menu slug
'display_custom_image_size_form' // Callback function to display the form
);
}
add_action('admin_menu', 'custom_image_size_settings_page');
@ -247,6 +256,7 @@ function render_lcp_theme_settings_page() {
<li class="tab-link active" data-tab="custom-meta">Custom Meta</li> <li class="tab-link active" data-tab="custom-meta">Custom Meta</li>
<li class="tab-link" data-tab="icons">Icons</li> <li class="tab-link" data-tab="icons">Icons</li>
<li class="tab-link" data-tab="custom-code">Custom Code</li> <li class="tab-link" data-tab="custom-code">Custom Code</li>
<li class="tab-link" data-tab="images">Images</li>
<li class="tab-link" data-tab="misc">Miscellaneous</li> <li class="tab-link" data-tab="misc">Miscellaneous</li>
</ul> </ul>
@ -302,6 +312,24 @@ function render_lcp_theme_settings_page() {
</form> </form>
</div> </div>
<div id="images" class="tab-pane">
<h3> Image Sizes </h3>
<div class="lcp-repeater">
<div class="lcp-repeater-row">
<input data-lcp-repeater-key="name" placeholder="Enter Name">
<input type="number" data-lcp-repeater-key="width" data-lcp-required="true" placeholder="Enter Width (pixels)">
<input type="number" data-lcp-repeater-key="height" data-lcp-required-for-new-row="true" placeholder="Enter Height (pixels)">
<label for="crop-toggle">Crop</label>
<input type="checkbox" data-lcp-repeater-key="crop">
</div>
<button class="lcp-button lcp-repeater-add-row" id="add-repeater-row">Add Row</button>
<button class="lcp-button lcp-repeater-submit" data-lcp-action="lcpUpdateImageSizes"id="submit-repeater">Submit Repeater</button>
</div>
</div>
<!-- Misc Settings Tab -->
<div id="misc" class="tab-pane"> <div id="misc" class="tab-pane">
<!-- Misc Settings --> <!-- Misc Settings -->
<h2>Miscellaneous Settings</h2> <h2>Miscellaneous Settings</h2>

View File

@ -55,6 +55,31 @@ function lcp_backend_enqueue() {
'ajax_url' => admin_url('admin-ajax.php'), // This is the URL that well send the AJAX request to 'ajax_url' => admin_url('admin-ajax.php'), // This is the URL that well send the AJAX request to
'nonce' => wp_create_nonce('lcp_import_demo_posts_nonce') // Security nonce for validation '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'); 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');

View File

@ -322,7 +322,7 @@ Version: 0.0.1
#lcp-sidecontent { #lcp-sidecontent {
overflow: scroll;
scrollbar-color: red orange; scrollbar-color: red orange;
scrollbar-width: thin; scrollbar-width: thin;
border-radius:5px border-radius:5px

BIN
theme.zip

Binary file not shown.