Big ideas about the web.


  • Screenshot of the album's front page

    About three years ago I had the idea to build a replacement for Flickr. The main reason was that I wanted a place to store videos, mostly (as I was and still am in the process of digitizing old VHS home videos, which of course will never end), from which I could also easily share them. And while I was at it, I might as well just use that place to store my photos too, and consolidate all my sharing needs.

    Over a year later, after a couple of failed attempts at using different prepackaged platforms, I started building it as my first real Drupal 8 project. Of course.

    But despite all the awesomeness in Drupal 8, and above all the promise of core media, the road to getting all my requirements into place would be very long.

    Over the course of the next few posts I’ll cover all my requirements and how I solved them. Eventually, I’d like to clean up my code enough to be able to make it available on

    I wanted the system to:

    1. Allow multiple uploads
    2. Collect and save EXIF data
    3. Not make me worry about disk space
    4. Allow private albums and media
    5. Allow select guests to view any private content
    6. Allow easy importing from Flickr

    Multiple uploads

    Because I wanted to maintain perfect independence between albums and media, I couldn’t just add a Plupload widget to a node’s multi-value image field and be done with it. This for a few reasons:

    1. I wanted to take advantage of the media module (which wasn’t yet in core when I started the project, but the transition from Media Entity was seamless). This would be enough of a reason, but I had a few more.
    2. I wanted to be able to add different types of media to an album.
    3. I wanted to be free not to associate media with any album at all.

    The idea of uploading media one at a time was unthinkable—especially not after years working with Flickr’s very smooth upload experience. The only thing that would make sense would be to have an upload process that creates a single media entity for each item uploaded, and that would allow media of different types to be uploaded at the same time.

    Chance was that just a few weeks before I started the project someone had tried to tackle exactly the same issue, with the Media Upload module. I tried using that for a while, and I contributed some ideas and a few code fixes, but—long story short—it wasn’t really doing it for me, and rather than trying to hijack someone else’s plans I decided to build my own upload module from scratch. I know, not very community-oriented, but my requirement was for more than just an upload form.

    The module provides a two-step form: one step for the upload itself, and one for the details that will populate the media entity.

    The upload step uses a Plupload widget by default, because as much as I dislike depending on JavaScript it would be tough to make an HTML-only form work across various browsers. (Not that I’m going to use anything other than the latest Safari, but I’d like to be mindful of others if/when I publish the module.) This way I can also take advantage of a few more of Plupload’s perks, particularly the ability to break up large files.

    On submission, the form saves the uploads as temporary file entities and associates them with media entities. The reason I don’t just work with temporary files and entity stubs is that I wanted to display thumbnails in the next step, and as much as I tried I couldn’t find a way to make it happen unless I saved the media entities first. I will get back to that at some point and see if I can get Drupal to produce the thumbnail before saving the entity.

    To try to prevent duplicate files, I’m using the File Hash module, which does a pretty good job at figuring out which files already exist in the system, thus which media entities should not be recreated.

    The details step is a megaform that displays a few fields for each media entity created:

    • Thumbnail (just a markup element)
    • Title
    • Description
    • A choice of tags from my “Subsets” vocabulary.
    • The audience selection, which is a custom field to decide whether a media entity should be public or private. This is less granular than Flickr’s privacy settings, but I think it’ll do.
    • A “Keep” checkbox that can be unchecked if the user doesn’t want to actually save the media entity, so the entity will just be deleted. This is where it would be better if the media entities hadn’t already been saved, but presumably very few entities will not be kept after being uploaded.

    There are a few fancy things happening here:

    • The title and description fields are pre-filled using the EXIF title and caption data. If there is no title data, the file name will be used (which is kinda meh, but it works).
    • The subsets and audience settings are also pre-filled using machine tags.

    Submitting the form triggers a batch operation that takes care of saving the media entities with the new information and deleting those whose “Keep” setting was unchecked.

    Room for improvement

    Each piece of the details form is hard-coded to match the structure of the media form, and doesn’t use a custom form view mode yet. When I started building the form it was early enough in my Drupal 8 game that I hadn’t yet figured out how to pull up a custom entity form. I have since been able to do that in a different part of the system, so eventually I’ll go back and rebuild the details form in a more future-friendly way.

    Collecting and saving EXIF data

    EXIF data is so variable and unpredictable that I didn’t just want to create a new field for each record. Instead, I wanted something more flexible. I ended up creating a basic field structure using Paragraphs (which I still find very clunky and unpleasant to use):

    • Each media entity gets a paragraph field, whose values can belong to three different paragraph types:
      • Single-value metadata, used for any string-based values
      • Date-based metadata
      • Multi-value metadata, such as keywords
    • Each paragraph has two fields:
      • A string field for the label. This doesn’t make me too happy, since the labels are repeated over and over again in the database. I’d like to convert this to a taxonomy-based setup in the future.
      • A value field whose type depends on the data type: string, date, or multi-value string.

    This setup makes it a bit awkward to do stuff like sorting media by EXIF creation date (more on this later), but it can be done with a good dose of aggregation in views.

    To retrieve EXIF values from images I had a couple of different solutions: one was the EXIF module, which is very opinionated and outputs data in a very nicely organized array; the other was [File MDM][mdm], which is more complex and would have required me to massage the data it retrieves a lot more. I chose EXIF mostly because I was impatient and just wanted to get it done, but a different requirement later on forced me to also install File MDM, so eventually I’ll go back and rearchitect this part of the system to avoid having two modules that do pretty much the same thing.

    When I retrieve keywords, anything that matches my patterns for machine names (audience and subsets) gets processed accordingly, while everything else gets saved as a keyword.

    Room for improvement

    Frankly, I’m still not sure if using Paragraphs the way I did is ideal. While it does make metadata Views-friendly, the fact that metadata labels are stored as text fields isn’t as slick as I’d like it to be. That’s also why I haven’t spent too much time refining the display of metadata.

    The way machine tags work is largely hard-coded to work with my specific setup. It would be fun to make it more generic and build a proper API out of it.

    Up next

    How I’m dealing with disk-space hunger and what I’m doing to provide reasonable access control.

  • A new module for Drupal 7 has just come out of our pantry, and is now live on

    Formatted Titles allows to change the type of the title field in an entity’s edit form from simple text to formatted text. When the entity is loaded, its title is then replaced with its formatted version.

    In a view, Formatted Title tries to replace all instances of an entity’s title, even when the entity is being brought in through a relationship.

    After enabling the module, go to admin/config/content/format-title, where you can enable formatted titles on a per-entity, per-bundle basis. You can also choose to restrict the HTML output of the module even further.

  • After about three years, we decided it was time for major renovation around here, and we decided to go all in. Not only new colors (which we feel better fit our personality), but also a new font (we have a history with Proxima Nova), and better responsiveness (responsive web design was only in its infancy when we designed the previous version of this website, and we were so busy being responsive for everyone else that we left our home behind). And not to forget the sweet kitchen-themed icons Francesca Komel designed just for us.

    This renovation has also given us a chance to play with new toys, such as CSS’s Flexible Box module, SVG images, and some complicated (but very fun) Sass mixins.

    Also, we added a Resources section, which hosts a growing repository of information for clients, as well as fellow designers, developers, and drupalistas.

    Last, but not least, we’ve decided to respect the original spirit of the web and get rid of our copyright. Now most of our content is available under a Creative Commons license.

  • Two weeks ago we launched the first phase of the new website of the Mid-Atlantic Popular & American Culture Association. It’s part of a larger project that will run for the next few years.

    An outline of the general goals and updates on the current state of advancement can be found on the project’s page in our portfolio.

  • After blogging and e-mail, let’s tackle proper behavior in social networking. While I do think everyone should feel free to be him/herself (within a reason, always) when acting on Twitter or Facebook on a personal capacity, I become pickier when it comes to business.

    Some may want you to believe that social networking for your business is part of a broader marketing strategy. While I think that can be true to some extent, I believe that what you write and do in social networks falls squarely into your content strategy, and should be consistent with it. It would make no sense to plan a content strategy that’s careful and considerate, only to blow it all off on Twitter.

    What I’m giving here, as usual, is not advice on what content to write, which depends on your specific strategy, but on how to do (or not to do) certain things on various social networks. Some of this advice can equally apply to Facebook or Twitter or Google+, and some is aimed at promoting, preventing or correcting behaviors on specific platforms.

    Be human

    You’re a human being, so act like one. Your content should be always fresh and new, even when you’re promoting a product or service. Copying and pasting old tweets or statuses will add to the ambient noise, and will do nothing to your brand (except making it look like a spambot).

    Of course, there are cases in which it’s okay to have a bot help you. Specifically, when you have content on your website that you need to publicize on various platforms. In this case, using a service like to poll your website (via RSS) and feed the results to Twitter or Facebook will simplify your job—especially if you publish content very often.

    One more human thing to do is to engage with your audience or with the people you follow more than by simply retweeting other people’s content. Establish your brand, your identity and your personality by creating your own content—but again, make sure it matches the personality that you outlined in your content strategy.

    Be cool

    But again, be cool as a human, not as a machine. This includes:

    1. when you post something on your Facebook page (or even on your personal profile), don’t “like” it. It should be quite implicit that you like what you just posted, but if you need to add something to it, just add a note before posting, or a comment after posting. If you posted something you didn’t like, just say so
    2. thanking every one of your followers for following you is something middle schoolers might do on MySpace. You don’t need to do that, as it just adds to the noise. Plus, people don’t follow you to do you a favor, they do it because they’re interested in what you have to say.1 The best way to reward your followers is by publishing meaningful content
    3. likewise, sending phatic cues (like an isolated hello) to fellow tweeters, particularly those you don’t know personally or you haven’t previously interacted with, doesn’t just grab their attention (which I assume would be the desired outcome), but it will most likely get you reported as a spammer
    4. don’t rush things. I know, we’ve all been there: the early-morning tweet that we just have to respond to while we’re still uncaffeinated, only to go “D’oh!” right after we send our response off into the world. Sure, you can always delete it or deal as gracefully as possible with the consequences, but prevention is the best course of treatment.

    Be consistent

    If it’s not just you, but you have a bunch of people managing your social networking, make sure everyone is on the same page. Come up with guidelines that everyone should follow in order to prevent apparent schizophrenia. And, as always, accuracy and attention to detail go a long way.

    1. Unless they’re spammers, in which case they follow you just to get in your way, and you have every right—nay, a duty to report them on the spot. ↩︎