No Code Attached Yet J4 Issue
avatar aaron-harding
aaron-harding
14 Nov 2016

Steps to reproduce the issue

  1. Create an html override for mod_custom in /templates/template name/html/mod_custom/default.php
  2. Use following code in the override:
<?php
/**
 * @package     Joomla.Site
 * @subpackage  mod_custom
 *
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die; ?>

<div class="test-wrapper">
    <?php echo $module->content; ?>
</div>
  1. Create a custom module, give it some content in the text editor and then assign to a page.
  2. Inspect the page source in the front end of your site.

Expected result

Expected to see:

<div class="test-wrapper">
    Module Content here
</div>

Actual result

The module is wrapped twice in the test-wrapper div like so:

<div class="test-wrapper">
    <div class="test-wrapper">
        Module Content here
    </div>
</div>

System information (as much as possible)

Fresh install of Joomla with Blog content.

Additional comments

This issue only happens with mod_custom. I suspect it has something to do with outputting $module->content in the layout which is perhaps run twice by JModuleHelper::renderModule?

This issue happens even without an override on the module. The original default.php will output:

<div class="custom">
    <div class="custom">
        Module Content here
    </div>
</div>
avatar aaron-harding aaron-harding - open - 14 Nov 2016
avatar joomla-cms-bot joomla-cms-bot - change - 14 Nov 2016
Labels Added: ?
avatar aaron-harding aaron-harding - change - 14 Nov 2016
The description was changed
avatar aaron-harding aaron-harding - edited - 14 Nov 2016
avatar aaron-harding aaron-harding - change - 14 Nov 2016
The description was changed
avatar aaron-harding aaron-harding - edited - 14 Nov 2016
avatar brianteeman
brianteeman - comment - 14 Nov 2016

I suspect (not checked) that this is the module chrome of the module position causing this


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/12888.

avatar brianteeman brianteeman - change - 14 Nov 2016
Category Modules
avatar aaron-harding
aaron-harding - comment - 14 Nov 2016

I managed to replicate this issue if the module does get loaded twice.

Steps to reproduce with protostar template

  1. Create custom html module with title "Test Custom Module".
  2. Assign to position "Left [position-8]" and assign to all pages.
  3. Create a featured article that loads that same module. {loadmodule mod_custom,Test Custom Module}

Result

The module in the left position will now have been doubled up in the html markup.

avatar brianteeman
brianteeman - comment - 14 Nov 2016

So thats exactly what i suspected. The module chrome for that template position is xhtml.
The code for that is coming from here
https://github.com/joomla/joomla-cms/blob/staging/templates/system/html/modules.php#L89

So what you are seeing is absolutely expected behaviour

avatar SharkyKZ
SharkyKZ - comment - 14 Nov 2016

Happens with other chromes too.

avatar brianteeman
brianteeman - comment - 14 Nov 2016

yes it depends on the chrome being used
For example it wont happen with chrome:none

avatar aaron-harding
aaron-harding - comment - 14 Nov 2016

Changing the module chrome from "xhtml" to "none" stills doubles the markup which in this case is just outputting $module->content.

I loaded the same module again in the featured article for a second time. The module in the left position is then tripled in the markup. This is run through JModuleHelper::renderModule each time the module is loaded. The renderModule method is modifying the $module->content param here: https://github.com/joomla/joomla-cms/blob/staging/libraries/cms/module/helper.php#L199

This is then passed again to the mod_custom layout here: https://github.com/joomla/joomla-cms/blob/staging/modules/mod_custom/tmpl/default.php#L15, where it is again wrapped in a div with a class of custom.

I would have thought that expected behaviour is to be rendered once and then reused output for the other two modules?

avatar mbabker
mbabker - comment - 14 Nov 2016

I would have thought that expected behaviour is to be rendered once and then reused output for the other two modules?

Joomla doesn't hold in memory the results of rendering a module. The $module object that method is processing is a plain PHP stdClass object, it doesn't correspond directly to the database record (because the API also could conceivably support rendering a module without needing any data from the database). So if what you're saying is true in that the same module's contents are being echoed out multiple times, it would seem to me whatever is feeding the data object into JModuleHelper::renderModule() is incorrectly building/structuring that data, not necessarily a bug in that method (since also if you look in that method, at no point does it prepend/append the content but rather sets it and overwrites anything that might already be assigned to the content key of the object).

What could possibly be causing an issue (with all modules in general) is an issue of scope creep. When a module is rendered, the module's base file includes these variables defined in JModuleHelper::renderModule(). Since $module->content is the result of whatever the module echoes out plus whatever is assigned to the $content variable, if a module is actually setting that variable in some form it would result in unexpected output changes.

avatar aaron-harding
aaron-harding - comment - 14 Nov 2016

Ok that makes sense. In that case should the JModuleHelper::renderModule method clone the $module param so it does not modify the $module->content? Since $module is an object it is modified by reference and changes the original object in the code block that calls the renderModule method.

As a test I have put clone $module like so:

    public static function renderModule($module, $attribs = array())
    {
        static $chrome;
        $module = clone $module;

        // Check that $module is a valid module object
        if (!is_object($module) || !isset($module->module) || !isset($module->params))
        ....

at the top of the renderModule method and this does stop the duplication issue. As this method is just used for generating the output, I don't think it should modify the original $module object.

Does that make sense?

Edit:

Not sure what the value of the $content variable here: https://github.com/joomla/joomla-cms/blob/staging/libraries/cms/module/helper.php#L196-L199. Why is it always appending '' to $module->content?

avatar mbabker
mbabker - comment - 14 Nov 2016

I don't think we'd need to clone it at first glance. My gut feeling is whatever upstream provider is passing the data in might be reusing an object when it shouldn't be (depending on the path this might come back to the plugins that render modules in content or the JDocument renderers).

As for the $content variable, I honestly haven't a clue. Seems like someone could create an edge case though where they assign something to that $content variable in their module and its value is spit out after the module's been processed (the require JModuleHelper::getLayoutPath() line in most modules). They'd be better off just spitting it out themselves in the layout or after the require line, but thanks to variable scope creep, it's entirely possible to do something goofy (and other damaging things if you look at what variables are declared and creep in).

avatar aaron-harding
aaron-harding - comment - 16 Nov 2016

I've had a closer look through the process of rendering modules via JDocumentRendererHtmlModule and the loadmodule plugin (the plugin uses that renderer anyway). They both at some point end up calling JModuleHelper::load where it has stored a static array of module objects. It seems like it is here it is reusing the module objects for the renderModule method.

I think the solution to this is to either clone the $module object in the renderModule method so it does not modify the original object or we update the mod_custom module to not use $module->content in its layout. Instead it should load the contents from the table row via a helper to prevent the variable scope creep.

avatar mbabker
mbabker - comment - 16 Nov 2016

The module table's content row should be renamed if it's causing this deep of a conflict, or the object's key name should be changed. Either way it's a B/C break so not an immediate fix.

I personally don't think cloning in the render method is the right fix, it seems more like that is addressing a symptom of the issue versus fixing it.

Honestly, we shouldn't be trying to render the same object multiple times. Seems like there should be better tracking internally to prevent that. If you're really displaying the same mod_custom instance three times on the same page, the actual module should only be rendered once and the other times it's rendered should make use of that first run then apply template chrome since that can be configured differently based on where in the page it's displayed.

avatar aaron-harding
aaron-harding - comment - 16 Nov 2016

Would you still have the same issue with allowing the chromes to run once for each instance? It seems it will keep wrapping $module->content here as well.

I'm having trouble working out what should keep track internally of which parts of the module has been rendered. Is this a task for JDocumentRenderer or the JModuleHelper::renderModule method?

avatar mbabker
mbabker - comment - 16 Nov 2016

So here's the issues I see:

  • The $module->content key is reused in several ways; as a database record it corresponds to the row in the modules table, and its uses in the render method
  • Modules are inherently rendered the same number of times they are configured to display on a page; a single module instance (one record from the database for most conventional uses) should only trigger the module's mod_whatever.php file once since the results shouldn't change unless you're manipulating the parameters or something outside the normal rendering process, but honestly in that case you should be working with a different object (i.e. clone it)
  • The wrapping chrome is assigned to $module->content as well, and because of the reuse, it causes the recursion issues
  • Why do we even need to assign the processed content to $module to begin with? In the render method we're injecting the module object and returning the processed string, but the processed string is assigned to the module object too and thanks to references in PHP that contributes to the reuse/recursion issues. We'd really be better off here using a local variable (that questionable $content variable perhaps?) to keep the rendered contents separated from the $module object (and inherently the content key that exists from the database)

I'm having trouble working out what should keep track internally of which parts of the module has been rendered. Is this a task for JDocumentRenderer or the JModuleHelper::renderModule method?

I would probably have a static var in JModuleHelper for this. Create an associative array with the key being an MD5 hash of the module object and the value being whatever's processed by including the module's mod_whatever.php file. Then do something like this:

if (isset(static::$processed[$key])) {
    $content = static::$processed[$key];
} else {
    $content = include $modulePath;
}

So you're avoiding the scoping and reference issues now and can pass that separate content to the chrome method as an additional variable for that to be wrapped and in the end we end up in a state where we don't process the same data multiple times where we can help it and get rid of some of the internal issues.

Unfortunately, all of this would have to go into the 4.0 branch because it has major B/C implications (it would affect the internal handling in the module helper, change how module chromes function, and how the events dispatched from the module helper interact with the module). So maybe cloning can be a short term fix for the immediate issue while a bigger (and IMO more correct) fix be worked on separately.

avatar franz-wohlkoenig franz-wohlkoenig - change - 5 Apr 2017
Status New Discussion
avatar ChrisBreaks
ChrisBreaks - comment - 11 Apr 2017

I have come across the same issue. I am displaying a custom module assigned to all pages. This module is also integrated in an article via loadmodule (loadposition has the same effect). I didn't duplicate the module so its' content only needs to be changed once when being updated.

To avoid the multiple-wrapping-issue without altering the joomla core files, I created an alternative layout for mod_custom, assigned it to the module and added $module = null; at the end of the layout file.
Maybe someone finds this helpful. Dirty fix, please don't judge :)

avatar brianteeman brianteeman - labeled - 25 Mar 2018
avatar aaron-harding
aaron-harding - comment - 12 Apr 2019

I can still see this issue happening since my original post and looking at our issues being posted, it does not seem like i'm the only person having this issue.

The problem with the current setup of the module rendering is that anything modifying/referencing $module->content is getting stuck in a loop depending on the number of times the renderModule method gets called during the page load.

The process:

  1. ModuleHelper::getModule, stores the $module reference in a static list
  2. ModuleHelper::renderModule, wraps $module->content in the module chromes and then overwrites $module->content. As $module is an object, this is passed by reference in the renderMethod which commits the $module reference back to the static array in ModuleHelper::getModule
  3. ModuleHelper::getModule is called again at some point in the process, this will search the static array for the $module object which at this point will now have the $module->content wrapped in the module chome markup.
  4. ModuleHelper::renderModule is called again (second loadposition, 3rd party extension), this time it will wrap $module->content in the module chrome again. This is where the duplicate wrapping starts.

I'm not sure why the clone fix in the renderModule method would be a B/C? It runs the same logic the multiple times anyway, except it does not modify the original reference.

Also does this highlight that the module rendering is not efficient? Its only highlighted in the custom html module, but would this be running the module layout code the number of times renderMethod is called?

avatar jwaisner jwaisner - change - 17 Apr 2020
Status Discussion Confirmed
Build master 4.0-dev
avatar joomla-cms-bot joomla-cms-bot - edited - 17 Apr 2020
avatar jwaisner jwaisner - change - 17 Apr 2020
Title
mod_custom layout is run twice
[4.0] mod_custom layout is run twice
avatar jwaisner jwaisner - change - 17 Apr 2020
Labels Added: J4 Issue
Removed: J3 Issue
avatar jwaisner jwaisner - unlabeled - 17 Apr 2020
avatar jwaisner jwaisner - labeled - 17 Apr 2020
avatar coolcat-creations
coolcat-creations - comment - 19 Dec 2020

I can't reproduce the Issue on J4 - @chmst can you crosscheck and maybe close ?

avatar chmst
chmst - comment - 19 Dec 2020

@coolcat-creations I can reproduce. If you load a custom module as describend abvoe in an article you can see it. But no clue how to resove it.

avatar coolcat-creations
coolcat-creations - comment - 22 Dec 2020

@chmst ah now I got it - I maybe have an idea! thanks

avatar coolcat-creations
coolcat-creations - comment - 22 Dec 2020

@chmst no still can't reproduce it ...

grafik

I would look to solve it in the loadmodule plugin but I can't see it happening at all

avatar chmst
chmst - comment - 22 Dec 2020

@coolcat-creations thanks a lot for testing. 'We both repeated the tests on 3.9 and 4.0 and could not reproduce the issue. Closing this now as it seems resolved.

avatar chmst chmst - change - 22 Dec 2020
Status Confirmed Closed
Closed_Date 0000-00-00 00:00:00 2020-12-22 16:06:57
Closed_By chmst
avatar chmst chmst - close - 22 Dec 2020
avatar SharkyKZ
SharkyKZ - comment - 22 Dec 2020

Not solved...

avatar chmst chmst - change - 22 Dec 2020
Status Closed New
Closed_Date 2020-12-22 16:06:57
Closed_By chmst
avatar chmst chmst - reopen - 22 Dec 2020
avatar chmst
chmst - comment - 22 Dec 2020

@SharkyKZ Can you reproduce it?

avatar angieradtke
angieradtke - comment - 22 Aug 2022

In Joomla 4 the issue is still there.

@coolcat-creations @chmst @bembelimen

Steps to reproduce

  • Create custom html module with title "Test Custom Module"
  • Assign any position an all sites
  • Create a article that loads that same module.
avatar brianteeman
brianteeman - comment - 22 Aug 2022

I still cannot find a bug when doing this

image

avatar angieradtke
angieradtke - comment - 22 Aug 2022

I use cassiopeia.
Add a custom module at the position banner -> Module Assignment-> all pages
Use module-Style -> html5
Create an article -> Load this module via moduleid inside the article.
Create article menu item to this item. And it happens.

avatar brianteeman
brianteeman - comment - 22 Aug 2022

Use module-Style -> html5

That was the missing bit. I can confirm weirdness happens when html5 is selected

avatar brianteeman
brianteeman - comment - 23 Aug 2022

Please test #38571

avatar zero-24 zero-24 - change - 23 Aug 2022
Status New Closed
Closed_Date 0000-00-00 00:00:00 2022-08-23 18:39:48
Closed_By zero-24
Labels Added: No Code Attached Yet
Removed: ?
avatar zero-24 zero-24 - close - 23 Aug 2022

Add a Comment

Login with GitHub to post a comment