Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

kmsch's avatar
Level 1

Passing a variable into Blade directive doesn't pass variable content, but name of variable

Hi guys,

Probably a beginner's question, but I couldn't find the answer so I'll ask anyway.

I made a custom Blade directive called formatStatus. I'm passing in the status of a payment and want it to return a formatted status (label). I pass in data like this:

@formatStatus ($payment->status)

However, when I dump and die the passed in variable, I just get

"$payment->status"

as a result, not the status itself. Any clue how to fix this?

Regards, Koen

0 likes
16 replies
Cronix's avatar

You'd kind of need to show your custom directive code.

1 like
kmsch's avatar
Level 1

Hi Cronix, that'd be:

Blade::directive('formatStatus', function($status){
            dd($status);
            if ($status == 'valid') {
                $span = "<span class='label label-success'>" . $status . "</span>";
                return "<?php echo $span; ?>";
            }
        });
Snapey's avatar

your custom blade only receives the expression as a string.

you should be able to use single curly braces if you are only passing one parameter - otherwise you need to explode the string into separate variables

try dd({$status})

kmsch's avatar
Level 1

Hi Snapey, if I

dd({status}) 

that simply returns a

Whoops, looks like something went wrong.
(1/1) FatalErrorException
syntax error, unexpected '{'
in AppServiceProvider.php (line 18)

It's really strange, passing a variable into a Blade directive should just work like this right?

Snapey's avatar

This is what is expected. The blade directive only receives a string representation of the variable name, not the variable itself.

Remember that with blade, you are building a view so for instance

return "echo 'your value was' . $expression"; 

will return a string containing the expression which is then rendered when the view is processed.

If you want to process expression within the blade directive and not just pass it to the view then you need to handle it specially.

clearly dd did not work as it was, try this;

dd(with({$status}));

I don't have access to any way to test at the moment.

This thread contains some other ideas.

https://laracasts.com/discuss/channels/laravel/useful-blade-directives

Snapey's avatar

I can't fathom how to eval the code with the arrow operator in it so, to provide your solution you need to evaluate the status in the view and not in the blade pre-processor

Blade::directive('formatStatus', function ($status) {   
    $ret = "<?php if({$status} == 'valid') {";
    $ret .= "echo('<span class=\'label label-success\'>' . $status . '</span>');";
    $ret .= "} ?>";
    return $ret;
});

stueynet's avatar

Here I am resurrecting this thread. @kmsch did you ever figure this one out? I am doing a similar thing where we have a simple blade directive and want to pass it a variable just like we would do with built in directives. Nothing seems to work.

@custom($variable)simply gives you $variable. Here is the directive:

Blade::directive('custom', function ($input) {
    return <?php echo $input; ?>
});

// $input
kmsch's avatar
Level 1

Hey @stueynet , I'm afraid not, I chose to make a class myself and share an object of that across all my views and use that. An example:

<?php
 <td>{!! $style->statusLabel($subscription->status) !!}</td>
?>

I'm sure there's plenty wrong with this approach, but it works. I'd be open to a more elegant solution though.

Snapey's avatar

@stueynet You are building a macro in blade. You need to return a string that will be evaluated later

Blade::directive('custom', function ($input) {
    return "<?php echo " .  $input . "; ?>";

});

ie, with quotes around, you return the string.

paulheijman's avatar

I had the same problem with $status. Seems like $status is a reserved word in Blade. Changing it to $stat works...

saidbakr's avatar

Simply to solve this issue, you may regard the directive output something like encapsulating PHP code in a clean way inside the view, or you may regard it like eval. I will show an example, that apply this idea:

Blade::directive('jobBg',function($job){
            return '<?php 
               if (isset($job->started) && !isset($job->completed)){
                   echo " style=\"background-color: #00FF00;\"";
               }
               elseif (isset($job->started) && isset($job->completed)){
                   echo " style=\"background-color: #9c9c9c;\"";
               }
            ?>';
        });

In the view, I use it like the following:

@foreach ($machine->jobs()->paginate(config('fox.pagingPerPage')) as $job)
  <tr @jobBg($job)>

In the above example, you must consider it like eval so, the variable $job must be already defined i the view before calling the directive. Of course the above solution may be generalized by using the name of the variable name. i.e $$job

2 likes
amitshahc's avatar

This one is very odd usage. what if i want to pass some date as string and timezone so that i can print the local time on the template? This kind of approach is waste. it doesn't meet its goal.

public function registerBladeDirectives()
    {
        \Blade::directive('localtime', function ($datetime, $timezone = null) {
            dd($datetime);
            $datetime_carbon = \DateTimeOperations::getCarbonObject($datetime);
            $timezone = $timezone ?? config('app.timezone');
dd($datetime, $datetime_carbon);
            return "<?php echo ($datetime_carbon->setTimezone($timezone)->toDayDateTimeString(), $datetime_carbon->tzName); ?>";
        });
    }

so calling @localtime($appointment->start_time, $shop->timzone) will just print "$appointment->start_time" i can't get the parsed value inside it.

Bowiemtl's avatar

@Snapey ah ofcourse, I should've figured this out the moment I even got errors changing up my code. Thank you

Perturbatio's avatar

This is an old one, but I've just encountered a similar issue.

The best (hacky) way I've found to deal with this is to do something like the following:

/**
 * @var string $key
 * @var string $default
 */
$key     = $params[0];
$keyIsVariable = false;
/**
 * This is a little bit hacky, but if the key begins with a $
 * assume it's a PHP var being passed in and let the template evaluate that
 * otherwise we'll assume the key is a string
 */
if (substr($key, 0, 1) === '$'){
    $keyIsVariable = true;
}

if ($keyIsVariable) {
    return /** @lang PHP */ <<<DIRECTIVE_CODE
<?= useItAsAVarToBeParsedLater($key, '$default'); ?>
DIRECTIVE_CODE;
} else {
    return /** @lang PHP */ <<<DIRECTIVE_CODE
<?= useItAsAString('$key', '$default'); ?>
DIRECTIVE_CODE;
}

so if your param[0] is a variable you can use it as such and if it's a string, do the alternative

Perturbatio's avatar

OR, create a third param and use

$keyIsVariable = filter_var(Arr::get($params, 2, false), FILTER_VALIDATE_BOOLEAN) ;

Please or to participate in this conversation.