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 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
    • By louisstephens
      So I was going to build a todo tracking app for myself to test/broaden my knowledge of processwire, and so far it has been taxing 😓.  My Site structure is:
      - Project One - Phase One - Task - Task - Task - Phase Two - Task - Task - Task So far it was pretty easy, I can easily foreach through the Project and get the phases with their tasks. However, it gets a bit muddled when I have more than one project as I was trying to have a dashboard where the content switches out to the selected project as opposed to accessing each project via their own url. How would yall handle this?
      My next hurdle is each task has a select field (for project status) that I want to update via ajax (for the smooth transitioning).
      Scenario: You finish a task, change the option from "new" to "completed", and an onclick changes the status drop down background to green (which I have working), but then posts/saves a field on the backend to the new option.
       
      I have a page called "Actions" set up with url segments using
      if ($config->ajax && $input->urlSegment1 == 'change-status') { //save update field on admin } However, I am a little fuzzy on how to actually pass the current page along with the new selected status to actually update the page (task). I guess I am not very far into my endeavor. Any help would be greatly appreciated.
    • By louisstephens
      So I have a project where multiple pages are sending POST data to 1 single template page.  All was working well (well, at least with one ajax post), but now I have hit a stumbling block. I figured  the "best" way to handle the request were to use url segments and then use the following in the status page:
      if ($config->ajax && $input->urlSegment1 == 'add-bookmark') { // some code here } However, this doesnt seem to really work (as I assume the the request isnt being posted to /status/ but rather to /status/add-bookmark/). What is the best way to actually handle this?
    • By louisstephens
      Currently, I have a page set up listing all child pages using a foreach loop and outputting some information (thus far, it is all gravy). However, I ran into a slight problem. I have a "button" on each item being rendered that when clicked needs to send the page id to another page for processing via ajax. I thought I could just save the item id like :
      <?php $itemId = $item->id; ?> And then encoding it below in my javascript:
      var itemId = <?php echo json_encode($itemId); ?>; var data = { itemId: itemId, }; $.ajax({ type: "POST", url: "/intra/status/", data: data, success: function(){ console.log(itemId); } }); However, it is only posting the last page's id rendered by the foreach. Have I just overlooked something simple on this?
×
×
  • Create New...