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 Micro.blog first, I wanted an easy way to copy posts into Threads because it doesn’t support cross-posting from Micro.blog 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
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
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
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.
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.
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.
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:
Simplifying Markdown-formatted links
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!
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.
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.
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:
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
Open Threads App
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.↩︎
To actually differentiate when a shortcut is run on an iPhone versus an iPad, use the ‘Device Type’ parameter instead.↩︎
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.↩︎