One tricky thing: do we track which #categories are included in the post itself vs. in pure metadata?
Assuming all are inline, things are simple: on publish or update, we always parse hashtags in the body. If a tag isn’t there, we delete its association with the post. If it is there, we associate it with the post.
If we also want to have pure-metadata categories, so we don’t have to clutter up a post with visible hashtags, then we need to track which categories are inline vs. metadata-only, so we know which ones to remove on update and which ones to keep. (And now this is getting complicated.)
It’s mostly getting complicated in the UI. Assuming the editor now has a “categories” field, we’ll need to keep it in sync between inline / editor hashtags and metadata-only tags. I mean, it’s unlikely someone would use both; I don’t want to cater to that edge case, but I also don’t want to exclude it if we don’t have to.
We might also follow the pattern we’ve laid out with other add-on post metadata, like #authors. Right now, you can add an author in the Rich Text (RT) editor, but not the Plain Text (PT) editor. In this way, we keep our underlying flexibility, but the client / editing UI guides users toward the correct input method. I think we can assume that the PT editor is for focused writing and inline metadata; the RT editor is for exact control over presentation and metadata. I’m not sure if that’s entirely correct, but I think I have to start there.
Continuing yesterday’s work, internal support for #categories is finished. The result is basically a lightweight layer on top of the existing hashtag-based system.
Now whenever you create or modify a post, or move it to a blog, we’ll parse out the hashtags and automatically create categories from them, as necessary. Categories store original information about hashtags, plus a user-friendly title (which can include spaces, punctuation, capitalization you want, etc.) and a URL-friendly slug. (You can see some of the underlying code here.)
In this way, they’re completely optional and unobtrusive by default. If you care to carefully manage your categories, with this new system, you’ll be able to do it. If you just want to tag a post occasionally, this won’t slow you down. And if your needs change as you write more posts, this will be there when you decide to organize things.
I still have more testing to do before deploying this change, and even then, users won’t notice anything new yet. But the groundwork will be there for us to tackle the management side next.
Working on support for categories today. There are a few functional goals we’re trying to solve with this:
- We can list all categories used on a blog
- We can quickly filter all posts under a certain category
- We can create tags with specific capitalization, Unicode characters, and spaces in the name
- We can associate posts with certain categories via existing plain text tagging system
The last point in particular is pretty tricky to solve; all other points are solved easily by adding some new data structures. I’m thinking we’ll just store three pieces of data for each category: a slug (e.g.
united-states), a title (e.g.
United States), and a normalized “lookup slug” that can be represented by a hashtag (e.g.
Then we’ll do some magic on the backend when creating or updating a post that parses the post and creates a new category automatically and / or associates the post with an existing category. That will allow existing posts to use this new categorization system. Then we might also support a new “silent” way of adding categories via a new API field, so you can associate a post with a category without inserting it into the body of the post.
Just some implementation ideas so far; we’ll see if this works in practice.
Just rolled out the largest update to Write.as I’ve pushed in a while. Most regular users shouldn’t notice anything different, but Team users will see it: a way to switch the entire interface / navigation from your personal Write.as account to your Team (as I’ve written about before).
These changes stretch across to the management side of the app, but it was all mainly for one reason: knowing what information to present in the editor. The “action context” (as I’ve called it internally) dictates what integrations the editor presents, tells photos where to go when uploaded from the editor, and determines what authors you can publish an article under (this feature is coming next). Since I was working in the editor anyway, I also made those other small updates announced today.
I probably could’ve designed this in a different way, especially to fit my fluid usage (tens of personal blogs, plus three teams, each with many blogs). But from an actual customer perspective — the people I’m building this for — I think the firm line between “individual writer” and “team member” is the right way to go. Plenty of people will only be writing for their team, for example. Hopefully this design fits them well (besides my own dogfooding, we’ll find out soon with early testers).
Next, as I mentioned, we’ll launch those author features. I’ll announce that more widely on the official blog.
Realized that we need a clearer line, UX-wise, between the personal writing experience and Team writing experience.
- Teams basically act as Users, with their own set of integrations, Snap.as uploads, drafts (eventually), and a pool of #authors that they can add to blog posts
- We want to severely reduce the chance of accidental posting to the wrong blog (don’t want a personal post ending up on the company blog!)
- We can optimize the editor and backend management flow if we know you’re in “team mode” instead of “individual writer mode” — like working at the office vs. writing at home
Concretely, we’ll have a way for users to switch between their personal account and any team they’re a member of, like they already can on Snap.as.
This also furthers my assumption that collaborative work on our platform is different from writing as an individual — something I don’t think many publishing platforms assume. With time, we’ll see how that assumption holds up, or if the improved Team UX / navigation bleeds back into the individual experience.
Yesterday I made a ton of progress on new Team features. The biggest one is the ability to add outside contributors, so you can show authorship information on posts without actually creating accounts for each author.
Besides that, I updated the Snap.as API to support Team uploads, and updated the Classic editor to do the same — so if you have a Team blog selected in the editor, your photos will automatically upload to your Team’s collective photo storage, instead of your personal account’s storage space.
These features should go live today or tomorrow!
#dev #teams #authors #contributors
I’ve had a lot of trouble modeling the Team Member / Author roles I recently came up with to support everything we need to on collaborative blogs. Unlike Users, Posts, and Collections (blogs) that I can understand from one perspective, these new concepts need several perspectives to fully understand (and model correctly). At this point, I think I’ve finally worked it all out:
From a data perspective, these are distinct objects with a one-to-one relationship. A Member is (aside: always backed by one User, and) always associated with one Author — but an Author can exist without an associated Member (if the Member was removed from the team, the User was deleted, or it’s an outside collaborator).
From a user management perspective, team admins will always interact with either a Member-Author or just an Author object. But the complexity will be hidden and they’ll look the same to the end user — just in different states, really.
From a user (writer) perspective, a team writer will always interact with an Author object. They’ll only be concerned with who is authoring a post.
#dev #teams #authors
Author functionality is coming along! Now it’ll optionally display at the top of a post, if it has one or more authors set.
#dev #teams #authors
At the end of the day yesterday, I added another layer of spam prevention to user registrations, powered by Akismet. Over the last 15 hours, it’s blocked 18 bot signups that slipped through our own filters (which blocked 587 bots over the same time period).
To implement this, I forked a Go library for the Akismet API, and updated it with Go module support, unmerged PRs, docs improvements, and tagged releases. Soon, I’ll also add this spam prevention to WriteFreely — I think many open instances will appreciate it.
Continuing yesterday’s work on “outside contributors,” some new perspectives:
Now, there are three “person” concepts in Write.as: User, Team Member, and Author. The first two, User and Member, are private structures that primarily hold permission data and contextual settings (User: password + email for the platform; Member: role + email for the team).
An Author, however, is a public structure meant to hold publicly-known information, like a bio and post authorship. Most blogging platforms don’t make the distinction between an Author and a User like this. But this allows us to minimize data collection and eliminate unnecessary work for writers (a single-user blog doesn’t really need an author bio, because the blog is the bio).
I often think of our UX like various gentle slopes of increasing friction and weight — from simplicity to complexity, or zero to full data collection. With this new user structure, we can maintain a gentle slope from writing alone to writing with others. The experience for a single blog author doesn’t change at all — the added work only shows up at the precise moment someone decides they want to write with others, and specifically, that they want some kind of public authorship known to readers (that is, we’ll still enable you to have a multi-author blog that conceals the identity of individual writers).
#dev #teams #ux