roots / docs

📝 Documentation for Roots projects
https://roots.io/docs/
168 stars 183 forks source link

Sage 10 Child/Parent Theme Support #450

Open ouun opened 4 years ago

ouun commented 4 years ago

Description

Related to this discussion: https://discourse.roots.io/t/sage-10-as-parent-child-themes/ It would be fantastic to get some feedback ftom @Log1x and @QWp6t

Steps to reproduce

1. Parent Theme:

1.1 Make a new Sage 10 Theme with custom Namespace "Parent" in folder 'parent' 1.2 Add some View Composers variables such as "siteName" and reference it in a blade file 1.3 Add a function my_test_function() to helpers.php 1.4 Activate the theme, it should be working and the variable $siteName is outputted correctly

2. Child Theme

1.1 Make a new Sage 10 Theme and leave the Namespace as "App" in folder child 1.2 Add Template: parent to style.css 1.3 Remove all blade files from ./resources/views/ 1.4 Use \Parent\my_test_function() e.g. in a child View Composer 1.5 Autoload parent theme Class in composer.php:

"psr-4": {
      "App\\": "app/",
      "Parent\\": "./../parent/app/"
    }

1.5 Activate the child theme

Expected behavior: [What you expect to happen]

Actual behavior: [What actually happens]

Reproduces how often: [What percentage of the time does it reproduce?]

In the current setup 100%. More tests required.

Versions

Sage 10.0.0-alpha

Additional information

It would be fantastic to get a very short summary how child/parent themes should be set-up with Sage 10.

ouun commented 4 years ago

Regarding Functions from parent theme in helpers.php are available via \Parent\my_test_function() I was able to solve it:

In the functions.php I oversaw that locate_template() is used what checks for files by hierachy (Searches STYLESHEETPATH before TEMPLATEPATH). So as I still had a helpers.php, setup.php, ... in my child/app folder, it loaded the child one and skipped the parent files in parent/app even though they should get included as well (by default). So this is fixable by renaming either the files. In my case I renamed parent/app to parent/inc so the locate_template() function in the parents function.php will recognize them.

So for now I am only confused what the best way is to autload the View Composers from the parent theme.

Cheers

ouun commented 4 years ago

Well, another issue solved. Quite easy and obvious when now thinking about it:

In the child theme config/view.php you have to (of cause) add the composer Classes:

    'composers' => [
        // App\Composers\Alert::class,
        Parent\Composers\Alert::class,
        Parent\Composers\App::class,
        Parent\Composers\Title::class,
    ],

Furthermore if you have custom ServiceProviders in the parent theme, you need to load them as well in /config/app.php:

 'providers' => [
        Parent\Providers\ThemeServiceProvider::class,
        // App\SomeService\SomeServiceServiceProvider::class,
    ],

So my currently only leftover is that it would be fantastic to get config values via \Roots\config() that fallbaks to parent value if it is not overwritten in the child theme.

Log1x commented 4 years ago

Putting this on hold until Sage 10 documentation is finished.

evankford commented 3 years ago

To chime in here from my debugging work, it looks like the current method for adding composers/components from outside the theme directory structure is no longer in config/app.php or config/view.php.

The way I've found to implement composers and components is to implement theme in your child theme's ServiceProvider. Specifically, you'll want to add them into the boot() function as shown in the Laravel documentation for View Composers and manually registering package components. Both of these are a bit clunky, as shown below.

/** ... 
* Inside your ThemeServiceProvider.php file
*/
use Roots\Acorn\ServiceProvider;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\View;

...

 /**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot() {
    // Boot your view composers here. 
    // Note that you have to redefine the 'view' in order for it to use this composer on the correct view partials
    View::composer('view.name', \ParentApp\View\Composers\ViewName::class);

    // Boot your components here. 
    Blade::component('alert', \ParentApp\View\ComposersComponents\Alert::class);

}

This is obviously not great because you have to define your view names, and import all your classes manually. Shouldn't we be able to boot the parent theme's ServiceProvider and bring in all those Composers/Components? Someone with more Laravel/PHP experience may be able to help with that. I have a feeling that if we want a child theme/app to work, we'll need to create a child theme fork.

In the mean time, I hope this helps the poor souls looking to make this work.

gitgudcameron commented 3 years ago

Does anyone have a working example of a Sage 10 parent / child theme for a noob like myself? :)

ouun commented 3 years ago

@gitgudcameron you can have a look at this comment: https://github.com/ouun/stage/issues/204#issuecomment-764809660

slackday commented 2 years ago

Thanks @evankford I was struggling with how to convert a Sage9 child-theme to Sage10 (after parent theme upgrade).

I'm not 100% familiar with Blade/View/Composers yet but following your example I managed to get it working.

In child theme composer file I put

  "autoload": {
    "psr-4": {
      "App\\": "./../sage/app",
      "Child\\": "app/"
    }
  },

To load the parent theme.

I don't think it makes sense to load all components in boot so I don't mind defining each line. For example to use parents theme App I put

View::composer('*', \App\View\Composers\App::class);

And child theme also uses "site messages" in layouts/app.blade.php.

View::composer('site.messages', \App\View\Composers\Site\Messages::class);

However for all the components I found "componentNamespace" in Laravel documentation which is nice so in the boot function I also put

Blade::componentNamespace('\\App\\View\\Components', 'sage');

and can use the parent themes components in the child theme like so <x-sage::page-section>...</x-sage::page-section>

Hope this helps anyone else making a child theme!

edit

Oh yeah... all the child themes View/Composers are namespaced like so namespace Child\View\Composers;

waqas-raza-dh commented 2 years ago

Please let me know If I need to open a new issue for this on github?

Is there any proper guide for setting up the child theme with sage 10? I am using sage 10 as my main theme on WordPress and for customizations, I have to create the child theme. I tried following the above discussion to create the child theme and it does not work. Changing the parent theme's namespace to Parent (from App) breaks the connection between composers and views, data does not go to the views.

Child theme is activated.

getting this error

Undefined variable $heroBackground in section-page-header.blade.php $heroBackground is defined in the Parent\View\Composers\App.php

in the child App.php I have the following code

<?php

namespace App\View\Composers;

use Roots\Acorn\View\Composer;

class App extends Composer
{
}

And in the child theme's App\Providers\ThemeServiceProvider

<?php

namespace App\Providers;

use Roots\Acorn\ServiceProvider;

class ThemeServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //this outputs the correct data from the parent function
        dd((new \Parent\View\Composers\App())->getColorScheme());
    }
}

Any hint about where to go from this point will be much appreciated.

evankford commented 2 years ago

@waqas-raza-dh

Any hint about where to go from this point will be much appreciated.

If I understand from my troubles with this, it's likely that the child theme is not loading the parent's view composer for section-page-header.blade.php. Usually, that would be a SectionPageHeader.php class file in the App/View/Composers folder/namespace.

I'm sure there's a more elegant way to autoload all the parent's composer classes, but I add the ones I need to the boot function in the child's ThemeServiceProvider

 /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        View::composer('index', \Parent\View\Composers\Index::class);
        View::composer('partials.footer', \Parent\View\Composers\Footer::class);

        ... Whatever else you have here

Surely you could programmatically fetch all parent classes, or maybe I'm doing something wrong and they're supposed to be autoloaded, but this works for me.

waqas-raza-dh commented 2 years ago

@evankford thank you for clearing things out for me. So, in my Parent view composer App\View\Composers I am passing some common data to all the views so I am able to get the variables like {{$var}} in my parent blade files. But when I activate my child theme and load the parent view composer in the boot method

View::composer('*', \App\View\Composers\App::class);

it does not make any difference, and I still get the error that variable does not exist.

evankford commented 2 years ago

@waqas-raza-dh Without knowing more, it's hard to say why that's not loading. I would check:

  1. Is the \App namespace the parent or the child app? In your first example, you used \Parent for the parent app.
  2. If you're correctly referencing the file, you should check that the code is loading at all (a var_dump, or inserting some broken code).
  3. Is your child ThemeServiceProvider loading?
waqas-raza-dh commented 2 years ago

@evankford I was able to fix the issue. The issue was within the child stylesheet. So, composer files are loading perfectly now and all the data is also coming through. Is there any correct way of importing parent theme's styles and scripts. Currently I am importing the parent theme's style in my child theme like below

@import "../parent-theme/resources/styles/app.scss"; and when i run the build some css does not load.

smirnizky commented 1 year ago

Hello everybody! Tell me please is there any detailed guide on how to create child theme for Sage 10 properly? Can you give me the URL of such tutorial if it exists? Is this approach recommended at all?

Dathix commented 1 year ago

Hey everyone! I would like to push this discussion further ahead and hopefully, we will come up with a solution that we can incorporate into Acorn and add some official documentation about child themes. I think @ouun has a good starting point here https://github.com/ouun/stage/blob/master/app/Providers/StageServiceProvider.php#L56. I would love to just call attachParentComposers() or even detect the child theme and automatically attach them. What do you guys think, can we make this work a little bit more smooth?

smirnizky commented 1 year ago

@Dathix I think it's a great idea! I want to take part in this task, but I don't have enough skills to do it. I wounder what Sage core team members think about child theme support in future.