Approaching farmOS Module Development

I’ve been asked how to begin developing modules for farmOS, so I decided to write up a quick forum post, in hopes that it may be useful for others.

This is meant to compliment the official farmOS 2.x Module Development Guide.

Note that this is specific to farmOS 2.x. We recorded two videos a while back that were specific to the 1.x development process, which may also provide useful context: Part 1 / Part 2

Also note that this is specifically for farmOS server module development… not “Field Modules” for farmOS Field Kit - which are still a developing concept (@jgaehring can provide some intros to that process when the time is right).

Layers of modules

We have a pretty elegant layered development model - building on that of the Drupal community/platform itself. If you are coming to farmOS as a new developer (and without any experience with Drupal) it helps to understand the options that are available.

Custom modules

If you want ultimate freedom, then you can create your own custom module (eg: farm_myfarmname) and play around however you want. This module can provide new asset types, log types, plan types, etc… depend on other modules (eg: farm_fungi)… override configuration from other modules… add pages, forms, etc etc etc… ultimate freedom! This is a great place to start experimenting, as it has no affect/considerations with regard to the “official” modules or farmOS core itself. You’re basically building your own layer on top to do exactly what you want/need.

Custom modules can be very specific to your needs. And as such, it often doesn’t make sense for others to use them. They can be kept private (not published to public repository), and only installed on your individual instance.

Contrib modules

The next level up is “contrib modules”, which is just Drupal parlance for a module that isn’t part of Drupal core, or in our case farmOS core - and often means it’s “community maintained”. These include modules like Fungi, Organic, Grazing, etc.

Core/official modules

The other end of that spectrum is contributing patches or pull requests to farmOS core itself. We also maintain a number of “official contrib” modules (under the farmOS GitHub organization: farmOS · GitHub).

Contributing to these has more of a strict process to it, and therefore more restrictions and considerations. We try to keep the core/official code as simple and easy to maintain as we can - and critically: as general as possible, so that it fits the needs of a wide audience.

Moving upstream

The combination of these three approaches is a great balance, because it keeps the core maintenance of official code manageable, while allowing for ultimate freedom for experimentation in the “contrib” and “custom” space. This also allows for a process whereby code from custom/contrib can “move upstream” to core/official code over time. So if someone comes up with a really great solution in their own module, and it solves a general need that others in the community see value in, they can propose that it be considered for inclusion in “upstream” code.

Custom to contrib

In many cases, it may make sense for code to start in a custom module, and then if it is general and useful to others it can be published as a contrib module. Or, if it modifies/extends an existing contrib module it can propose moving certain parts to the upstream project.

Contrib/custom to core

If an improvement is so general that it makes sense to include in farmOS core itself, then it can be proposed for inclusion in a similar way.

Getting started

The first step to getting started is to set up a local development environment: Getting started - farmOS 2.x Docs

Then, decide where you want to start: custom, contrib, or core. In most cases the easiest place to start is a custom module.

Custom

To create your first custom module, create a new directory inside www/web/sites/all/modules with the name of your module. Module names must be all lowercase alphanumeric, with underscores. Standard practice is to prefix your module name with farm_ to designate that it is a farmOS module (not a more general Drupal module). Then, within that directory, create a file called [modulename].info.yml. This simply tells Drupal that the module exists.

For example: modules/farm_mymodule/farm_mymodule.info.yml

mylogtype.info.yml:

name: My custom farmOS module
description: This is a description of what my module does.
type: module
package: farmOS Custom
core_version_requirement: ^9

That’s it! Now when you go to https://[my-farmOS-hostname]/admin/modules you will see your custom module and be able to enable it.

What you do from there depends on what your goals are… feel free to ask questions here if it is not already covered in the module development guide.

Contrib

If you want to work with an existing module directly, you can fork it’s repository on GitHub (or wherever it lives), and clone it to your sites/all/modules directory. Then you can make changes, commits, and create Pull Requests like normal.

https://paulrohan.medium.com/workflow-of-pull-request-or-merge-request-to-github-bitbucket-gitlab-b0942ec5d56e

Core

If you believe your changes belong in farmOS core itself, start by opening an issue to describe your proposal.

The farmOS development environment automatically checks out the farmOS Git repository in www/web/profiles/farm - so you can create a branch there, add your remote fork, etc.

Communication with maintainers

If you plan to contribute changes to core or contrib modules, it’s always a good idea to open an issue first that describes what you’d like to do, and work with the maintainers to make sure that it makes sense. farmOS core and official modules strive to be both general (applicable to many use-cases), and maintainable (the least amount of code to achieve agreed upon goals). So before you put a lot of effort into changes, be sure that they have a chance for inclusion upstream in the first place. If not, they can live in your own custom or contrib modules instead. This is another reason why it’s often best to start in a custom module… it allows you to work quickly to meet your own needs, without the extra considerations of upstream contributions, while still leaving the possibility open to moving upstream in the future, if applicable.

Resources

The farmOS Module Development Guide aims to provide some basic information about farmOS module development. It focuses on farmOS-specific concepts (as well as a basic intro to Drupal module file structure).

For information about Drupal module development more generally (of which farmOS modules are a subset), refer to the official Drupal Module Developer’s Guide.

There are a lot of aspects and possibilities to Drupal module development, which we cannot possibly cover in detail here or in our own documentation. So we try to keep our docs focused on the farmOS-specific details. But feel free to ask questions in this thread, or post links to additional resources that you found helpful in your explorations!

Welcome to farmOS development! :smiley:

6 Likes

OK. Here’s my first issue.

I grabbed the fungi module to “copy” the code in order to start my custom version. Changed the names of files, classes, etc.

Then I installed my custom module and got this error:


What did I do wrong here?

I’m about to create my own repository in Git with the files if anyone wants access to them.

Thanks!

1 Like

After thinking about this a bit, could it be the namespace path?

I added the “custom” files to farmOS\www\web\sites\all\modules\farm_shane_fungi\

If that’s the case, how do I resolve the path correctly?

Thanks!

1 Like

Looks like your asset type IDs aren’t matching up! Based on asset.type.shane_fungi.yml, your ID should be shane_fungi in the following @AssetType annotation. I think you class name should be OK as is.

/**
 * Provides the fungi asset type.
 *
 * @AssetType(
 *   id = "fungi",
 *   label = @Translation("Fungi"),
 * )
 */
class ShaneFungi extends FarmAssetType {
2 Likes

I thought that part was commented out. I’ll make the change and see what happens.

1 Like

So something else happened with Visual Studio Code, and I ended up starting from scratch (deleted the dev environment, reinstalled farmOS). Then I used VS Code to clone my repository, made the change @paul121 suggested, installed my custom module and got this error after clicking on “Install”:

“The website encountered an unexpected error. Please try again later.”

Now I’m completely lost as to what is going on.

:man_facepalming:

1 Like

I’m wearing this thread out already! :rofl:

I enabled all errors to be reported and found out an apostrophe is causing an issue with my description in the taxonomy yml file.

Easy for me to take that out. However, if someone knows how to get that in there properly, I would really appreciate it!

Update:

1 Like

Oh interesting! TIL in a YAML single quoted string you escape the single quote character with another single quote. So if you change that description to 'Shane''s ...' it should work: YAML Ain't Markup Language (YAML) Version 1.1

Re: that error… interesting… referencing the farm_fungi module and everything looks OK. Have you tried installing the farm_fungi module itself to confirm it’s working? Maybe you can start a new forum thread or open an issue in your github repo? :smiley:

2 Likes

I did install the farm_fungi module and it worked correctly. That’s why I’m thinking it has something to do with the namespace path I referenced above. I’ll create an issue for it and see what responses I get while attempting to change the namespace path in the PHP file.

New thread.

Cheers!

2 Likes

@shane_aldrich Probably makes sense to start a separate thread to help you debug this stuff specifically. The farmOS chat room is another good option - happy to help debug with you in there if/when I’m around. But some tips real quick:

  • Start small. Don’t try to add everything all at once. Add one small piece at a time and make sure it works before moving on to the next piece. The more variables you’re trying to debug at once the more confusing it will be.
  • Be prepared to reinstall from scratch. Drupal does a lot of stuff behind the scenes with the information it gets from your module, including creating database tables, generating config entities, caching things, etc. If you are throwing things at the wall to see what sticks it’s possible to end up with a messed up database/cache/etc - and while in theory anything can be detangled, that requires understanding what is tangled in the first place - so it may be easier to just reinstall everything from scratch to make sure you’re starting fresh.
  • Learn to use Drush Especially the drush cr command - which rebuilds the Drupal cache. A lot of my development involves changing something in code and then running drush cr. Basic guide here: Drush - farmOS 2.x Docs

Lastly, it’s always a good idea to start with a plan for your data architecture before you jump into the module code itself. What asset types do you want? What log types? What additional fields are necessary for specific data, or for linking records together? This can all be outlined before you write your first line of code.

Hope that helps! I’ll check out the issue you started in your repo to help with the specific issues you’re encountering… :slight_smile:

1 Like

That’s my plan. Hence, just making small changes to the Farm Fungi 2.x module as my base code. :slightly_smiling_face:

I’ve done that a couple of times already. So that’s super easy to accomplish!

Thanks for the link! I’ll start to learn Drush commands today.

I have a good start on this just using pen and paper. By having that as a reference and making incremental changes, hopefully, I won’t end up with too many errors moving forward.

Much appreciated!

1 Like

I started a new branch on GitHub 0.0.1 where I plan on doing most of the experimental design aspects of how I envision this module working.

Today I created an overview page where all things Fungi can live and interact with the rest of farmOS.

It’s just a simple “Hello World” page for now while I dive deeper into adding menu links to the page from the home screen. Unless someone can suggest a better way to accomplish the navigation within the farmOS UI framework. Once that is accomplished, I’ll start to add dependencies and links to adding assets from the overview.

Prost! :beers:

2 Likes