Jump to content
entschleunigung

Call to undefined function wire() with Ajax

Recommended Posts

hello,

i have a _func.php file with this function. in the documentation i read that some api variables in functions are not available, so i use wire('pages').

function doSomething($u, $p) {
    $p = wire('pages')->get("id=$p");
    $u = wire('pages')->get("id=$u");
    $p->of(false);
    { ... populate repeater field stuff }
    $p->save();
}

if i call this function in my home.php like doSomething(41,1093) (only for testing!) everything is fine, the function works, it add items to a repeater field.

 

the german says "Wenn es dem Esel zu wohl ist, geht er aufs Eis", so i play around with ajax to fire up this function. 

$(document).ready(function() {
	$("#hit").click(function(){
		$.ajax({
                url: '<?= $config->urls->templates?>includes/_func.php/',
                type: 'post',
                data: {userID: "<?= $user->id ?>", pageID: "<?= $page->id ?>"},
                success: function(output){
                	console.log(output);
                }
            })
	})
})

 

i read something about variable scopes and i think i understand it a little bit. but i don't understand why doSomething(41,1093)  works in home.php the ajax call runs into a Call to undefined function wire() ?   also i tried if ($config->ajax) but no luck ...

that's the relevant party of  _func.php. 

function doSomething($u, $p) {
    $p = wire('pages')->get("id=$p");
    $u = wire('pages')->get("id=$u");
    $p->of(false);
    { ... populate repeater field stuff }
    $p->save();
}

if(isset($_POST['userID']) && !empty($_POST['userID']) && isset($_POST['pageID']) && !empty($_POST['pageID'])) {
	$u = $_POST['userID'];
	$p = $_POST['pageID'];
	{ ... }
	echo sendLike($u, $p);
}

 

where is my mistake? any ideas? 

 

thx

 

Share this post


Link to post
Share on other sites

Are you using the latest master?

If you haven't already, try adding a ProcessWire namespace to your file, or use function ProcessWire\wire :

 

<?php

namespace ProcessWire;
use function ProcessWire\wire;

 

  • Like 1

Share this post


Link to post
Share on other sites

Did you declare namespace in your file? 

<?php namespace Processwire; 

 

  • Like 1

Share this post


Link to post
Share on other sites

When you're sending a request to a file that's not called by ProcessWire, wire() will not be defined. You need to bootstrap processwire manually using

include '../../../index.php' at the top of your _func.php

  • Like 1

Share this post


Link to post
Share on other sites

hi abdus,

i know about bootstraping the index.php, but why the function works with direct call the function in home.php and with ajax not?

and this is the message, when i bootstrap index.php: Error: Cannot redeclare doSomething()

thx

Share this post


Link to post
Share on other sites

Wrap the function with

if(! function_exists('doSomething')) {
    // function doSomething() {...} 
} 

It works when used inside home.php because _func.php was included after the PW took over the request. But when you're calling the function directly apache calls _func.php instead of index.php and PW will not be defined until you include it.

http://php.net/manual/en/function.function-exists.php

  • Like 4

Share this post


Link to post
Share on other sites
4 hours ago, entschleunigung said:

url: '<?= $config->urls->templates?>includes/_func.php/',

It's often better to use a PW page for your AJAX url than a standalone PHP file - just create a special template / template file / page for the purpose and call it in your AJAX function. That way everything in PW, init.php, etc, is available just like normal.

  • Like 5

Share this post


Link to post
Share on other sites

I certainly agree. I create a template and page called api for basic JSON outputs.

One other method to handle arbitrary urls without using any page/template can be hooking into ProcessPageView::pageNotFound like this

// /site/ready.php

wire()->addHookBefore('ProcessPageView::pageNotFound', function (HookEvent $e) {
    if ($e->input->url === '/api/create/') {
        $pageId = $e->input->post->int('id');
        $content = $e->input->post->text('text');

        // your logic
        // or hand it to another function / class etc.

        header('Content-Type: application/json');
        echo json_encode([
            'pageId' => $pageId,
            'content' => $content
        ]);
        exit();
    }
});

 

  • Like 5

Share this post


Link to post
Share on other sites

sorry for the late reply.

i check everything but nothing works for me at this moment, i will try a new installation of pw, perhaps i misconfigured something ... ?!

(abdus, your last tipp i didn't try because i want start with a fresh installation, but thanks for the hint!)

thanks for all tipps.

Share this post


Link to post
Share on other sites

Hey enschleunigung,

one way to make this work would be the following:

Instead of sending the Ajax request to your _func.php send it to any normal page. This way all the ProcessWire features will be initialized. Then in your _func.php you can do

 

function doSomething($u, $p) {
	// ...
}

if($config->ajax && $input->post->userID && $input->post->pageID) {
  echo doSomething($input->post->userID, $input->post->pageID);
  
  die(); // just output the content, do not process the templates
}

 

There are better ways to structure the code, but it will get you started.

  • Like 1

Share this post


Link to post
Share on other sites
20 hours ago, MrSnoozles said:

die(); // just output the content, do not process the templates

Please do NOT die :) There are other explanations in the forum about why but here is one too: 

https://webdesign.tutsplus.com/tutorials/processwire-tricks-and-tips--cms-28613

<?php
if ($config->ajax) {
 // AJAX content
 echo my content’;
 // Calling halt() stops template rendering but continues towards ProcessWire’s normal shutdown.
 return $this->halt();
}
// non AJAX content below

 

  • Like 3

Share this post


Link to post
Share on other sites

@szabesz in templates, sure, using return $this->halt() is a better solution, but in functions or classes or anywhere outside template context, there's no option but to exit; or die; to stop PHP from processing further.

  • Like 3

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Brian Scramlin
      I just wanted to share that I added an AJAX-powered gallery to an artist website that I developed and host: https://jackpinecreations.com/gallery/

      There were two things that frustrated me about creating this. Perhaps you can show me a better way.
      1. After creating my processing script, which I placed under /templates/scripts/get-items.php, I realized that I would get a 403, due to ProcessWire's routing and security. This forced me to have to create a template and page for this little script. This was frustrating simply because it seemed unnecessarily confusing. But worse, see #2.
      2. I usually use config.php to prepend and append each of my templates with a head.inc and foot.inc, which keeps my templates easy to use and I don't have to go and use the GUI to do so on each template separately. However, since I realized I needed to create a new template and page so as to access it, whenever I sent POST params to it, I would get the header and footer along with it!!! I could find no workarounds and had to remove the pre/append calls in config.php and use the GUI on each template individually.  
      Code Below if you're interested:
      HTML and JavaScript (forgive my sad JavaScript skills, I know this can be tightened up)
      <!-- Begin Grid --> <div class="container mt-4"> <div id="gallery" class="row"> <?php foreach ($page->children("limit=9") as $child): ?> <div class="col-6 col-md-4 gallery-item"> <a href="<?= $child->url ?>" title="View <?= $child->title ?>"> <img class="gallery-item" src="<?= $child->item_featured_image->size(640, 640)->url ?>" alt="<?= $child->title ?> Image"> </a> </div> <?php endforeach; ?> </div> </div> <!-- End Grid --> <div class="center-block text-center"> <button id="get-more-items" type="button" name="get-more-items" class="btn-vintage">Load More</button> </div> <script type="text/javascript"> var buttonGetItems = document.getElementById("get-more-items"); var indexStart = 0; buttonGetItems.addEventListener("click", function() { indexStart += 9; $.ajax({ url: '<?= $pages->get(1186)->url ?>', type: "POST", dataType:'json', // add json datatype to get json data: ({page_id: <?= $page->id ?>, index_start: indexStart}), success: function(data){ console.log(data); if (data[1]) { //for each element, append it. $.each(data, function(key, value) { $("#gallery").append(value); }); } else { $("#get-more-items").after('<p class="center-block text-center">There are no more items to load.</p>'); $("#get-more-items").remove(); } } }); }); </script> Processing Script
      <?php $items_array = []; $i = 0; foreach ($pages->get($input->post->page_id)->children->slice($input->post->index_start, 9) as $child) { $i++; $items_array[$i] = "<div class='col-6 col-md-4 gallery-item'> <a href='$child->url' title='View $child->title'> <img src='{$child->item_featured_image->size(640,640)->url}' alt='$child->title Image'> </a> </div>"; } echo json_encode($items_array); I love ProcessWire for hundreds of reasons, but I've been using AJAX more and more, and I'm not liking having to create templates to access scripts. 
      Any advice?
    • By celfred
      Hello,
      I'm facing a weird issue here. I have a page loaded with this code inside (my comments in line ends) :

      if ($session->allPlayers) { // Set in a head.inc file. I have also a $session->set('allTeams', $allTeams); in my head.inc   $allPlayers = $session->allPlayers; } else {   $allPlayers = getAllPlayers($user, false);   $session->set('allPlayers', $allPlayers); } bd($session->getAll()); // HERE, I get a number of 11 variables which is what I expect In the same page, I have a link pointing to ajaxContent.php that loads stuff via Ajax.
      I just write this in my ajaxContent.php to test :

      bd($session->getAll()); // HERE, I get only 9 variables. All my newly set $session variables ($allTeams and $allPlayers) are not conveyed to ajaxContent.php ??? Would you have any idea why is that ??? Another thing : I have a $session->headMenu set in my head.inc, and this one works fine. I can retrieve it in my ajaxContent.php page.
      I've tried cleaning all caches but it doesn't change anything 😞 
      At first, I expected it to be a 15-minute update to my site... It turns out to be a 2-hour issue and I'm still  stuck.
      Thanks for your ideas ! 
    • By louisstephens
      So I have a template called "development" where I am testing out a few ideas etc set up on a local mamp server. I also have a page called "ajax" using a template called ajax. From my development template, I am posting a form using ajax and all is working quite well:
      $('.test').click(function(event) { event.preventDefault(); redirectUrl = $(this).data('redirect'); var data = { firstName: $("#firstname").val(), lastName: $("#lastname").val(), email: $("#email").val(), phone: $("#phone").val(), redirectUrl: redirectUrl }; $.ajax({ type: "POST", url: "localhost:8888/sandbox/ajax/form/", data: data, success: function() { console.log(this.data); top.window.location = redirectUrl; }, failure: function() { console.log(this.data); } }); And in my ajax template:
      if($input->urlSegment == 'form'){ if ($_POST) { //handle the post } } The redirectUrl is a data attribute I added in to the button (that launches the form in a modal) that pulls in from a field in processwire. Everything works just fine locally, but when I export everything to a live site it fails. It will work 1 time and redirect, but if you go back to resubmit, it submits the data but won't redirect. Can anyone see any glaring issue here, or have a better way around this?
      ------------------------------
      So, it turns out the request to /ajax/form/ was being canceled. It still handled the POST request, but never sent back a 200 to show "success". Adding in 
      return false; at the end of my .onclick solved the issue. It is strange though as I have never had this issue before.
    • By rushy
      Hello. I have recently adopted PW markup regions and really like this way of working. However, I am also trying to learn how to use Ajax and I am not sure of a good way to use the two together. Has anyone got any experience, tips or hints on using them together? For ajax -  I've used a simple scheme where I have a "webservice" template and page that handles Ajax requests and returns the appropriate content wrapped with some markup for the requesting page. I have markup regions enabled and all my pages (bar webservice) include a _main.php which brings in the headers, a default body and the footer. My javascript intercepts the page links and does my ajax call to webservice and that sends back the appropriate markup which is then placed by in the div #body defined in _main.php.  Does this seem a reasonable way to work? I guess I am looking for some advice before I invest too much time going the wrong way!
      Any guidance, remarks,  comments, or a nudge in the right direction greatly appreciated.
      Paul
    • By gerald
      In my frontend I would like to implement a small AJAX-solution, but it does´nt work. For example:
      template/js/ajax.js: contains jquery-ajax-snippet with click-function like this: $.post('ajax.inc', function(e) {});
      template/ajax.inc: contains db-query with HTML-output
      template/home.php: contains div-element for the ajax-response, e.g. <div id='result'>...ajax-response...</div>
      It seems, PW does´nt allow database-requests via AJAX (jquery). I know the post from Ryan "How to work with AJAX driven content in ProcessWire". But this solution requires a completely new template-concept. I only need a simple solution for a small ajax-db-request.
      Thanks to all
×
×
  • Create New...