Hey there! We’re really happy you’ve found your way here 💪. Timber is a community project that is developed by people from all over the world. We appreciate any help.
Here are ways to get involved:
- Star the project!
- Answer questions that come in through GitHub issues.
- Report a bug that you find.
- Share a theme you’ve built with Timber. This helps transfer knowledge about best practices, etc. Add it to the Showcase list.
- Tweet and blog about the advantages (and criticisms) of the project and Twig.
- Browse "help wanted" and "good first issue" labels for areas of WordPress/PHP/code you know well to consider, build or document.
- Answer questions on Stack Overflow posted under the «Timber» tag. You can also subscribe to a tag via email to get notified when someone needs help.
- Answer questions and join in on GitHub Discussions.
Pull requests are highly appreciated. More than 150 people have written parts of Timber (so far). Here are some guidelines to help:
- Solve a problem – Features are great, but even better is cleaning-up and fixing issues in the code that you discover.
- Write tests – This helps preserve functionality as the codebase grows and demonstrates how your change affects the code.
- Write documentation – Timber is only useful if its features are documented. This covers inline documentation of the code as well as documenting functionality and use cases in the Guides section of the documentation.
- Small > big – Better to have a few small pull requests that address specific parts of the code, than one big pull request that jumps all over.
- Comply with Coding Standards – See next section.
We try to follow the WordPress Coding Standards as close as we can, with the following exceptions:
- Class and file names are defined in
StudlyCaps
. We follow the PSR-0 standard, because we use autoloading via Composer. - We use hook names namespaced by
/
instead of underscores (e.g.timber/context
instead oftimber_context
).
To check where the code deviates from the standards, you can use PHP_CodeSniffer. Timber comes with a phpcs.xml
in the root folder of the repository, so that the the Timber code base will be automatically checked for coding standards violations.
When you run composer install
in Timber’s repository root, you will get all required dependencies to check the coding standards.
To run PHP_CodeSniffer with the default settings on all relevant Timber files, use the following command from the root folder of the Timber repository:
composer lint
You can check a single file like this:
./vendor/bin/phpcs ./lib/Menu.php
Use ./vendor/bin/phpcs --help
for a list of available settings or refer to the PHP_CodeSniffer documentation.
Please refer to https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards#using-phpcs-and-wpcs-from-within-your-ide for different ways to use PHP_CodeSniffer directly in your IDE. In some IDEs like PHPStorm, you may have to select the phpcs.xml
explicitly to apply the proper standards.
If it’s not possible to adapt to certain rules, code could be whitelisted. However, this should be used sparingly.
- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/wiki/Whitelisting-code-which-flags-errors
- https://github.com/squizlabs/PHP_CodeSniffer/wiki/Advanced-Usage#ignoring-parts-of-a-file
The Reference section of the documentation is automatically generated from the inline documentation of the Timber code base. To document Timber, we follow the official PHP Documentation Standards of WordPress.
There are minor differences to the official standards:
- For class headers, we don’t use
@package
or@subpackage
tags. - We don’t use the
@access
tag.
The documentation generator ignores a number of elements. An element (class, method, property) is ignored when one of the following conditions applies:
- No DocBlock is provided
- No
@api
tag is present - An
@ignore
tag is present - An
@internal
tag is present - The visibility is
private
(applies to methods only)
This means that for Markdown files to be generated for a class at all, you’ll need at least a DocBlock with an @api
tag.
When referencing a namespaced class name in a type (for example in a @param
or @return
tag), then use the fully qualified name. Example: Timber\Post
instead of just Post
.
Timber uses tabs for indentation, but you should always use spaces for indentation in code examples, because the resulting Markdown will have a more consistens styling.
The @example
tag allows you add code examples to your DocBlocks, including fenced code blocks:
/**
* Function summary.
*
* Function description.
*
* @api
* @example
*
* Optional text to describe the example.
*
* ```php
* my_method( 'example', false );
* ```
*
* @param string $param1 Description. Default 'value'.
* @param bool $param2 Optional. Description. Default true.
*/
function my_method( $param1, $param2 = true ) {}
When you use the @see
tag, the Reference Generator will automatically convert it to a link to the reference.
- Use this tag only when the referenced method has an
@api
tag, which means that it is public. - Beware, you’ll always use the notation with
::
, which you normally know from static methods. But even if the method that you link is not static, you’ll have to use the double colon.
An example:
@see \Timber\Image::src()
will turn into this:
<strong>see</strong>
<a href="/docs/reference/timber-image/#src">Timber\Image::src()</a>
Follow the official Inline Documentation Standards for Actions and Filters to document hooks.
A DocBlock that documents a hook should always start with the keyword
Filters
for filter hooksFires
for action hooks
This is needed so that the Hook Reference Generator can detect the comments associated with filters and actions.
/**
* Filters … / Fires … (Summary)
*
* Description.
*
* `$var` Optional description of variables that might be used in the filter name.
*
* @see \Timber\Classname::function()
* @link https://github.com/timber/timber/pull/1254
* @since x.x.x
* @deprecated x.x.x
* @example
* Optional text to describe the example.
*
* ```php
* // A PHP example
*
* /**
* * Multiline comments are possible as well.
* * You’ll need to escape the closing tag with a "\".
* *\/
* ```
*
* ```twig
* {# A Twig example #}
* ```
*
* @param type $var Description. Default 'value'.
* @param array $args {
* Short description about this hash.
*
* @type type $var Optional. Description. Default value.
* @type type $var Optional. Description. Default value.
* }
* @param type $var Optional. Description. Default value.
*/
When a filter contains a variable, it should be marked up with double quotes "
and the variable name inside curly braces:
$force = apply_filters( "timber/transient/force_transient_{$slug}", $force );
Additionally to this, document what the variable is by adding it to the description. Add it on a new line with the variable wrapped in backticks, so that it appears as code in Markdown:
/**
* Filters the status of a particularly named transient.
*
* Allows you to override the behavior on a case-by-case basis.
* `$slug` The transient slug.
*
* @param bool $force Param description.
*/
$force = apply_filters( "timber/transient/force_transient_{$slug}", $force );
Formatting a filter into multiple lines when the line should be too long is allowed:
/**
* Filters …
*/
$force = apply_filters_deprecated(
'timber_force_transients',
array( $force ),
'2.0.0',
'timber/transient/force_transients'
);
If a filter description is not finished yet, mark it up with the @todo
tag. It’s okay if you don’t know what a filter is doing exactly or if you’re unsure about what a parameter does. Describe what needs to be done in the @todo
tag.
/**
* Filters …
*
* @todo Add summary, add description.
*
* @param bool $force Param description.
*/
As soon as the todo is resolved, the @todo
tag can be removed.
All PRs receive a review from at least one maintainer. We’ll do our best to do that review in a week, but we’d rather go slow and get it right than merge in code with issues that just lead to trouble.
You might see us assign multiple reviewers, in this case these are OR checks (i.e. either Coby or Pascal) unless we explicitly say it’s an AND type thing (i.e. can both Lukas and Maciej check this out?).
We use the assignee to show who’s responsible at that moment. We’ll assign back to the submitter if we need additional info/code/response, or it might be assigned to a branch maintainer if it needs more thought/revision (perhaps it’s directly related to an issue that's actively being worked on).
Once approved, the lead maintainer for the branch should merge the PR into the master
or 2.x
branch. The 1.x team will work to resolve merge conflicts on #1617 (2.x
into master
) so the branches stay in sync.
- 1.x: @jaredNova (lead), @palmiak
- 2.x: @gchtr (lead), @pascalknecht, @cobytamayo