Shortcuts Tips: Techniques Behind the ‘Convert Text and Post to Threads’ Shortcut

Threads has taken the world by storm and established new playbooks, and although it isn’t my favorite social network, I’m enjoying kicking the tires and having a broader audience to share all my silly thoughts with again. That being said, since I’m still posting to first, I wanted an easy way to copy posts into Threads because it doesn’t support cross-posting from like other social destinations.

Enter Shortcuts: my jackknife of an automation tool. I ended up creating two shortcuts (Convert Text and Post to Threads’ and Open Threads App’) that work together to make it as easy as currently possible to get posts into Threads. Seeing as Threads doesn’t have any native Shortcuts actions yet, I had to get a little clever about how to move the data from point A to point B. Spoiler: They use the If’ and Match Text’ actions copiously. Let’s dig in.

Matching and formatting the alt text first

Shortcuts editor showing text getting matched with a regular expression.
Regular expressions are weird, but so powerful.

They say accessibility should be built-in right from the start and that’s true for my conversion shortcut, even if it wasn’t true for the Threads app at launch. For, gosh, probably three years now — yeah, ever since I started this blog — I’ve been diligent about adding descriptions for images that I post online. Image descriptions, or alt text, make the internet a better place for everyone. Folks who use screen readers to read the web deserve to know what is being shared in images, even if they can’t see them. Many social networks have a workflow for adding those descriptions — usually by tapping on a photo after it’s been uploaded — but Threads doesn’t support them yet. But since I write almost all of my social posts in Drafts using Markdown, the alt text can be isolated programmatically.

Markdown images are referenced using the syntax ![Alt text.](image-url.jpeg). So we use a Match Text’ action that deploys a regular expression to match any text that lives within a set of square brackets ([]) that is immediately preceded by an exclamation point (!). I’m no regular expression guru, but ChatGPT is. After some back-and-forth explaining what I needed and then testing, I got this expression: (?<=!\[)(.*?)(?=\]) which gets the text in the brackets, but not the brackets themselves. The Match Text’ action results in a list of matched items, so we’ll use that variable later to format the image descriptions just how we want them.

By having already matched the alt text first, we can manipulate the starting text without worrying about losing track of those descriptions later.

Accommodating for plurals

Counting matches and adding an “s” if there is more than one.
Four actions to add an s”.

Here’s a bit that I’m proud of having figured out. Being a stickler for grammar, I wanted to make sure that if multiple images were shared I’d be able to correctly label them as the plural image descriptions” as opposed to an image description”. By counting up the number of matches — after checking if there are any matches to begin with, which is handy to distinguish so later we can control what happens if there were no images at all — we simply add a Text’ action containing the single letter s” I need to make description” into its plural and set it as a variable.1

A text action showing the plural variable added onto the word “Description”
It looks funny, but it works!

Next, we need to format the matched alt text how we want it to appear in the Threads post. Still within the If’ block that controls what happens if more than one description is matched, we use a Repeat with Each’ action to number each description using its repeat index and put it on its own line so that a listener can differentiate between the descriptions when they’re read aloud. Key here is to use an Add to Variable’ action before it repeats so that it makes a list of the descriptions all within one variable. We’ll call the variable matched-descriptions”.

In the Otherwise’ part of the If’ action, we know that just one description was matched. We get that matching text — no reformating necessary — and it gets added to a variable named the same matched-descriptions” so that variable can be used either way.

Calling up the original matched alt text with no modifications.
Matched variable names for those matched descriptions.

Finally, we put it all together in one more Text’ action. Image Description” gets the plural’ variable tacked on so it’ll get that extra s” if necessary. The matched-descriptions’ variable containing the numbered descriptions on their own lines gets put below the label.

Setting the alt-text variable with extra line breaks.
But what’s all that whitespace for?

Creating an auto-threaded reply

The really cool bit in this step is how the alt text gets put automatically into its own threaded reply when it’s pasted into Threads. It turns out that you can hit the return’ key three times when composing a thread to create a threaded reply before ever posting the first one. We put those same three line breaks ahead of the Image Descriptions” label and — voilá! — we’ve easily separated the descriptions from the main post so that (1) they’re less annoying to people who don’t need to see them, and (2) we’re more likely to stick within the 500 character limit for each post.

Pasting the text into Threads, resulting in a post and a reply.
Threadin’ be easy!

Here’s that whole flow after matching the alt text from the initial text input until we set it all as a new alt-text’ variable:

Count, If, Repeat, oh my!

Even though Markdown is made to be human-readable (and I think clarifies what links should refer to when read as plain text), I want to be a good platform citizen of Threads. This means getting rid of the extra square brackets around linked text, and, of course, the text for Markdown-referenced images since they’ll be natively attached in the Threads app. But after all that we’ve done above, this should be a piece of cake!

Matching text with a regular expression, and then replacing the Markdown bits that we don’t want.
Massaging out the Markdown is comparatively simple.

A match and replace-filled piece of cake that is. We go back to our old friend Match Text’ with a new regular expression to match anything that looks like a Markdown reference to an image. This expression \n!\s*(.*) finds a blank line followed by a new line starting with !. Since I don’t start sentences with an exclamation point, I can be pretty sure that it’s an image reference. We replace that matched text with nothing, so it’s just deleted from the starting-text’ variable.

Next, we want to get rid of the opening square bracket around linked text, so individual instances of those are likewise replaced with nothing. For the closing square bracket, we actually do replace it with some new text. In this case, we find instances of ]( and replace them with a blank space plus the opening parentheses. That separates the parentheses-enclosed URL from its linked text, which looks a little more natural in Threads.

Note that we’re replacing text in a continuous line of Updated Text’ variables by just passing the result from one to the next.

To set up the actual final bit of text that will be posted to Threads, we use one last Text’ action and call up just two variables: converted-text’ and alt-text’ without a space between them. That alt-text’ variable won’t contain anything if there weren’t images in the input, but it will contain the necessary line breaks if there were, so we just place them right next to each other.

Opening the Threads app

We’ve done all this work, and we still haven’t even gotten to the Threads app yet. Thankfully, getting our newly-formatted text into Threads to post is quite simple.

Actions for previewing the result, copying it, and opening Threads.
Trust but verify.

But before we open the app, let’s make sure everything looks right. By adding a Show Result’ action before copying it to the clipboard, we can ensure that nothing funny happened during the conversion process. For example, if there was body text separating the referenced images, that body text might get lost in the migration.

If it doesn’t look right, you can hit the Cancel’ button when it’s showing the result to stop the shortcut from continuing and overwriting the clipboard.

The ‘Show Result’ preview with the option to cancel.
I like having the option to stop the shortcut if it screws something up.

If it’s all good, we hit Done’ and the shortcut copies the final-text’ variable to the clipboard and ends with a Run Shortcut’ action to run the Open Threads App’ shortcut. Don’t worry about passing any variables to that Run Shortcut’ action because we’re just going to use the clipboard anyway.

You might be wondering why we don’t just use an Open App’ action on its own here to open the Threads app. This next screenshot should clue you in as to why:

Actions to check the OS and open Threads.
Running shortcuts as functions are the best.

You see, Threads is an iOS-only app for now. You can, however, install the iOS app on your iPad where it’s pretty good in Stage Manager, and great for browsing alongside a Mac using Universal Control. By using an If’ action to check if the Device Details → OS type is iOS (Shortcuts, thankfully, treats iOS and iPadOS as the same operating system2) and only use the Open App’ action in that case, while doing nothing on macOS.

It’s because I like to use Threads on iPad as a companion to my Mac that I use that If’ block. I can run the shortcut on text from my Mac, and it won’t give me an error when the app isn’t installed. Instead, I just pop my cursor over onto the iPad, open Threads, and — thanks to the magic of the Universal Clipboard — paste the converted text into a new post. Or when run from an iPad or iPhone, the Threads app opens automatically, ready to go.

I don’t want to recreate that If’ block every other time I want to programmatically open the Threads app, so splitting it off into its own shortcut makes it useful elsewhere.3

And that’s it!

That wasn’t so hard, right? 😝 While employing relatively simple actions, these shortcuts use more advanced techniques to accommodate multiple scenarios, and are good to bear in mind as you build your own more versatile automations.

Get the shortcuts:

Let’s take a look at the whole flow in action:

You can reveal screenshots of both shortcuts from top to bottom below.

Show/hide the shortcuts

Convert Text and Post to Threads

It’s a honker.

Open Threads App

And a little guy.

  1. Bonus tip: You’ll notice that I set variables for a lot of things here even though they could be called up as Magic Variables without explicitly setting them. When they’re explicitly set and named, variables are way easier to use later because they show up in the menu of variables. You have to go back and hunt down Magic Variables where they are created in the flow of actions.↩︎

  2. To actually differentiate when a shortcut is run on an iPhone versus an iPad, use the Device Type’ parameter instead.↩︎

  3. Running other shortcuts as functions makes your automations more versatile, and can save you a bunch of time and hassle. By designing shortcuts as building blocks to be fitted together in this way, you don’t have to remember all of the actions needed to accomplish a task and string them together in every shortcut you need to do it. Less time to build a shortcut, and less opportunity for errors. It’s the whole point of making shortcuts to begin with! I might break out the section of this shortcut for counting items and making a word plural into its own function next.↩︎

Shortcuts Tips

❮ Previous post

7 Things This Week [#103] July 16, 2023

Next post ❯

Quick Tip: Use CleanShot X to Pin and Edit Any Image July 16, 2023