XF 2.2 Callback return on load

FoxSecrets

Active member
I am using callback xf syntax which simply returns a string and I've noticed that I can see it only on second load (I think this is the standard behavior).

Is it possible to get the return on first loading?
 
I need to get the parameter in PAGE_CONTAINER and the callback syntax is called from template modification.

How can I do in this case?
 
The callback will run on the first page load, but to be honest callbacks are kind of an option of last resort as there are usually better ways to achieve what they are capable of.

You’d have to post code as well as the expected result and unexpected behavior, or at least describe what you’re trying to accomplish as it feels like an XY problem.
 
Well, my callback just return on second load.

I need to read a cookie value to use in conditional. What would you suggest?

CALLBACK:
Code:
public static function getValue() {
      return $_COOKIE['cookieKey'];
    }


Template modification: PAGE_CONTAINER
Code:
<xf:set var="$myValue">
    <xf:callback class="XF\MY\Class" method="getValue"></xf:callback>
</xf:set>

<xf:foreach loop="$xf.app.db.fetchAll('SELECT item FROM xf_table')" value="$data">
    <xf:if is="({$data.item} == '1' AND {{$myValue}} == 'abc')">
        <h1>Hello World</h1>
    </xf:if>
</xf:foreach>
 
The callback will run on the every load, including the first. Is it possible the cookie isn't set on the initial request? If you're setting it somewhere in the first response, it won't be visible until the second request.

Also, I'd recommend using the response/request objects to write/read cookies, rather than globals.
PHP:
// initial response -- write cookie
\XF::app()->response()->setCookie('cookieKey', 'cookieValue');
// later request -- read cookie
$cookie = \XF::app()->request()->getCookie('cookieKey');
 
Last edited:
The cookie is set on page load. I can see the cookie value on first load in browser inspect, not on page body (which shows on second).
Is callback perhaps running before cookie is recorded?

PS: the response/request objects didn't work for me
 
Last edited:
Also, why the callback value is returning like below and not only "abc"?
I forced return = "abc" to check

1689900668204.png
 
Last edited:
The cookie is set on page load. I can see the cookie value on first load in browser inspect, not on page body (which shows on second).
The application pane will show a live view of currently set cookies, but the actual cookies sent with any given request can vary. If you look at the request headers in the network pane, you can see the cookies which were sent to the server for the selected request:

1689902420667.png

When you set a cookie in a response to one request, the browser will send it back to the server in future requests.

Also, why the callback value is returning like below and not only "abc"?
I forced return = "abc" to check

View attachment 288815
Related to value escaping, for security. Are you trying to <xf:set var="$foo"><xf:callback ... /></xf:set>? If you want to make variables available in a page template, it's best to do what I suggested in my first reply here.
 
The application pane will show a live view of currently set cookies, but the actual cookies sent with any given request can vary. If you look at the request headers in the network pane, you can see the cookies which were sent to the server for the selected request:

View attachment 288818

When you set a cookie in a response to one request, the browser will send it back to the server in future requests.
What you mean? I didn't get it.


Related to value escaping, for security. Are you trying to <xf:set var="$foo"><xf:callback ... /></xf:set>? If you want to make variables available in a page template, it's best to do what I suggested in my first reply here.
Right I'll try it now. Where do I find that callback field in page template? I see only title and textarea

1689905738904.webp
 
They are in the page node options, if you are rendering your template with a page node.
Actually, as I said, it's a feature in PAGE_CONTAINER, not really a page node.
So I believe it's not possible to insert callback directly unless by syntax.
 
Last edited:
Actually, as I said, it's a feature in PAGE_CONTAINER, not really a page node.
So I believe it's not possible to insert callback directly unless by syntax.
Right, sorry. You would typically introduce new page behaviors (and template parameters) by extending a controller. If you need to do this more globally, you can use code events (like templater_template_pre_render or templater_global_data) to add parameters (variables) to templates.

How can I deal with this callback return? How to read it? Some include method?
This would solve my problem, but it's not plain.
In any case, the callback should work ok. It will output its contents where the <xf:callback> tag is placed. If you are saving the value to a variable by wrapping it in <xf:set>, you will get back a pre-escaped object but you should still be able to render it like any other variable:

HTML:
<xf:set var="$output"><xf:callback class="Some\AddOn\Class" method="getOutput" /></xf:set>
{$output}

If you're trying to use it in a conditional or something where you require the unescaped value, you're better off using code events to set the data.
 
Actually, rereading your code with fresh eyes, I understand what you're trying to do now. You don't need a callback to read a cookie, you can just use $xf.request.getCookieRaw('cookieKey'). Since you don't need <xf:callback>, you can store the unescaped value using the alternate <xf:set> syntax:

HTML:
<xf:set var="$cookieKey" value="{{ $xf.request.getCookieRaw('cookieKey') }}" />

You should then be able to use $cookieKey in conditionals like you expect. Apologies for the confusion, though I would still caution against placing this sort of logic directly in templates (even if it is technically possible). It works in a pinch but would likely fall outside of the resource standards for add-ons.
 
Actually, rereading your code with fresh eyes, I understand what you're trying to do now. You don't need a callback to read a cookie, you can just use $xf.request.getCookieRaw('cookieKey'). Since you don't need <xf:callback>, you can store the unescaped value using the alternate <xf:set> syntax:

HTML:
<xf:set var="$cookieKey" value="{{ $xf.request.getCookieRaw('cookieKey') }}" />

You should then be able to use $cookieKey in conditionals like you expect. Apologies for the confusion, though I would still caution against placing this sort of logic directly in templates (even if it is technically possible). It works in a pinch but would likely fall outside of the resource standards for add-ons.
Awesome @Jeremy P , exactly what I was looking for! Very simple! How can I get full syntax XF list? Any documentation?

Despite being a great solution to get cookie, I still notice a delay to get the cookie that I've set on load.
I guess "template modification" comes first that body on load instruction, is that correct? If so, that's the cause of delay I've got.
 
Awesome @Jeremy P , exactly what I was looking for! Very simple! How can I get full syntax XF list? Any documentation?

Despite being a great solution to get cookie, I still notice a delay to get the cookie that I've set on load.
I guess "template modification" comes first that body on load instruction, is that correct? If so, that's the cause of delay I've got.

Despite being a great solution to get cookie, I still notice a delay to get the cookie that I've set on load.
I guess "template modification" comes first that body on load instruction, is that correct? If so, that's the cause of delay I've got.
XenForo is rendered server-side, and JS runs in the browser after the page has already been rendered by the server. The browser can only send cookies to the server that have already been set, so any cookies set in one request will not be visible to the server until later requests.
 
The $xf variable contains global template data. You can dump it to inspect it further with {{ dump($xf) }}, or dump all variables for a given template with {{ dump(vars()) }}. The $xf.request key will give you the \XF\Http\Request object pertaining to the current request.
 
The $xf variable contains global template data. You can dump it to inspect it further with {{ dump($xf) }}, or dump all variables for a given template with {{ dump(vars()) }}. The $xf.request key will give you the \XF\Http\Request object pertaining to the current request.
Great! Thank you so much!
 
Top Bottom