Managing Composer Repositories via the Command Line

I’m in the process of a top-to-bottom restructure of this site: everything from the design, to the code architecture, to the content, to the deployment strategies. One major piece of this work has been integrating the Composer-based workflow I’m so familiar with using on the large enterprise client sites that I’ve worked on into my personal toolset.

Composer is an amazing tool for PHP, and if you aren’t using it yet for WordPress development, I highly encourage you to stop reading this post right now and go check it out. I’ve given a talk about it at several different WordCamps in the past two years, and there’s lots of great content on the web about what it does and how to integrated it into your workflow.

What I want to write about today, though, is a very small part of Composer: the config command. Or, more specifically, the config command as it pertains to non-Packagist based repositories, and how you might consider structuring your composer.json file going forward.

Manually Adding Repositories

Let’s imagine for a minute that you started reading this blog post, didn’t know a thing about Composer, and that you went and studied up on it before coming back to this blog post. First, thank you for your dedication! Second, you probably learned the following bits of information:

  • The composer require command, by default, visits Packagist.org to find an instance of repositories that match the name you provided. So, if you ran composer require wp-cli/wp-cli-bundle --dev, you’d get a copy of the full WP-CLI tool and all of its bundled commands, because it has a reference on Packagist.
  • All packages require a valid composer.json file with, at a minimum, a name entry in order to be installable (well, sort of, but I’ll talk about that later).
  • You are required to give your local Composer project more information if you need to install packages which are not referenced on Packagist.

Assuredly, you learned a ton more information than this. But, in terms of installing a package, those are the key details you need to know: if it’s not on Packagist, you need to tell Composer where to find it.

How?

Here’s an example

Let’s say you wanted to install anything that’s in the WordPress.org plugins repository. This is the bare minimum you will need in your composer.json file:

{
  "repositories": [
    {
      "type": "composer",
      "url": "https://wpackagist.org"
    }
  ]
}

This block of JSON says to Composer, “Hey, the dependencies for my project are located both on Packagist.org and on WPackagist.org, which is a Composer-based mirror of the WordPress plugins repository. Once that’s in your composer.json file, you’re free to install any plugin in the WordPress repository by using the custom prefixes that WPackagist uses. For instance, if I wanted to install Jetpack, I’d run the following command:

composer require wpackagist-plugin/jetpack

I’d automatically get the latest version. Note, though, that this example is a little contrived, because Automattic wisely contributes Jetpack to Packagist, so the additional repository is not needed, but not every company or developer does this. You could run composer require automattic/jetpack instead and get the same result.

Another Example

Let’s say you’re like me, and you’re working on a full rebuild of your site. Maybe you’re making a new theme, or a new plugin, or both, and are not yet ready to put your repository on Packagist (or, you’d argue that you don’t need to). You can add the URL to your Git repository right in your composer.json file:

{
  "repositories": [
    {
      "type": "composer",
      "url": "https://wpackagist.org"
    },
    {
      "type": "git",
      "url": "https://github.com/jmichaelward/board-game-collector.git"
    }
  ]
}

In this case, if I run composer require jmichaelward/board-game-collector:[email protected], I’ll get the latest version of my Board Game Collector plugin’s develop branch. You might start to see why this is useful.

Automatically Adding Repositories

A Small Problem

There’s something that the Composer documentation and online content that I’ve seen which talks about it doesn’t necessarily cover.

First, there’s no requirement which states that a package’s name needs to be the same as its repository. In the previous example, my repository is at jmichaelward/board-game-collector, but my Composer package’s name could just as easily be jmw/bgc. I can’t reliable use the repositories list to cross-reference the packages in my require object.

Second, there’s a Composer command that lets you add repositories. Consider this example:

composer config repositories.0 git https://github.com/jmichaelward/board-game-collector.git

This command automatically updates the repositories array in my composer.json file! No more need to open my composer.json anymore, I can just achieve this update directly from the command line, right?

Well, not exactly. Note this section of the command: repositories.0. That says, “set the 0 index of my array to this value”, where “git” is the type of repository, and “https://github.com/jmichaelward/board-game-collector.git” is the URL. If I already had a zero index, such as the WPackagist repository in the earlier examples, it would get overwritten.

A Solution, and a Proposal

The composer config command will let you create a key-value object instead. Consider this alternative:

composer config repositories.jmichaelward/board-game-collector git https://github.com/jmichaelward/board-game-collector.git

This converts the repositories array in your composer.json to an object, where each key is the name you provided in the command (in this case, jmichaelward/board-game-collector), and the values are the type and URL for that repository.

If we use the command line to add all of our repositories, we wind up with something that looks more like this:

{
  "repositories": {
    "wpackagist": {
      "type": "composer",
      "url": "https://wpackagist.org"
    },
    "jmichaelward/board-game-collector": {
      "type": "git",
      "url": "https://github.com/jmichaelward/board-game-collector.git"
    }
  }
}

The benefit here is two-fold: first, we gain access to the repositories we need to install the packages our project requires. But second, and more importantly, we get a direct map between the package names in our require block and the repositories they’re linked to.

This second benefit could not be overstated. By setting your repositories up as a key-value object instead of an array, you help other engineers who want to quickly look at the repositories for your project’s dependencies. They can easily see which packages map to which URLs, then access those URLs directly. It’s a small documentation touch, and something that I’m looking to do more and more of in my future projects.

Summary

Composer is an amazing tool for managing PHP project dependencies, but sometimes the documentation isn’t the greatest, or best practices aren’t well-defined. Documentation is one of the most important parts of building any projects, as it can help others who are looking at your code in the future, or it can even help your future self as you question what you did many weeks or months ago.

Composer’s config command provides a lot of flexibility for setting up your composer.json file. I highly recommend giving it a look and learning other ways it can help you streamline your workflow when managing dependencies.

And What a Week It Was

Boy, what a week.

With everything going on nationally and globally, I suspect I’m not alone when I say it’s been really challenging to stay focused. I would expect that to be the case for the next several weeks as more of us stay home and learn how to adapt to a remote lifestyle. In hindsight, my decision to seek new opportunities couldn’t possibly have come at a worse time, but I am extremely thankful that I was able to move at a slower pace and work on my own personal growth during what was undoubtedly one of the most uncertain weeks in recent U.S. history.

With all of that said, I wanted to take a moment to discuss some of the things I worked on this past week, and document additional areas of focus for this week, as well.

Learning Python

Between keeping up with the news and taking some well-needed time off, most of my attention has been focused on learning Python. During the weekend of March 7th & 8th, I visited my local library, and examined their computer programming collection. Sadly, the amount books they have on hand are few, and most of them are 5+ years old, but one book that I thought would be useful to help solidify the basics was Automate the Boring Stuff With Python by Al Sweigart. Thankfully, I was right! Sweigart’s book covers all of the basic data structures in Python – strings, lists, tuples, dictionaries, and objects, then spends the bulk of the rest of the book showing the reader how to write some basic scripts to accomplish a series of tasks, such as parsing and modifying spreadsheets, scraping web content, scheduling tasks and opening programs, and more. He very clearly indicates that the examples are intentionally not the cleanest, least complex way to structure one’s code to accomplish the task, which works fine for me, because that’s where my past programming experience comes into play.

While reading Sweigart’s book, I started a repository for studying Python, but quickly came to realize that simply copying some of the examples wasn’t going to be sufficient for me. More on that later.

The finest benefit offered by my local library, which I also just learned about that same weekend, is that one’s library card grants them free access to all of the instructional videos on Lynda.com (now LinkedIn Learning)! I highly recommend checking to see if your own library offers this benefit, as it has quickly become my go-to resource for learning Python basics. Thus far, I have completed two tutorials: Python Essential Training by Bill Weinman and Python: Design Patterns by Jungwoo Ryoo. These two courses, along with the aforementioned Sweigart book, and my college textbook, Python Programming: An Introduction to Computer Science, Second Edition by John Zelle, have given me enough foundational knowledge to begin tinkering.

Toward that end, one project I started last week and will continue to explore this week is a custom Slack bot written in Python that will integrate with the BoardGameGeek API. If you’re interested, you can follow along with this project on GitHub.

Self-Care

While I’m aiming to learn as much as possible while I seek out my next gig, it wouldn’t be a proper break if I didn’t take a little time for myself, too. In addition to learning a new language, I also played the role of homemaker, which also served as a nice diversion from the news. I went shopping for supplies. I cleaned the whole house, and checked off some seasonal cleaning tasks of the list. On Friday, I baked a lasagna, which we got to enjoy for the remainder of the weekend. And I dug back into a couple of games on the Switch that I hadn’t played in awhile: Celeste, which is absolutely breath-takingly amazing, and Stardew Valley, which I think I’m finally ready for given the slower pace we’ll all be living at in the coming months.

At the library, I also digitally rented Bob Odenkirk’s book of short stories, A Load of Hooey. My partner and I took a nice walk around Lake Phalen. We invited a friend over to play board games on Saturday, and though it was just the three of us, I realized it should be the last time we have anyone over for a bit.

What’s In Store For This Week?

This week, I’m going to continue familiarizing myself with Python via the aforementioned Slack bot project. I’m also looking to do some work on this website, and am planning on exploring some front-end technologies that have come out in the past few years, particularly CSS grid. Also, because much of the U.S. is starting to work remotely for the first time, and/or they’re already remote and are dealing with our new isolated social contract, I’ll be publishing a Zoom link on my Twitter account at 6pm CDT each weekday in the forseeable future so my friends and acquaintances can have a place to connect and socialize.

It’s a strange time, but I’m making the most of it, and I hope anyone who is reading this is, too.

To New Adventures

Today marks my final day as a Senior Backend Engineer at WebDevStudios.

The motivators for change sometimes come in a rush. More often, as in my case, they drip in slowly, their positive or negative impacts affecting the balance, until one’s cup is full with a bittersweet drink — a meaningful goal accomplished, a lifelong friendship forged, a valued colleague departed, a role ever-evolving.

I have so much to be proud of from my time working at WDS. The last year alone has been particularly full of rewarding opportunities, including:

  • Open-sourcing my first library to promote object-oriented programming in WordPress.
  • Speaking at three different WordCamps.
  • Curating, hosting, and occasionally presenting at internal “Lunch & Learns”, our monthly continuous education program.
  • Giving in-depth code reviews and helping mentor junior engineers.
  • Developing my first set of editor blocks, as part of a completely headless publishing workflow.
  • Being entrusted to build relationships and lead the engineering team for one of our largest clients.

I’m proud of the work my colleagues and I have accomplished in the past three years, and the last year in particular has been one of incredible growth. It’s been so rewarding to see the leaps and bounds we’ve all taken to make ourselves better engineers, better project managers, and better co-workers.

The flip side of all of this, of course, is that as I’ve taken these additional opportunities onto my plate, I’ve in many ways been getting further and further from the thing that’s gotten me here: my love of computer programming. And, in particular, as the WordPress programming landscape continues to evolve — WordPress as the client, custom editor blocks written in React, static sites — I’m left with two distinct feelings. First, and most importantly, that there is a broader world of software development that I’ve been missing out on by staying exclusively within the WordPress ecosphere. And second, that my time spent away from my IDE is also time spent away from my absolute favorite part of my career.

With that realization, I’ve come to the difficult decision that it’s time to try something new, to grow once more, and to potentially submerse myself in completely unfamiliar territory: a new language, a new environment, a new community. I don’t know what this means just yet, by my desire is clear:

  • I want to spend the majority of my day writing software.
  • I want the opportunity to learn more languages.
  • I want to work in a physical office again, at least some of the time.
  • I want to continue to grow in every possible way that I can.

In my last entry, I wrote about intentions. Leaving one’s job without having something else lined up is one of the scariest things one could possibly do, but sometimes it’s absolutely necessary in order to enact positive change for one’s self. I have applications in at a few local companies with roles that sound fun and challenging, and in some cases their development stack is something completely outside of my past experience. That’s not surprising, either, given that my past experience to date has been enterprise WordPress development in an agency setting.

My intention for the coming weeks is to rediscover my love of computer programming; to study, and tinker, and create during the day, and also spend time researching, applying for, and interviewing with companies that align with my values and career aspirations. I’m planning on reflecting a bit more about what I’m looking for and sharing updates about what I’m working on during this transition, so keep your eyes peeled for updates to this space.

It’s an exciting time. It’s a scary one, too. But, I enter this transition feeling optimistic and knowing that I’ll become a better engineer as a result of it. And, above all, I’m thankful for my colleagues and the leadership at WebDevStudios for the opportunities they’ve given me. I’m hopeful that I’ve left things in a better place than when I got there, and that we all prosper in our next adventures. I can’t wait to see what’s next.

On Goals and Intentions

This morning, I sat down at the kitchen island and drafted up some notes of reflection. I’ve thought a lot about how I’ve spent my creative focus during previous decades (drawing, playing music, learning computer programming), and the various ways I’ve chosen to pass the time: video games, board games, listening to records, watching movies, etc.

Awhile ago, I made a conscious decision to set the focus for this blog to be about topics pertaining to my professional career. In some ways, that’s been great, because focus in in part what I require. In others, it’s left me feeling like I haven’t given myself a true outlet to talk about dreams and goals that may not have much bearing on my professional self, but which carry a lot of weight around who I am and what I want out of this life. I don’t write enough from either perspective to bother making the distinction, so for today at least, it makes sense to just jot down what I feel for the purpose of writing at all.

I had a great conversation with my friend Michelle last week about goal-setting. I mentioned how it was mid-January, and I hadn’t yet written any posts to reflect upon my goals from last year. I felt in some ways that I’d accomplished a lot in 2019, but that things quickly got off course in June after I started leading a huge client project at work and signed up to give more and more unique presentations at WordCamps and internal continuous education sessions.

Michelle told me that she prefers not to set goals, but that instead, she likes to set intentions that can help guide her focus and behavior for a given period of time. It really struck me as a better way to go about things. On the one hand, setting and achieving a measurable goal gives you great information about your quantitative progress over a span of time. “I set out to read 12 books, and I did it!” On the other, it exposes to you a number of serious shortcomings: your inability to plan, to adapt to changing conditions, to be realistic about what you can actually achieve.

Mostly, it leaves you feeling bad, either because you didn’t accomplish the thing that you set out to do, or maybe because you did accomplish it and hated every minute of working toward something you don’t actually care about.

Here’s a truly dumb, real-life example from last year: I wanted complete the 10×10 challenge, something the board gaming community labels as playing ten games ten times each. And I did it (a real achievement, obviously)! Ultimately, though, I disliked everything about it, particularly as the year-end got closer and closer, and I had a dedicated list of games that I needed to keep playing, regardless of whether I actually wanted to.

And, while I think that’s not a very meaningful example, I think it can be applied to other goals we beat ourselves up over. For instance, I set out to apply to one out of town WordCamp. I applied to four WordCamps total last year – three of them out-of-town – and was accepted to three. Goal accomplished! The problem is that I think I was so eager to prove to myself that I could do it, that I didn’t necessarily consider the ramifications of it all: the time it takes to prepare a talk, the time and expense of travel, the focus it can take away from other parts of your life. I had a wonderful time speaking at each of these conferences and, in hindsight, was really glad that I did it. But, at the end of the day, I don’t know that it furthered my own vision for whatever it is I’m setting out to achieve with my career or that it brought me closer to self-actualization of any sort. It was a thing that I arbitrarily set out to do, I did it, and now what?

Intent, however, is different, though it of course has its own sets of trade-offs. Let’s presume one of my intentions for this year is to perform more acts of kindness. How do I measure it? How will I know I’ve done it at the end of the year? Shouldn’t I instead set a goal of sending, say, ten thank you cards by December, or purchase five random gifts?

The distinction in my mind centers on how reflecting on the goal or intention happens. If the goal is to send ten thank you cards over the course of a year, you might revisit that goal every couple of months to see how your progress has gone, and realize that you’re either far behind on your goal (“I better send more thank you cards!”), or you’re far enough ahead that you can relax for awhile (“I already sent eight thank you cards! I can coast for a bit…”). Intention, however, can serve as more of a guiding principle (“Anytime someone invites me over for dinner, I want to follow up by sending a handwritten note.”). It accommodates for failure without needing to beat yourself up too much over that failure. It’s measurable in that you can still take stock in how well you adhered to that intention and, perhaps, whether it converted from intention to habit (“I intended to send thank you cards frequently, and now I do it all the time.”).

Perhaps this isn’t an ideal example, but it makes sense in my head, and that’s really all that matters, right? :)

What Are My Intentions?

This is the part upon which I’m still processing, and also where I’m probably also giving in to the normal focus of this blog. That said, I do want to comment a bit about the last year with the purpose of trying to think through this all out loud a bit.

First, something that I didn’t explicitly set as a goal in my post last year but that I’ve been working toward is enhancing my online privacy and either taking ownership of or redistributing management of my data. In 2019, I completed every step of the Online Security Checklist, which funnily is 90% “leave Google”, but that’s what I did. I canceled my Google G-Suite account and stopped using Gmail, Google Calendar (much to my partner’s dismay), and Google Maps. I closed my Dropbox account, because I feel the service they provide is encroaching beyond what I signed up for. I switched to Firefox, and use DuckDuckGo as my primary search engine. I use Apple Maps now which, although Apple has plenty of their own privacy concerns, I’m okay with because it’s not all about leaving one big service for another, but rather, no longer consolidating all of my eggs in one basket.

I also bought a Linux desktop, with the long-term intention of switching to Linux for work, too, if I find that I can work within that ecosystem. It’s a huge shift for me, but I’m enjoying the challenge of learning how to work in a new environment, just like I did when I switched from Windows to a Mac.

Second, I intend to slow down. I struggle a lot with indecision, in part because there are so many things I want to do that I wind up doing nothing at all. For instance, I’ve been wanting to write this blog post all week, but I’ve also wanted to get familiar with this new computer, help my friend upgrade his WordPress site, read a book, play some video games, play some board games, follow the historic news of the week, engage with the community, write e-mails to friends and family, attend bar trivia with my partner, go see the new Star Wars (I still haven’t), do my laundry… the list goes on and on. I need to learn to accept that I can’t do everything that I want to do. Instead, what I can do is dedicate my focus toward achieving something particular on a given day, and start there. Today, I want to publish this blog post and go spend time with my friends and share in the pride of seeing their teenage nephew play a show at a local rock club (I remember my first rock club show!).

In other words, I can be aware of all the things I want to do and make incremental progress toward doing them by setting a focus for the day. Checklists are great – my partner uses them all the time.

Third, I intend to write more. Not necessarily on this site, but I think taking account of how I’ve spent my time each day will give me a better sense of whether I’m on the right path. I’ve read stories from friends who have kept gratitude journals, and I think that’s one excellent way to take stock. It’s so easy to get caught up in the day-to-day that it’s easy to lose sight of the big picture, but writing it down helps bring guidance and clarity. It’s a good reminder to myself, too, that not everything needs to be for public consumption. Sometimes just writing something down for the sake of relection brings about some level-setting and accountability.

Lastly, I intend to be more present. That means getting out of the house more, showing up for events, supporting my friends, and engaging in more conversations. It means putting the damn phone away. It might mean volunteering. I closed up shop when things got too demanding for me last year, and escaped into board games and screen time. It resulted in less investment in personal projects, less reaching out to make plans, less involvement in my community, and I’ve abhorred every minute of it (I mean, almost… I do love board games). I like talking to people, making friends, learning how to solve problems, and being helpful where I can. I don’t want to close myself off to potential friendships and new experiences just because I’m tired from a long day or things aren’t going just quite right at any particular moment. It’s important to set this intention and follow through as much as possible, because presence is supportive, and being supportive leads to all sorts of opportunities.

I’m grateful for my friendships, online acquaintances, and colleagues who helped pave the way for where I am today. This year, I intend to return the favor.

A Quick Developer’s Guide to the WordPress Block Editor

TL;DR: You can skip all the exposition below and click here to get to the good part.

If you’re anything like me, you’re interested in the ever-changing landscape of web development, but your day-to-day work precludes you from digging too deeply into a topic during working hours unless a project necessitates it. As such, most of your study time happens during nights and weekends, either via focused study, exploratory projects, or a combination of the two. You might also happen to be interested in a lot of different topics, so the investment of digging into and not only acquiring but also retaining that knowledge is significant.

In the past year, I’ve spent some portion of time learning (or re-learning) the basics of Swift, Craft CMS, Laravel, React, Symfony Components (Console, Process, etc.), Bash, MySQL, NPM, converting XML to JSON… the list goes on and on. In some cases, I have a working app; in others, an unfinished idea. In most cases, though, my trials are loose collections of notes and throwaway code to try and understand various concepts, or to play around with a reusable approach to solving a problem even while I’m trying to understand the concepts behind the solution.

The WordPress Block Editor, released into core with version 5.0 in December of last year, has been one such challenge. I defined learning how to create custom blocks as a goal of mine in 2019, and tinkered with some reusable approaches to it early in the year. Still, most of my work this year has been related to developing back-end solutions, be they custom migrations, supporting existing architectures, or establishing approaches to object-oriented plugin development. My evenings and weekends had left time for tinkering, but most often, I was either preparing or rehearsing a presentation, spending time with friends and family, or just trying to unwind from a challenging day’s work.

To that latter point, this summer, I started working as a lead on a big project at WDS that fully incorporates the block editor into a publishing workflow. In the long term, this means I’ll have far more opportunities to work with the block editor, but shorter-term, it has meant integrating work that already exists and, as a project lead, doing more planning and strategy than actual development.

But I digress…

During the first weekend in November, I attended WordCamp US in St. Louis, MO. I sat in on some beginner sessions and workshops about the block editor to refresh and verify the knowledge I already have, and I chatted at length with one of my colleagues about his interest in JavaScript development and in the block editor in particular. It was a fun and exciting trip, capped off via a two-day summit with my client and their agency partners about our plans for the next six months.

Upon returning from St. Louis, I had a nice, long 6-day weekend in which to relax, refresh, and start digging into the block editor in earnest. My “quick start” guide follows.

What You Should Know About the Block Editor

Over the weekend, I watched Zac Gordon‘s excellent Gutenberg Block Development Course, and it helped to clear up a lot of questions that I had as a PHP developer who is trying to better understand the JavaScript ecosystem and how to work with the block editor.

Above all else, there are two primary resources for getting started with creating custom blocks in WordPress: the Block Editor Handbook and the Gutenberg plugin repository. Both of those links have just about everything you could possibly want to know about creating blocks, but they serve better as reference materials than tutorials, and that, really, is the rationale behind this post.

Here are some key takeaways I’ve learned over the weekend that will hopefully help you on your journey in developing custom blocks in WordPress, particularly if you’re familiar with a more traditional PHP-based workflow:

  • The block editor is composed of a series of NPM packages. These packages correspond with what you’ll find in the packages directory of the Gutenberg plugin. This is one of the most important things to understand, particularly if you find it more helpful to look at code than README docs.
  • One of those packages is the block-library, which contains all of the editor blocks that are part of WordPress core. The Gutenberg plugin here is useful, because this gives you tangible examples for how each block is constructed. As a developer new to the block editor, you can use any of these examples as a starting point for your own custom block exploration.
  • The dependencies you define when you register a block correspond with other packages in the Gutenberg plugin, such as element (WordPress’s abstraction layer around React), editor (which includes components like RichText for input and BlockControls for concepts like alignment), and data (which serves as a sort of communication hub between the component and WordPress itself), among others.
  • Blocks can be registered via PHP or JavaScript, but most-typically, only dynamic blocks will be registered via PHP. PHP’s role in block registration is primarily limited to making WordPress aware of the main JavaScript and CSS files required to render and make a block functional.

None of this information above will walk you through creating your first blocks (unlike the tutorials in the Block Editor Handbook, which I think are fairly sufficient for early exploration), but I do feel strongly that these details will help new developers better understand how to use the various components available from within the block editor, and more importantly, which ones to set as a dependency of a block.

For instance, the Block Editor tutorial indicates that you can require the wp-editor package as a dependency for your block and use the RichText component from it to provide a rich text input. But, it falls just short of linking back to the Gutenberg repository to provide examples and further documentation for that particular component so that developers can fully understand what it is and how it ties in with the block they’re trying to create.

Hopefully, putting together some pieces of this puzzle will help you on your block editor journey. It’s been an important weekend for discovery for me. This type of exploration can only happen during trial and error, which is why a long weekend is ideal. In my situation, the ability to apply these learnings to client work is going to go a long way toward helping me understand how things are constructed, and I’m hopeful those of you reading this will be able to apply some of those takeaways as well.