Partial fix Template modifications are active after add-on uninstallation via cmd.php

Affected version


Well-known member
I've noticed weird behaviour in command line uninstaller: if add-on is uninstalled via command line, its template modifications are still parsed during postExecutionCleanUp()

Same bug doesn't happen if add-on is uninstalled from admin panel.

Add-on where bug appears:
In test environment php should have write access to src/config.php, otherwise bug doesn't appear. Bug will trigger exception.
Last edited:


XenForo developer
Staff member
Just so you know, the same thing does (or can) happen via the web uninstaller too. If it's not happening, it may well be related to opcache not removing your config.php changes instantly.

I'm not sure what action (if any) we'll take with this. It continues to show examples why extending the template system with custom tags via an add-on (even the alternative approach taken here) is difficult. Add-on data isn't removed until after the uninstall steps are run. The uninstall steps remove the config.php code you added, thus making the template tags no longer valid at that time. Removing the uninstall data then triggers some template recompiles. In this case, it's from the phrase usage. The template modifications are still applied then, which isn't really unexpected with the given order of operations.

An alternative order could change the behavior, though this order is also used for installation. Beyond that though, the issue could exist if a customized template (or any template other than one directly associated with your add-on) used a custom tag, as that wouldn't be removed.

Generally, config.php overrides for the container would be considered a very advanced usage and there would be an expectation that users have removed code/customizations that depend on the changes prior to removing them (or unexpected things might happen, such as this).

For reference, the error logged is:
XF\Template\Compiler\Exception: Line 69: Unknown tag iconboxrow encountered.

#0 src\XF\Template\Compiler\Syntax\Tag.php(48): XF\Template\Compiler\Syntax\AbstractSyntax->exception(Object(XF\Phrase))
#1 src\XF\Template\Compiler\Syntax\Tag.php(40): XF\Template\Compiler\Syntax\Tag->getTag(Object(XF\Template\Compiler))
#2 src\XF\Template\Compiler.php(263): XF\Template\Compiler\Syntax\Tag->compile(Object(XF\Template\Compiler), Array, true)
#3 src\XF\Template\Compiler\Tag\Form.php(16): XF\Template\Compiler->compileInlineList(Array, Array)
#4 src\XF\Template\Compiler\Syntax\Tag.php(40): XF\Template\Compiler\Tag\Form->compile(Object(XF\Template\Compiler\Syntax\Tag), Object(XF\Template\Compiler), Array, false)
#5 src\XF\Template\Compiler.php(245): XF\Template\Compiler\Syntax\Tag->compile(Object(XF\Template\Compiler), Array, false)
#6 src\XF\Template\Compiler.php(227): XF\Template\Compiler->traverseBlockChildren(Array, Array)
#7 src\XF\Service\Template\Compile.php(24): XF\Template\Compiler->compileAst(Object(XF\Template\Compiler\Ast), Object(XF\Language))
#8 src\XF\Service\Phrase\Compile.php(71): XF\Service\Template\Compile->recompile(Object(XF\Entity\Template))
#9 src\XF\Entity\Phrase.php(198): XF\Service\Phrase\Compile->recompileIncludeContent('iconbox.icon')
#10 src\XF\Mvc\Entity\Entity.php(1580): XF\Entity\Phrase->_postDelete()
#11 src\XF\AddOn\DataType\AbstractDataType.php(117): XF\Mvc\Entity\Entity->delete()
#12 src\XF\AddOn\DataType\AbstractDataType.php(103): XF\AddOn\DataType\AbstractDataType->deleteEntity(Object(XF\Entity\Phrase))
#13 src\XF\Job\AddOnUninstallData.php(54): XF\AddOn\DataType\AbstractDataType->deleteAddOnData('Iconify/Iconify', G)
#14 src\XF\Job\Manager.php(253): XF\Job\AddOnUninstallData->run(8)
#15 src\XF\Job\Manager.php(195): XF\Job\Manager->runJobInternal(Array, 8)
#16 src\XF\Job\Manager.php(164): XF\Job\Manager->runJobEntry(Array, 8)
#17 src\XF\Cli\Runner.php(113): XF\Job\Manager->runById(63, 8)
#18 src\XF\Cli\Runner.php(64): XF\Cli\Runner->postExecutionCleanUp(Object(Symfony\Component\Console\Output\ConsoleOutput))
#19 cmd.php(15): XF\Cli\Runner->run()
#20 {main}


XenForo developer
Staff member
On second thought, I have made a change that at least allows the uninstall to continue, though it will potentially trigger a number of error logs about failed template compiles. The reasoning from my previous post stands; we just now capture template compilation errors in the template compiler service. Note that if the recompile fails, we won't change the previously compiled version. This may lead to run-time errors (as it would be calling methods that don't exist), but it should allow the issues to be addressed without the uninstall getting stuck.


Well-known member

I found a simple workaround for this: run db query that disables template modifications from add-on during uninstallation:
$finder = \XF::finder('XF:TemplateModification');
$finder->where('addon_id', 'Iconify/Iconify');
foreach ($finder->fetch() as $tm)
    $tm->enabled = false;