Category: Media

  • How I Built WordUp: A Guide to Creating a macOS App

    I realized recently that I don’t do nearly enough about sharing some of the cool things I build. Or blogging. I don’t do nearly enough of either.

    TL;DR: I just shipped my very first macOS desktop app called WordUp.

    https://github.com/georgestephanis/WordUp/releases/tag/v0.2.1

    I’ve used some desktop apps, such as CloudApp (now Zight) and CloudUp (which was acquired shortly after I joined Automattic) in years past. The basic gist is, they live in your computer’s menu bar, and when you either take a screenshot or drag an image onto the icon, it will upload it to their service and give you a handy URL that you can use to share the asset with a client, or a user, or whatever you may need.

    Hugely useful! A modern-day analogue may be something like Loom, I suppose?

    Anyway, at their most basic, these programs do a few relatively trivial things:

    1. Notice when a screenshot is taken or an image is requested to be uploaded,
    2. Upload it to a cloud server for sharing, and
    3. Automatically drop a link to the asset onto your clipboard.

    Well, I’ve wondered for years why this is something that folks need an external company to do. I work with WordPress daily, and I love open-source software! Why can’t an app just connect to your WordPress site and use that as the remote server for hosting the assets?

    No image limits, you own your own data and content, and no need for your usage or credentials to pass through anyone else’s servers.

    My only problem? I’m a web developer, and I have no idea how to work with building desktop apps.

    So I’ve spent the past decade periodically starting conversations with folks in the Apps teams while I worked at Automattic, asking if anyone would be interested in throwing it together or porting over the CloudUp desktop app functionality to also connect to self-hosted WordPress sites. Didn’t get any takers. So I stopped asking, as I really didn’t want to turn into Glootie.

    The other week when it happened to come up and I mentioned it to (fellow ex-Automattician) Jorge Leandro Perez, he suggested that I try to make it myself, using AI-based tooling with Cursor.

    A minor digression: Thoughts and feelings on large language models and generative AI are complex, with outspoken individuals on all sides. I tend to be middle-of-the-road and may use them here and there — but selectively. I should probably write a bigger post on my thoughts when it comes to generative AI soon.

    I wound up delving in, and through a lot of refinement and debugging (including a decent bit of learning Swift and manually rewriting bits where AI got the APIs it was trying to use wrong), I finally got something in a state that I was pleased with.

    A couple of caveats, though:

    • Authentication currently works with self-hosted sites and leverages the WordPress REST API through Application Passwords.
      • As it uses Application Passwords for authentication, if you’re using a security plugin such as Wordfence or others, they may be disabling Application Passwords on your website by default — you’ll need to re-enable it in their settings panel for this to work.
      • I’d like to eventually integrate it with WordPress.com’s REST API, but that’ll involve app keys and secrets for its authentication system, as WordPress.com doesn’t support the same implementation of Application Passwords that the open-source WordPress project provides (and also doesn’t support the authorize-application.php workflow that I’m using). So, maybe in the near future.
    • It can’t upload any media that your WordPress site isn’t configured to allow. So, by default, no SVG assets (as an example).
    • You can only authenticate to a single WordPress site. I’d like to eventually let you authenticate to multiple, and then you can change which one it uploads to in settings, but that’s not there currently (as I wanted to keep the UX simple).
    • I’m not a UX designer. At all! I made something functional that I thought looked … good enough? If anyone else would like to chip in, feel free! I’d gladly welcome input.

    How Using Generative AI / “Vibe” Coding Worked Out

    Honestly, it worked alright. There were numerous sequential prompts to develop an idea, telling it that its code was generating errors, and sometimes it would get balled up into a loop, and I’d have to go in and manually debug.

    But it worked pretty well to get a quick first pass built. I think I’d have had a much harder time with it if I wasn’t already comfortable with the system it was trying to integrate with, as well as other programming languages. Plenty of concepts translate well between programming languages; it’s just different syntax to implement them — so being able to leverage generative AI to take something I’m able to be very specific with and describe clearly and then build it out into a functional project was hugely beneficial.

    It feels like it’s shifting from the importance of being an expert in the programming language itself to being able to think through problems and use pseudo-code to describe the problem and solution well enough and let generative AI handle the implementation (even if it often gets it wrong).

    It’s an interesting time to be in software development, and I’m curious to see how else this sort of tech impacts the ecosystem. Just as StackOverflow and Google shifted the importance of “knowing” things to being able to find the answer, it feels like generative AI is going to emphasize the ability to think about a problem and find novel solutions and using developers to review code to polish it up for performance and security, instead of the nitty-gritty of implementations.

    Is this useful to you? Are there other ways that you’d like to be able to integrate things with your WordPress site but aren’t sure how to build a linkage? Let’s talk about the options in the comments below! 👇🏼

  • I’m Learning the Core Media Modal.

    Disclaimer: This is basically me stream-of-thought’ing things as I’m learning the Core Media Modal’s codebase.  It’s my scratchpad, and I’m merely making it public in the hopes that it may be useful to someone else at some point in the future.  Some things are probably very wrong.  If I catch it, I’ll likely come back and edit it later to be less wrong.  If you see me doing or saying something stupid, please leave a comment, so I can be less stupid.  Thanks!

    The media is written in Backbone, using the `wp.template` wrapper around Underscore templates for rendering.  If you want to really dive in depth, but don’t yet have a really solid understanding of Backbone, I’ve had several people recommend Addy Osmani’s book “Developing Backbone.js Applications” to me.  As luck would have it, it’s available for free online.

    When exploring the code in WordPress, it looks like it’s best to do the investigating in the develop.svn.wordpress.org repository’s src directory (yes, develop.svn matches to core.trac — basically because legacy reasons and not wanting to change core.trac’s url when they changed core.svn over to be the Grunt’d version), before the build tools such as Grunt have a chance to run Browserify on it #.  If you try to read through the code on the GitHub mirror, you’re gonna have a bad time, as that doesn’t have the `wp-includes/js/media/` directory with the source files in it.

    Browserify is a slick little tool in Node that bundles up a bunch of files, and puts them into a single file, so you can `require()` them in JS.  This makes them easier to work with in the source, and quicker to load in a browser.  WordPress has been using it to compile the Javascript for media since 4.2 (#28510), when the great splittening happened.  If this intrigues or confuses you, Scott Taylor has a great write-up on that ticket about the whys, hows, and whatnot.  It originally merged in at [31373] halfway through the 4.2 cycle.

    Oh, and all the actual templates that are parsed and rendered by the views are in `wp-includes/media-template.php`

    Okay, time to dig in.  (So that I’m not inadvertently writing a book, I’m going to split this into a series — but if you’d like to read them all, I’m dropping them in a tag.  You can find them all here.)