WordPress.org

Make WordPress Core

Opened 3 months ago

Closed 3 months ago

Last modified 4 weeks ago

#52276 closed feature request (invalid)

Feature Request - additional hooks for parent and child theme

Reported by: landwire Owned by:
Milestone: Priority: normal
Severity: normal Version: 5.6
Component: Themes Keywords:
Focuses: Cc:

Description

Hi there,

would you consider adding a couple of hooks "after_setup_parent_theme" and "after_setup_child_theme" to wp-settings.php so that people have more control when overriding functions from a parent theme? The child theme is loaded first, so this helps in removing some functionality of the parent theme you might not want inside the child theme.

I also added another constant in the patch to switch the load order of child and parent theme. But I think having the additional hooks might be enough. Though in my logic I would have assumed that the parent theme would load first and then the child theme.

Attachments (1)

theme_hooks.patch (1.7 KB) - added by landwire 3 months ago.
Example Patch of suggested hooks

Download all attachments as: .zip

Change History (11)

@landwire
3 months ago

Example Patch of suggested hooks

#1 @SergeyBiryukov
3 months ago

  • Component changed from General to Themes

#2 follow-up: @joyously
3 months ago

Definitely can't switch the load order, since all the logic for existing themes would break.

#3 in reply to: ↑ 2 @landwire
3 months ago

Well, switching the load order could be an additional optional constant, as per the attached patch. No existing theme would be affected. Only WordPress installs that opt-in by setting this constant, would switch the load order.

What is the rationale behind loading the child theme first anyway? Just so I know what to look out for.

Replying to joyously:

Definitely can't switch the load order, since all the logic for existing themes would break.

#4 @joyously
3 months ago

Loading the child first means that it can define any of the pluggable functions that the parent defines. It also allows the child to preempt hooks with priority 0 that the parent might have.
It also matches the loading order of template files and template parts.
It is also documented everywhere, for years, that this is the order.

#5 @landwire
3 months ago

Thanks. I have not worked with pluggable functions yet. I usually work with namespaces and classes in PHP, so I do not get any conflicts. I understand why you do not want to switch the load order, also with respect to how the templates are loaded. That makes sense.

But if I want to extend a class that the parent defines that is not possible? Is that correct?
I.e: inside the child theme I would like to use:

  use Parent\Utils\FileLoader;

I could only get this to work with the earliest hook after the parent theme is loaded like so:

add_action(
  'after_setup_theme',
  function () {
      $composer_autoload = __DIR__ . '/vendor/autoload.php';
      if (file_exists($composer_autoload)) {
          require_once $composer_autoload;
      }
      ChildFileLoader::loadPhpFiles('inc'); // needs to stay here as it loads class below
      new ChildSite();
  }
);

But then I had problems that "known hooks" to remove parent functionality would not work at all in the child theme like the below. It would be a pain to change all those actions to something later like "init" or whatever as they are used in the parent theme with "after_setup_theme" and often code is copy and pasted.

add_action('after_setup_theme', 'Child\Gutenberg\addGutenbergAssets');

function removeGutenbergFromParentTheme()
{
    remove_action('after_setup_theme', 'Parent\Gutenberg\addGutenbergAssets');
}

Adding the 2 additional hooks, when a child theme is used, would help circumvent that problem.

The below "after_setup_parent_theme" would fire just before "after_setup_theme", so that "after_setup_theme" actions in the child theme would still work as expected.

add_action(
  'after_setup_parent_theme',
  function () {
      $composer_autoload = __DIR__ . '/vendor/autoload.php';
      if (file_exists($composer_autoload)) {
          require_once $composer_autoload;
      }
      ChildFileLoader::loadPhpFiles('inc'); // needs to stay here as it loads class below
      new ChildSite();
  }
);

Just so you know the reason why I am suggesting those hooks.
In the end it will just be about 10 lines of code in wp-settings.php, that will make the use of parent and child themes a bit more flexible, especially if you are not using pluggable functions, but rather extending classes. (Pluggable) functions are not really that easy to extend and often you end up with nearly the same/just slightly different code in the child function. Then you have to maintain the code in two places.

#6 @joyously
3 months ago

Since the child runs first, it can easily put all of its loading into its 'after_setup_theme' hook, and make sure that hook has a higher number for priority than the parent theme.
Simple, done, no new hooks needed.

#7 @landwire
3 months ago

Perfect. Thank you! Did not think of this.

I still have a problem removing a specific action though, which led me to this ticket. I am adding editor styles in the parent theme:

add_action('after_setup_theme', 'Proctor\BlockEditorAssets\loadBlockEditorCSS');

function loadBlockEditorCSS()
{
    $fe_path = FrontendPath::getFrontendPath();

    add_editor_style(get_template_directory_uri() . $fe_path . '/css/cssVariables.css');
    add_editor_style(get_template_directory_uri() . $fe_path . '/css/main.css');
    add_editor_style(get_template_directory_uri() . $fe_path . '/css/gutenberg.css');
}

My child theme loads with after_setup_theme and priority 15 as per your suggestion. That works great and no new hooks are necessary!

In the child theme I then try to remove the CSS from the parent with:

add_action('after_setup_theme', 'Slate\BlockEditorAssets\removeGutenbergAssetsFromParentTheme', 20);

function removeGutenbergAssetsFromParentTheme()
{
    // the JS is removed !!!
    remove_action('enqueue_block_editor_assets', 'Proctor\BlockEditorAssets\loadBlockEditorJS');
    // this does not remove CSS! -> Why?
    remove_action('after_setup_theme', 'Proctor\BlockEditorAssets\loadBlockEditorCSS');
}

Oddly enough it removes the JS, but not the CSS. What could the reason be for this?

#8 @joyously
3 months ago

Your question is a typical support question, unrelated to this ticket. But what your example code is doing is trying to remove an action that has already run, so of course it looks like it doesn't work. You would need to remove the editor style remove_editor_styles() instead of removing the action that adds them (which has already happened).

#9 @landwire
3 months ago

  • Resolution set to invalid
  • Status changed from new to closed

Thank you so much.
I guess I need to dive more into the whole action, order and priority topic and get my head around it.

#10 @desrosj
4 weeks ago

  • Milestone Awaiting Review deleted
Note: See TracTickets for help on using tickets.