Upload images to S3 via WordPress Plugin

A few years ago I blogged about creating an Adobe AIR app that would allow me to drag and drop images on it and automatically upload them to my blog server. The backend code would store the image and create a thumbnail. The WordPress plugin would display the images on the sidebar.

Since visiting AWS re:Invent, I started looking for a project to play around with some AWS services and decided it was time to create a new version of the “uploader”. The stack I used:

  • WordPress plugin
    • PHP
    • JS
  • S3 to store the images and thumbnails
  • SQS to get notified when the thumbnails are created
  • Lambda to generate thumbnails after an image is uploaded to S3

Concept

A WordPress plugin is configured to run on the sidebar. For a guest user, only the functionality to list images is loaded. This will make an API call to load all objects from the S3 bucket. In JS, we parse through all objects and display the newest x thumbnail images on the screen. Clicking on the image will load the original sized version.

The experience for the admin user is a bit different. That user sees a drag and drop area above the thumbnails. Upon dropping images on that spot, two progress bars are displayed. One shows the progress of images being uploaded to S3. The other shows the progress of thumbnails begin generated.

Guest View:

Admin View:

Uploading:

The Process

High level, this is what is happening:

  • Images are dropped on the WordPress plugin’s drag and drop area.
  • A call is made to upload those images to an S3 bucket using the AWS JS SDK.
  • The S3 bucket receives the image and when it’s completed, a Lambda function is triggered.
  • The Lambda function creates a thumbnail image and puts it in the thumbnail bucket.
  • When the thumbnail is fully received, that S3 bucket sends SQS a message with information about that image.
  • JS keeps checking back with SQS to check on completed images and when all images are done, resets the display and shows the new thumbnails.

Setup

S3

The first part of the process is to create two S3 buckets: one for the original sized images and the other for the thumbnails. The trickiest part here is to get permissions correct in AWS. We’ll need to attach the right policies. A lot of how I learned to configure this and how I got this to work comes from a hands-on training class from QuiklabsIntroduction to AWS Lambda.

Lambda

The purpose of the Lambda is to resize an uploaded image and store it in the thumbnail bucket.

SQS

We use SQS to track what thumbnails have been generated. When the Lambda is done, it sends a message to the SQS queue to let it know it’s finished.

WordPress Plugin

Nothing fancy here, just a WordPress plugin that shows recent images based on an API call to the S3 thumbnail bucket. It has a widget setup page to store the AWS connection strings.

Here is the repo: https://github.com/joeyrivera/wp-s3-images

Steps To Make This Happen

  • Setup S3
    • create two buckets
    • setup permissions
  • Create Lambda
    • configure the resize script
    • set it as a triggered event on the S3 bucket
    • setup permissions
  • Setup SQS
    • add event to receive from S3 resize bucket
    • setup permissions
  • Create WordPress plugin
    • create widget form
    • create settings page
    • drag and drop

Conclusion

If you want more details, leave a comment and I’ll do my best to answer your question or update this post with more.

Resources

WordPress Plugins

  • https://developer.wordpress.org/themes/basics/including-css-javascript/
  • https://wordpress.org/support/article/debugging-in-wordpress/

Drag and Drop JS

  • https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop
  • https://www.smashingmagazine.com/2018/01/drag-drop-file-uploader-vanilla-js/

AWS

  • https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html
  • https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SQS.html
  • https://docs.aws.amazon.com/AmazonS3/latest/user-guide/enable-event-notifications.html
  • https://www.tothenew.com/blog/configuring-sns-notifications-for-s3-put-object-event-operation/
  • https://stackoverflow.com/questions/19176926/how-to-make-all-objects-in-aws-s3-bucket-public-by-default
  • https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/s3-example-photo-album.html
  • https://run.qwiklabs.com/focuses/8613?parent=catalog
  • https://docs.aws.amazon.com/AmazonS3/latest/user-guide/enable-event-notifications.html#enable-event-notifications-how-to
  • https://aws.amazon.com/blogs/aws/new-for-aws-lambda-environment-variables-and-serverless-application-model/

Quick update to Uploader – fixed some minor bugs

Two bugs were found and addressed. The first bug happened while trying to upload a link. I dropped a URL on the Uploader and the app got stuck in the “Thinking” phase. After some troubleshooting, I noticed the page for the URL did not have a <title> tag so the app was sending the PHP page an empty ‘name’ variable causing the PHP page to stop executing during the validation phase.  The fix was to assign a default name to the link if no title tag is present. In these cases, I’ll manually give the link a proper title.

The second issue also had to do with the <title> tag. In this case, the HTML did have a title tag but the case was different that what I was looking for. My code was looking for all lowercase characters and the tag in the HTML was in uppercase. My first thought was to do a .toLowerCase() on the HTML code but then all the titles would be in lower case and wouldn’t look as presentable (ex: the size of our planet vs The Size of Our Planet). After giving this some more thought, it seemed using regex would be the cleanest solution. A quick Google search returned this page which said by adding an ‘i’ to the end of my regex, the search would be case insensitive. I gave it a try and it worked like a charm.

Before Code:

var start:Number = s.indexOf('<title>');
var end:Number = s.indexOf('</title>');
var title:String = s.substr(start + 7, end - start - 7);

After Code:

var start:Number = s.search(/<title>/i);
var end:Number = s.search(/<\/title>/i);
var title:String = s.substr(start + 7, end - start - 7);

Uploader Phase 2 complete!

Here is a screen shot of the Uploader 0.1.0
Uploader 0.2.0

So today after work I decided it was about time to start working on phase two of my Uploader tool. Phase two consists of allowing me to drag and drop an image URL into the app so the app can then download the image to a folder in my server, create a thumbnail of this image, and update the WordPress database with information about the new image. The new image would then show up the next time a person visits my blog. If you notice, there is now a “Pics of Interest” section on the sidebar to the right of the page (similar to what people are doing with the flickr plugin). Every time I drag an image URL into the Uploader, the new image thumbnail will show in that area and if you click on the thumbnail you’ll see the full size image.

It was actually much easier than I originally thought to make this work. Technically, the Uploader already has the drag/drop functionality and already takes in a URL. The only extra AS3 code was a check to see if the URL was an image and if so call the PHP page with a code (I’m passing –@IMAGE@– to know it’s an image – it was just the first thing that came to my head) so then PHP knows this URL should be treated as an image not just a URL. If you remember, phase 1 for the Uploader allows a person to drag/drop a URL into the app so it creates a new link under the “Links of Interest”. Continue reading “Uploader Phase 2 complete!”

Uploader Phase 1

Here is a screen shot of the Uploader 0.1.0
Uploader 0.1.0

If you missed the previous post explaining what Uploader is go check it out.

So after having some fun with code I think I’m close to being done with phase 1.  I currently have a working beta (0.1.0) that I’m going to share with you all and explain what I’ve done in case anyone else wants to do something similar.  For the most part this was pretty straight forward.  There were a few hiccups here and there that I’ll try to address in this post. The link to the code will be at the end.

  Continue reading “Uploader Phase 1”

Uploader: Automating WordPress Links and File Uploads

So now that I’m starting to get my WordPress and new hosting server settled in I’m trying to think of what I can create to help me automate some tasks. One of the things I know I’ll be doing quite often is adding new links to the ‘Links of Interest’ on the front page.  I’ll also be uploading files/images to use on posts or to share with others but I’m too lazy to be ftping files constantly. So… time for a new tool!

The Uploader (yeah I know, I’m very creative) is going to do all the above for me. This will be a app I can keep running on my desktop somewhere and when I need to upload a file or link I can just drag it over and drop it in. The tool will then figure out what kind of item was dropped in and what to do with it.

Phase 1 will handle the links. The way the tool should work for links is the following.  I visit a page that I find interesting and want to add to the ‘Links of Interest’.  Instead of logging into WordPress to create it, I highlight the link from the address bar of the browser, drag it over to the app, and drop it. Now the app needs to figure out the <title> of that page to use as the name since we need a name and url to create a link. Once it has that, the tool will send the information to a PHP page which will do an insert to the links table in the WordPress DB.  

Phase 2 will deal with images and files. I may break phase 2 into two since I may do some stuff differently with images versus other files.  I’m thinking I may want to upload images, create a thumbnail, and insert to a DB to display in the front page the same way some people do with their flickr images. Other files I would just upload and store somewhere else.  I’ll give this more thought when I get to it.

I’m going to be writing the tool in Flash CS3/AIR with PHP in the backend using the current WordPress MySQL DB.  Stay tuned for updates!

EDIT:

Uploader Phase 1 completed 
Uploader Phase 2 completed