Jump to content

Moving Image Files Between File Fields On the Same Page


prestoav
 Share

Recommended Posts

I am re-working an advert editor on a marketplace site and one of the most requested features is to be able to reorder the images that have been uploaded.

To do this I need to be able to move existing images between separate page fields (let's call them image_1, image-_, image_3 etc.). The fields are all setup to have only one image each in the field setup.

So far I have the functionality sorted to allow advert owners to delete images or upload replacement images for each field if needed and that all works fine. I also have an edit form that tracks the images as they are dragged around in JQuery UI so that, when the edit form is submitted, they post-processing can see the original field the image was in and the intended field that the image needs to move to as a result of the reordering.

I'm now stumped as to how to best move the actual files around so they show in the right order, both in the live advert and in the edit form if it's edited again.

Has anyone found a good way to do this?

The stumbling block is that each field can only tae one file at a time so it feels like I need to move all the files to be moved into a temporary location then move them back into the right, new spots.

Any suggestions very much appreciated!

 

Link to comment
Share on other sites

16 hours ago, prestoav said:

The stumbling block is that each field can only tae one file at a time so it feels like I need to move all the files to be moved into a temporary location then move them back into the right, new spots.

The trick is to put all the affected images into a new Pageimages object before you start setting the field values, so you can later get each image from there even after it has been removed from a field value. A proof of concept...

Image fields in Page Edit:

2022-01-19_194323.thumb.png.9d3066289b8ca923849c8d9f17e1b109.png

Tempate file markup:

<script src="/site/templates/js/jquery-ui.min.js"></script>
<script>
	$(document).ready(function() {
		var $sortable_images = $('.sortable-images');
		$sortable_images.sortable({
			// When any image has been moved...
			update: function(event, ui) {
				// Add the image basenames to an array in the new order
				var value = [];
				$sortable_images.find('img').each(function() {
					value.push($(this).data('filename'));
				});
				// Join to a comma separate string and set as the form field value
				$('#images').val(value.join(','));
			}
		});
	});
</script>
<div class="sortable-images">
	<img src="<?= $page->image_1->size(150,150)->url ?>" data-filename="<?= $page->image_1->basename ?>" alt="">
	<img src="<?= $page->image_2->size(150,150)->url ?>" data-filename="<?= $page->image_2->basename ?>" alt="">
	<img src="<?= $page->image_3->size(150,150)->url ?>" data-filename="<?= $page->image_3->basename ?>" alt="">
</div>
<form id="image-order" action="./" method="post">
	<textarea name="images" id="images"></textarea>
	<button>Submit</button>
</form>

Template file PHP:

// Look for the comma separated value in POST
$images_value = $input->post('images');
// If the value exists then the form was submitted
if($images_value) {
	// Explode the comma separated value to an array of image basenames
	$image_names = explode(',', $images_value);
	// Create a Pageimages object using the individual image basenames
	$all_images = new Pageimages($page);
	foreach($image_names as $image_name) {
		$all_images->add($image_name);
	}
	// Turn off output formatting because we are about to set field values
	$page->of(false);
	// Loop over the image basenames
	foreach($image_names as $index => $image_name) {
		// Get the Pageimage from $all_images
		$pageimage = $all_images->get($image_name);
		// Create a new empty Pageimages object
		$pageimages = new Pageimages($page);
		// Add the Pageimage
		$pageimages->add($pageimage);
		// Determine the field name that will be updated
		$image_field_name = 'image_' . ($index + 1);
		// Set the field value
		$page->$image_field_name = $pageimages;
	}
	// Save the page
	$page->save();
	// Redirect back to the page (Post/Redirect/Get pattern)
	$session->redirect($page->url);
}

images-sort.gif.bbdd89277c15741b91958ee53e5d205a.gif

  • Like 2
Link to comment
Share on other sites

  • 1 month later...

Hi @Robin S Thanks again for the code above, really useful.

I'm getting a lot of this to work now except the actual the actual upload of the file itself. The list of file names generates properly to the $_POST['images'] and is readable and correct if you print_t the $image_names.

However, the image isn't uploading and I'm getting this error :

Error: Exception: Unable to read: /site/assets/files/21526/img-1.png (in wire/core/Pagefile.php line 230)

There is no file uploaded to that directory.

Note: 21526 is the page ID, img-1.png is the correct name for the uploaded image.

Further down the error text the issue seems to originate from this line:

$pageimages->add($pageimage);

Here's my full PHP ($pte is the page itself assigned elsewhere and tested as working):

// Update Images
		
		// Look for the comma separated value in POST
		$images_value = $_POST['images'];
		
		// If the value exists then the form was submitted & we need to update image fields
		if($images_value != '') {
		
			// Explode the comma separated value to an array of image basenames
			$image_names = explode(',', $images_value);
			
			// Add empty images if no image added or removed
			if (count($image_names) < 4) {
				$blanks = 4 - count($image_names);
				while ($blanks > 0) {
					array_push($image_names, "");
					$blanks = $blanks - 1;
				}
			}
			
			// Create a Pageimages object using the individual image basenames
			$all_images = new Pageimages($pte);
			
			foreach($image_names as $image_name) {
				$all_images->add($image_name);
			}

			// Turn off output formatting because we are about to set field values
			$pte->of(false);
			
			// Loop over the image basenames
			foreach($image_names as $index => $image_name) {
			
				// Get the Pageimage from $all_images
				$pageimage = $all_images->get($image_name);
				
				// Create a new empty Pageimages object
				$pageimages = new Pageimages($page);
				
				// Add the Pageimage
				if ($pageimage != '') {
					$pageimages->add($pageimage);
			
					// Determine the field name that will be updated
					if ($index == 0) {
						$image_field_name = 'page_image';
					} else {
						$image_field_name = 'product_image_' . $index;
					}
	
					// Set the field value
					$pte->$image_field_name = $pageimages;
				}
			}

		}

		$pte->save();

You'll see I've added blanks to fill in empty / missing fields as the front end form allows for images to be deleted so I need to populate those with no image if they have been deleted. Also, you'll note that the first image field to upload to has a different name. This is a legacy issue I'm dealing with...

Any ideas on why the image isn't being uploaded would be really helpful!

Link to comment
Share on other sites

@prestoav, uploading a file is something different. The code I posted was for moving files that already exist on the page between fields.

There are lots of tutorials out there for how to create a file upload form and process it with PHP. Here is one: https://code.tutsplus.com/tutorials/how-to-upload-a-file-in-php-with-example--cms-31763

When you process the form input you'll want to move the uploaded file to the page's directory (you can use PagefilesManager to get the path) and then you'll be able to add the file to $pageimages using its path.

PW has the WireUpload class which can be useful for handling file uploads. If you search the forums you'll find examples.

Link to comment
Share on other sites

10 hours ago, Robin S said:

@prestoav, uploading a file is something different. The code I posted was for moving files that already exist on the page between fields.

There are lots of tutorials out there for how to create a file upload form and process it with PHP. Here is one: https://code.tutsplus.com/tutorials/how-to-upload-a-file-in-php-with-example--cms-31763

When you process the form input you'll want to move the uploaded file to the page's directory (you can use PagefilesManager to get the path) and then you'll be able to add the file to $pageimages using its path.

PW has the WireUpload class which can be useful for handling file uploads. If you search the forums you'll find examples.

Hi @Robin S this is super helpful and makes complete sense. I was arriving at that conclusion but your explanation and examples really help.

When I have it working I'll post final code here for anyone looking in future.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...