How to customize header and footer in tutor mfe

“mfe-dockerfile-post-npm-install-account”,
“”"
RUN npm install ‘@edx/brand@git+https://github.com/allenluna/VXI_Brand-OpenEdx.git#main’
“”"
),
am i doing right? seems not working, or I just need to remove the @edx/brand@git?

after saving I did tutor images build mfe --no-cache followed by tutor local stop and start

Thank you @dcoa

Hi, @Yagnesh

i need to customize my tutor local openedx header to show 2 logos nearby
so i have done cloning this repo and make changes in Logo.jsx and created a plugin file and it install my git repo and uses my changes

but when i build the mfe with no cache it shows like the things from my git is installing
after build success the changes are not reflecting in the lms header as the default header is loading
why ? is there any other method for my requirement(2 logos on header)

someone please help if you know
current version 20 + (teak version)

Hi @Akhil
Open edX already exposes plugin slots in the header specifically for this purpose:

:link: https://github.com/openedx/frontend-component-header/tree/master/src/plugin-slots

You can inject your custom React component (e.g. a second logo) via a plugin, without forking or modifying Logo.jsx.

Thank you for the reply @Abdul_Muqadim

i have tried this like created a env.config.jsx and the contents are like this :

import React from 'react';

import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';

import { getConfig } from '@edx/frontend-platform';




const InsertTwoLogos = () => {

  const cfg = (typeof getConfig === 'function' ? getConfig() : window.APP_CONFIG) || {};

  

  const schoolLogo = cfg.SCHOOL_LOGO_URL || '/theming/asset/images/logo_main.png';

  const SecondLogo = cfg.LOGO_URL || '/theming/asset/images/secondlogo.png';




  return (

    <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>

      <img src={schoolLogo} alt="School" style={{ height: 36 }} />

      <img src={SecondLogo} alt="second" style={{ height: 36 }} />

    </div>

  );

};




const config = {

  pluginSlots: {

    // using the logo slot (recommended)

    'org.openedx.frontend.layout.header_desktop.v1': {

      keepDefault: true, // keep the default logo and add ours next to it

      plugins: [

        {

          op: PLUGIN_OPERATIONS.Insert,

          widget: {

            id: 'dual_logo_widget',

            type: DIRECT_PLUGIN,

            RenderWidget: InsertTwoLogos,

            priority: 50,

          },

        },

      ],

    },

  },

};




export default config;

and this file is in the same directory of the plugin file for this and plugin file :

import os

from tutor import hooks




PLUGIN_DIR = os.path.dirname(__file__)




# Ensure the MFE build picks up env.config.jsx from the plugin dir

hooks.Filters.ENV_TEMPLATE_ROOTS.add_item(PLUGIN_DIR)





hooks.Filters.ENV_PATCHES.add_item((

    "mfe-dockerfile-post-npm-install",

    """

# Install atlas (Python 3 version)

RUN python3 -m pip install --upgrade pip setuptools wheel

RUN python3 -m pip install atlascli

"""

))




hooks.Filters.ENV_PATCHES.add_item((

    "mfe-dockerfile-pre-npm-install",

    """

ENV SHARP_DIST_BASE_URL=https://npm.taobao.org/mirrors/sharp-libvips/

RUN apt-get update && apt-get install -y libvips-dev build-essential python3

"""

))

after the mfe image build the changes(two logos) not reflected as the default learner dashboard with the tutor logo is appearing

anything wrong?

1 Like

Hi @Akhil,

A more reliable approach is to create a plugin Python file that directly registers your custom React widget via the PLUGIN_SLOTS API. Here’s a working pattern you can follow:

import os
from tutormfe.hooks import MFE_APPS, PLUGIN_SLOTS
from tutor import hooks

# Path to your plugin directory
PLUGIN_DIR = os.path.dirname(__file__)

# Example: Add a widget to the learner dashboard header
PLUGIN_SLOTS.add_item(
    (
        "learner-dashboard",            # MFE you want to target
        "desktop_main_menu_slot",       # Slot you want to inject into
        """
        {
            op: PLUGIN_OPERATIONS.Insert,
            widget: {
                id: 'custom_header',
                type: DIRECT_PLUGIN,
                RenderWidget: () => <SomeComp />,
                ),
            }
        }
        """
    )
)

Key points:

  1. Replace "learner-dashboard" with the MFE where you want your logos to appear.

    • Example: "studio" or "all" if you want it everywhere.
  2. Replace "desktop_main_menu_slot" with the slot you want to use in that MFE.

  3. The RenderWidget can be a simple React component or inline JSX like above.

  4. Make sure this Python plugin is picked up by Tutor by placing it in your plugin directory

1 Like

hi @Abdul_Muqadim

Thanks you it works!

but the thing is the /courses page is not getting the mfe pluginslot changes as per checking i found its a legacy page. so how can i customize the /courses page?
please give a solution

Tutor teak version

Hi,

Yes, that’s expected behavior.

The plugin slots only work with MFEs. The /courses page is a legacy LMS page, so MFE plugin slots will not apply there.

For legacy pages, customization needs to be done by modifying the LMS templates directly.

Since you’re using Tutor Indigo, you can update the header (and other UI parts) from here:

https://github.com/overhangio/tutor-indigo/tree/release/tutorindigo/templates/indigo/lms/templates/header

These template files control the header for legacy pages, including /courses.
You can override or modify them to apply your required changes.

Hi, i have changed like this and installed plugin and after build and restart the changes are not getting reflected as the default indigo is getting loaded..
why ?


hooks.Filters.ENV_TEMPLATE_ROOTS.add_item(
    os.path.join(PLUGIN_DIR, "templates")
)

hooks.Filters.ENV_PATTERNS_INCLUDE.add_items([
    r"indigo/lms/templates/header/navbar-logo-header.html",
    r"indigo/lms/templates/header/navbar-authenticated.html",
    r"indigo/lms/templates/footer.html",
    r"indigo/lms/static/sass/extra/_header.scss",
])

Hi @Abdul_Muqadim
i have customized the pages using plugin slots and it works but the /courses page is not getting the header and footer changes …
isn’t it a mfe app ? if not how to customize it ?
all my pages getting my custom header and footer through frontend plugin slots