Skip to content

Mixins: Standard mixins


The standard mixins are published by CiviCRM. Standard mixins aim to be short, simple, and portable. They have additional testing and tooling to provide consistent support over time.

It is often safe to copy a standard mixin and run it on an older environment. For example, menu-xml@1.0.0 has been distributed with CiviCRM 5.45+ -- but it can be used in CiviCRM 5.27. This is called backporting. If you manage your extension with civix, then backporting is automatic.

List of mixins

Name Minimum Compatible CiviCRM Distributed Since CiviCRM Description
afform-entity-php@1.0.0 5.31 5.50 Scan afformEntities/*.php. Register via internal event.
ang-php@1.0.0 5.27 5.45 Scan ang/*.ang.php. Register via hook_angularModules.
case-xml@1.0.0 5.27 5.45 Scan xml/case/*.xml. Register via hook_caseTypes.
entity-types-php@1 5.45 5.57 Scan xml/schema/**.entityType.php. Register via hook_entityTypes.
menu-xml@1.0.0 5.27 5.45 Scan xml/Menu/*.xml. Register with Menu-Router via hook_xmlMenu.
mgd-php@1.0.0 5.27 5.45 Scan **/*.mgd.php. Register via hook_managed.
mgd-php@1.1.0 5.27 5.50 As above, with extra performance optimization.
scan-classes@1.0.0 5.51 5.52 Scan CRM/**.php and Civi/**.php for key interfaces and annotations. Register via hook_scanClasses.
scan-classes@1.1.0 5.51 5.63 As above, minus a special PHPUnit quirk
setting-php@1.0.0 5.27 5.45 Scan settings/*.setting.php. Register via hook_alterSettingsFolders.
smarty-v2@1.0.0 5.27 5.59 Add templates/**.tpl to Smarty. Register via hook_config.
smarty-v2@1.0.1 5.27 5.60 As above, with slightly different internal API.
theme-php@1.0.0 5.27 5.45 Scan **/*.theme.php. Register via hook_themes.

This table is representative. It may not be completely up-to-date. For an authoritative list of standard mixins, browse civicrm-core:mixin/ and civix:mixin-backports.php.

Civix support

civix is a tool help extension-developers. It includes built-in support for standard mixins:

  • When you make a new extension, some common mixins are enabled by default.
  • When you generate new skeletal code, it will auto-enable any required mixins. (For example, civix generate:page will auto-enable menu-xml@1.)
  • When you run civix upgrade, it may suggest enabling or disabling specific mixins.
  • If your <compatibility> targets an older version of CiviCRM, then civix will automatically include polyfills and backports.
  • The command civix mixin can be used to view, enable, and disable mixins.

    ## List the standard mixins. Report on whether they are active.
    civix mixin
    ## Enable all standard mixins
    civix mixin --enable-all
    ## Enable specific mixins
    civix mixin --enable=ang-php@1,setting-php@1
    ## Disable specific mixins
    civix mixin --disable=ang-php@1
    ## Reset the mixins.
    civix mixin --disable-all --enable=mgd-php@1

Civix only supports mixins identified by civix:mixin-backports.php.

Quality assurance

Suppose you want to develop a new standard mixin that's available to other extension-developers. This is much like developing a basic mixin... but harder. Standard mixins need to work across a range of use-cases:

  • Applied to core extensions and contrib extensions
  • Distributed via core tarball and via backport
  • Activated (and deactivated) during installation (and uninstallation)
  • Executed via web and CLI and E2E-test and headless-test
  • Mixed and matched with other standard-mixins

Quality assurance is oriented around an example extension named shimmy. shimmy is not a regular extension. It is dynamically re-generated numerous times. Each time, it uses a different set of mixin options, and it's put through a series of installation and uninstallation tests. This is a brutal process designed to find (and prevent) subtle discrepancies in how mixins interact with system-services and system-caches.

To run the full suite (with all the permutations of shimmy), use this script:


test-all is important for the CI server, but it's an entire suite of tests. If you are trying to debug a specific problem, then you'll need to focus on one instance of shimmy. To do this, pick a folder where you will put shimmy and then run the mixer command.

SHIMMY=$(cv path -c extensionsDir/example-mixin)
./tools/mixin/bin/mixer create -f --bare "$SHIMMY" mgd-php@1 smarty-v2@1
What are the options in this command?
  • SHIMMY is the folder where it will put the extension
  • mixer is the command that generates the extension
  • -f forces the command to overwrite any pre-existing content in that path
  • --bare indicates that you just want to make a lightweight version of the extension. (You are not testing backports.)
  • mgd-php@1 smarty-v2@1 are two mixins that we want to focus on
Pick one SHIMMY folder and stick to it.

If you generate two copies of shimmy (in different folders), then this will quickly become confusing.

The example above is chosen to match the test-all script.

What does the example extension look like?

After creating this folder, you can inspect it:

find $SHIMMY -type f

You should see something that resembles a regular extension:

Where does the example code come from?

We asked mixer to focus on mgd-php@1 and smarty-v2@1, so it pulled from these sources:

  • mixin/mgd-php@1/example/ - Example data for mgd-php
  • mixin/smarty-v2@1/example/ - Example data for smarty-v2
  • tests/extensions/shimmy/ - Common boilerplate

Now, you have a regular extension. You can run tests in the usual ways:

cd "$SHIMMY"
phpunit9 --group e2e
phpunit9 --group headless
How do I run the test in PHPStorm?

If PhpStorm is already configured to run core tests, then:

  • In the SHIMMY folder, open tests/phpunit/E2E/Shimmy/LifecycleTest.php
  • Select a specific test, such as testLifecycleWithLocalFunctions.
    • (If you have freedom to choose, then use this -- it's easier to debug.)
  • Run this test like usual. It will fail.
  • Update the test options ("Run > Edit Configurations"). Find "LifecycleTest" and update it:
    • The workdir should match SHIMMY folder
    • The PHPUnit XML file should come from the SHIMMY folder.
    • The environment should not set CIVICRM_UF
  • Run this test again. It should execute.