Home › Toolset Professional Support › [Resolved] Changing Images but keeping URL
Problem:
Posts with image fields can be edited with front-end forms, meaning that users can change the images attached to a post. The URLs of these new images will be different, and the client wants to rename the new images so that they keep the old filename and URL.
Solution:
This requires disabling the WordPress setting to store uploads in year/month directories, and custom code to affect the filename changes.
A basic example is suggested below to use as a starting point for developing your own code: https://toolset.com/forums/topic/changing-images/#post-1236293
This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.
Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.
Sun | Mon | Tue | Wed | Thu | Fri | Sat |
---|---|---|---|---|---|---|
- | 7:00 – 14:00 | 7:00 – 14:00 | 7:00 – 14:00 | 7:00 – 14:00 | 7:00 – 14:00 | - |
- | 15:00 – 16:00 | 15:00 – 16:00 | 15:00 – 16:00 | 15:00 – 16:00 | 15:00 – 16:00 | - |
Supporter timezone: Europe/London (GMT+00:00)
Tagged: Toolset Forms
This topic contains 11 replies, has 2 voices.
Last updated by julieP 5 years, 7 months ago.
Assisted by: Nigel.
I'm developing a site where registered users can upload images via CRED. The images are not held in repeating fields; there's a field per image with a maximum of 6. The wordpress settings are set to using folders.
Everything is fine providing the originally uploaded images never change but as soon as image an image is removed by the user and a new one uploaded in its place, the new image will have a different URL (whether the new one resides in the same uploads folder or not) resulting in 404s or alot of redirects. I looked at the Enable Media Replace plugin but this requires wp-admin access which the users won't have.
So my question is whether there's a way of maintaining the original URL when an image is changed via CRED?
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
Hi Julie
Let me get this straight so I understand precisely what the issue is here.
A CRED form is used to publish posts of some type which includes up to 6 distinct image fields.
"an image is removed by the user and a new one uploaded in its place"
How? Using the Media Library?
If the users were removing the images and replacing them with new ones via a CRED edit form, then the URL saved in the image field would be updated accordingly and everything should continue to work.
It sounds like you expect the image fields still to work if the URL stored in the image field and the URL of some new image which the user has somehow selected do not correspond, is that right?
I need to know how the images are being updated to understand the implications.
hi Nigel
Thanks for your prompt attention!
A CRED form is used to publish posts of some type which includes up to 6 distinct image fields.
That's correct
How? Using the Media Library?
No, on the frontend via a CRED edit form
Changing an image works fine - this isn't the issue. The issue is that if an image were to be uploaded today via Field1, the URL for that image would be (for example):-
hidden link
If the user were to remove the image in Field1 next month and upload a different one (assume same filename), the URL would change to:-
hidden link
So I would now have an unused image in the Media Library which I'd have to remove manually resulting in 404s. If I leave unused images in the Library, that will also have consequences as time goes on.
I'd like to keep the Media Library as lean as possible so I'm asking what's achievable or the best approach. ideally, I'd like new images to replace old ones in the library and preferably keeping the original URL . I thought about file renaming on upload using a consistent format and not using folder structure for the library but I'm not sure if/how this can be done and whether it would actually overwrite/replace the existing as desired.
Hope this is a bit clearer?/
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
I'm not sure I follow this bit: "I would now have an unused image in the Media Library which I'd have to remove manually resulting in 404s".
Where do the 404s come from? If you edit the post with a CRED form and replace the image so that the URL points to the new image, wherever you output the image field it should be outputting the correct URL.
So what is outputting the old URL resulting in a 404?
Because apart from that detail it sounds like a house-keeping issue for not leaving "orphan" images in the media library, but, again, I want to be sure.
I would now have an unused image in the Media Library which I'd have to remove manually resulting in 404s because each has its own unique URL and the first/original will have been indexed by search engines already so if it's deleted, the result is a 404.
Yes, there is a house-keeping issue and that's what I'm trying to address. I did think that when an image is changed via a CRED form the original one would be removed from the library but this clearly isn't the case. I can see it could become a nightmare maintaining the media library (for one thing, you can't tell which images are the current ones for any given post without visiting the post itself - a WP issue, I know). I did look into identifying orphaned images using SQL queries on the database but if I recall correctly it was cumbersome amongst other things. It's also a bit "wag the dog's tail yourself".
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
CRED doesn't delete images when you remove them from a post with an edit form, for good reason, namely that once an image is in the Media Library it could be re-used and inserted in any number of places. If the image and the post are dating, they are not exclusive.
(This was the justification for not deleting images uploaded while entering a post via a form which was subsequently abandoned, but thankfully the devs were eventually persuaded that that is too strict.)
If you are happy to delete images from the Media Library whenever a user removes it from a post using a CRED edit form then you can with a little code that runs with the cred_before_save_data hook where you compare whether the submitted image is the same as the existing image, and if they are different delete the image (including the various sizes).
I put together a very crude example, which I'm sure you can modify:
add_action('cred_before_save_data', 'tssupp_form_edited' ); function tssupp_form_edited($form_data) { if (in_array($form_data['id'], array(127))) { $new_image_url = $_POST['wpcf-picture']; $current_image_url = get_post_meta( $form_data['container_id'], 'wpcf-picture', true ); if ( $new_image_url != $current_image_url ){ // delete old image $current_image_id = attachment_url_to_postid( $current_image_url ); wp_delete_attachment( $current_image_id, true ); } } }
Hi Nigel
many thanks for the explanation; in my scenario, images uploaded via a specific Types field will not be used anywhere else. In fact I'm not really convinced I even need the Media Library at all!!!
On a side note, the assumption that images will be re-used is interesting when Google would likely view this as duplicate/low value content (??)
Huge thanks for the snippet - it works a treat.
Is there a way of extending this to rename the new image & update the URL in the Types field using a combination of a usermeta value that already exists + Types field slug (or specific text)?
I've looked at a number of tickets from other users and the approaches are quite varied and don't seem to dovetail easily with the new snippet. For example, I adapted a snippet I found but it's a before_save hook and means of course that I would be renaming a file & URL whilst at the same time trying to check the intended new name with the existing.
I tried adding your snippet in the hook but the existing file isn't deleted. This is what I have so far:-
//Disable ajax uploads of images in Toolset Forms (global) add_filter( 'cred_file_upload_disable_progress_bar', '__return_true' ); //For specified forms set up file rename function tssupp_prepare_to_rename_upload( $form_data ){ if ( in_array( $form_data['id'], array( 2616 ) ) ) { // Edit Form IDs add_filter( 'wp_handle_upload', 'tssupp_handle_rename_upload', 10, 2 ); } } add_action( 'cred_before_save_data', 'tssupp_prepare_to_rename_upload' ); function tssupp_handle_rename_upload( $upload, $context ){ $user_id = get_current_user_id(); $business_name = get_user_meta($user_id, 'wpcf-business-name', true); $slug = sanitize_title_with_dashes( $business_name ); $append = 'random-text'; $path = pathinfo( $upload['file'] ); $newfile = $path['dirname']."/".$slug.'-'.$append.".".$path['extension']; $dir = wp_upload_dir(); $newurl = $dir['url'].'/'.$slug.'-'.$append.".".$path['extension']; rename( $upload['file'], $newfile ); $upload['file'] = $newfile; $upload['url'] = $newurl; return $upload; $current_image_url = get_post_meta( $form_data['container_id'], 'wpcf-custom-field', true ); if ( $newurl != $current_image_url ){ // delete old image $current_image_id = attachment_url_to_postid( $current_image_url ); wp_delete_attachment( $current_image_id, true ); } }
Am I trying to achieve the impossible?
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
Hi Julie
I guess you could check whether the filename has changed, as per the above code, and if it has delete the existing file and only then rename the uploaded file to use the same filename as the old file.
I don't think that would work if you use the date-based subfolders of the wp-uploads directory because you might have the same filename but still have a different URL.
It's not trivial by any means. I gave (too much) support for a similar issue where you can see the code we came up with here: https://toolset.com/forums/topic/split-rename-uploaded-images/#post-1116491
In that case what the user wanted was to rename images that are uploaded by clients so that the filenames match the post titles, to improve the image SEO.
So what's involved is not dissimilar to your use-case.
Can you take a look at that solution and see if you follow it well-enough to adapt?
Hi Nigel
That thread IS the one I worked on to produce the code I've shown in my previous entry. Thanks for pointing out the issue with folders (I had omitted to say I've set the 'use years/months' for uploads to 0).
I've tried moving the 'delete existing' part of the code around and changed the comparison where necessary but still no joy. However, I've noticed that in the Media Library, the filename and permalink are based on the original name of the file uploaded but in the white 'save' box, the File URL and Filename are changed (as intended). This would explain why the first file isn't being deleted but how can a file have two different names and two different URLs?
I've not been able to find much at all about how to deal with changed images (from an SEO point of view). Does everyone just not worry about 404s from orphaned media?
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
Let me try and get the above code working on a local test site and I'll report back with my findings. It might manage it before closing today, but might not.
Languages: English (English ) Spanish (Español )
Timezone: Europe/London (GMT+00:00)
OK, I reworked the code and got it to work on my site.
You can see in the screenshot I have replaced a cat photo with a dog photo, but my dog photo still has the original cat photo filename.
Here's the code:
/** * Disable ajax uploads of images in Toolset Forms (global) */ add_filter( 'cred_file_upload_disable_progress_bar', '__return_true' ); /** * Check if image field has been replaced with edit form */ add_action('cred_before_save_data', 'tssupp_form_edited' ); function tssupp_form_edited($form_data) { if (in_array($form_data['id'], array(8))) { $new_image_url = $_POST['wpcf-the-image']; $current_image_url = get_post_meta( $form_data['container_id'], 'wpcf-the-image', true ); if ( $new_image_url != $current_image_url ){ add_filter( 'wp_handle_upload', 'tssupp_handle_rename_upload', 10, 2 ); } } } /** * Handle file rename taking title from $_REQUEST object */ function tssupp_handle_rename_upload( $upload, $context ){ $current_image_url = get_post_meta( $_REQUEST['_cred_cred_prefix_post_id'], 'wpcf-the-image', true ); $current_image_id = attachment_url_to_postid( $current_image_url ); $current_image_path = get_attached_file( $current_image_id ); // delete current image wp_delete_attachment( $current_image_id, true ); // give new image old image name and path rename( $upload['file'], $current_image_path ); $upload['file'] = $current_image_path; $upload['url'] = $current_image_url; return $upload; }
This is a fairly crude example, I haven't included any kind of error checking for if there is no existing image etc., I'll leave you to experiment with that.
I can see what you've done there - that's awesome, thank you for all your help - gives me something to work on.
Have a good weekend 🙂