Steps to use Livewire with Acorn 4.0

Hej,

since roots/acorn:4.0 we have official support forlivewire/livewire (Enhanced Router Compatibility (Including Livewire Support) And Filters For Early Service Container Overrides by broskees · Pull Request #291 · roots/acorn · GitHub).

I tried to follow the mentioned steps in the related PR and found some needed changes (for me). But unfortunately, although it first seems to work, I ran into an issue related to the session / nonce / CSRF.

Currently the @livewireScripts or the ESM version @livewireScriptConfig won’t set a CSRF token, which will break on events like wire:click or wire:submit.

Has anyone a hint, why the csrf_token() will return null? Am I missing something?

Best,
Daniel

1 Like

… I tried to debug this and am quite not sure if I miss something fundamental.
It seems that the session will not be persistent between different requests. Secondly, at every point in code, the function csrf_token() will return null.

However, at the moment, I’m applying the following workaround to ensure that the Livewire components function properly:

In the layout file, I add:

<meta name="csrf-token" content="{{ Str::random(40) }}">

This will provide the Livewire JS code the required token.

1 Like

I’ve encountered same issue in the past where the CSRF token wasn’t generated on pages managed by WordPress itself.

I guess it’s due to WordPress pages aren’t managed by the Laravel router, so doesn’t trigger a middleware that initiates the session which generates the token.

This is my current workaround:

/**
 * Start Laravel Session after WordPress loaded.
 */
add_action('wp_loaded', fn () => app('session')->isStarted() || app('session')->start());
3 Likes

How did you both manage to handle the multiple instances of livewire being loaded?

Whenever I use wire:navigate this is what happens

I assumed you followed this guide,

https://github.com/iniznet/csrf-token-workaround/commits/main

Then, this link should help you,
https://livewire.laravel.com/docs/installation#manually-bundling-livewire-and-alpine

Thanks, I was already loading everything through the livewireconfigs:

collect([‘wp_head’ => ‘@livewireStyles’,
‘wp_footer’ => ‘@livewireScriptConfig’,
])->each(fn ($directive, $hook) =>
add_action($hook, function () use ($directive) {
echo Blade::render($directive);
})
);

My issue is that using wire:navigate keeps re-initiating everything whenever I press on a link.
grafik

Here is a working solution that I use:

This is an Acorn bootloader as a WP Must Use plugin:

<?php

use Roots\Acorn\Application;
use Sentry\Laravel\Integration;
use Roots\Acorn\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Foundation\Http\Middleware\ValidateCsrfToken;

/**
 * Plugin Name:  Acorn Bootloader
 * Plugin URI:   https://gitlab.com/rehashx/rehash-wp
 * Description:  Acorn must be booted in order to use it. This plugin handles Acorn booting.
 * Version:      1.0.0
 * Author:       Rehash
 * License:      MIT License
 */
if (! function_exists('\Roots\bootloader')) {
    wp_die(
        __('You need to install Acorn to use this site.', 'domain'),
        '',
        [
            'link_url' => 'https://roots.io/acorn/docs/installation/',
            'link_text' => __('Acorn Docs: Installation', 'domain'),
        ]
    );
}

function acorn_bootloader(): void
{
    $app_builder = Application::configure();
    $app_builder->withExceptions(function (Exceptions $exceptions) {
        Integration::handles($exceptions);
    });
    $app_builder->withMiddleware(function (Middleware $middleware) {
        $middleware->web(append: [
            ValidateCsrfToken::class,
        ]);
    });
    $app_builder->boot();
}

add_action('after_setup_theme', 'acorn_bootloader');

function acorn_bootloader_start_session(): void
{
    $session = app('session');

    if (!$session->isStarted()) {
        if (!empty($_COOKIE[$session->getName()])) {
            $session->setId($_COOKIE[$session->getName()]);
        }
        $session->start();
    }
}

add_action('init', 'acorn_bootloader_start_session');

function acorn_bootloader_save_session(): void
{
    $session = app('session');

    if ($session->isStarted()) {
        $session->save();
    }
}

add_action('shutdown', 'acorn_bootloader_save_session');

Thank you it works !

I build manually livewire and alpine (with some plugin) with radicle, and that was the missing part to work nicely :wink:

For information i just have a LivewireServiceProvider with

public function register(): void
    {
        add_filter('wp_head', function () {
            echo Blade::render('@livewireStyles');
        });

        add_filter('wp_footer', function () {
            echo Blade::render('@livewireScriptConfig');
        });

        add_action('wp_loaded', fn () => app('session')->isStarted() || app('session')->start());
    }

and app.ts is

// We add Livewire/Alpinejs manually to be more flexible
// @see https://livewire.laravel.com/docs/alpine#manually-bundling-alpine-in-your-javascript-build
import {Livewire, Alpine} from '../../vendor/livewire/livewire/dist/livewire.esm';
import resize from '@alpinejs/resize'

Alpine.plugin(resize)

Livewire.start()

import.meta.webpackHot?.accept(console.error);

cheers.

You are missing:

add_action('shutdown', 'acorn_bootloader_save_session');

shutdown is the last WP action and therefore I am using it to save the session to disk.