Why does CakePHP producing those URLs
<server>/Reporting/OnlineBanking/index/page:1
instead of
<server>/Reporting/OnlineBanking/index?page=1
There are alot of trouble with this using relative paths out of JavaScript for example.
And is there an option to change it?
Pagination with get parameters
By default, all parameters in CakePHP are named parameters (url fragments like /foo:bar/). This also applies, by default, to pagination arguments.
To use get arguments for pagination params - you can do that by setting appropriate config:
public $paginate = array(
'paramType' => 'querystring'
);
This will generate urls of the form:
/the/url?page=1&limit=10
Instead of:
/the/url/page:1/limit:10
Specifying urls as string is extremely fragile
Previously you mentioned using urls like get_backend_requests in javascript.
You will still find problems if you do that even using get arguments of pagination. That's because even for the "same" url, the result can be different:
/the/url => /the/get_backend_requests
/the/url/ => /the/url/get_backend_requests
Instead - specify urls in javascript as absolute urls:
$.ajax({
type: 'POST',
url: "/xyz/get_backend_requests",
...
If you're app is sometimes (or always) installed in a subfolder, you can account for that with a simple function:
e.g. in your html/layout put:
<html>
...
<script>
function url(url) {
return <?php
$base = rtrim(Router::url('/'), '/');
if ($base) {
echo "'$base' + ";
}
?>url;
}
</script>
Which will output:
<html>
...
<script>
function url(url) {
return '/subfolder' + url;
}
</script>
$.ajax({
type: 'POST',
url: url("/xyz/get_backend_requests"), // becomes the string "/subfolder/xyz/get_backend_requests"
...
Related
This question already has an answer here:
Calling PHP function from wordpress in ajax?
(1 answer)
Closed 5 years ago.
It's very difficult for me to learn the basics of AJAX since I was managed to find only complicated examples. In fact, I want to do an apparently simple thing, but I wasn't able to find any easy solution. There are numerous instructions how to use AJAX to check various forms, etc. But there is few data how this technology work in WordPress.
The official instruction was useless to me as well:
https://codex.wordpress.org/AJAX_in_Plugins
What exactly I need?
For example, I have some function in functions.php. Let it be a just simple string:
<?php
function do_echo() {
echo "Hello";
}
Now, I want to create a button inside my post and call do_echo() using AJAX.
<button class="my_button" type="button" role="button">Click Me</button>
So, the first and foremost thing I want to do is just push on the button and get "Hello, world!" displayed.
Of course, in fact, I need to execute the more complicated function. But, first of all, I need to do these simple things.
I realize that I need to do something like this using jQuery
$.ajax({
url: '/path/to/file',
type: 'default GET (Other values: POST)',
dataType: 'default: Intelligent Guess (Other values: xml, json, script,
or html)',
data: {param1: 'value1'},
})
.done(function() {
console.log("success");
})
.fail(function() {
console.log("error");
})
.always(function() {
console.log("complete");
});
I understand that I need to do something like this in PHP
add_action('wp_ajax_(action)', 'my_action_callback');
add_action('wp_ajax_nopriv_(action)', 'my_action_callback');
But I can't understand what exact steps I need to do to attach these things to WordPress.
Can anyone assist me with the simple instruction how to call any PHP function from functions.php in WordPress using AJAX when the button was clicked?
Thank you in advance.
Okay, let's write simplified example for this.
Here is a sample for functions.php:
add_action('wp_ajax_nopriv_sayhello', 'say_hello_function');
add_action('wp_ajax_sayhello', 'say_hello_function');
function say_hello_function(){
echo 'hello';
exit();
}
And this is front-end part:
<button class="my_button" type="button" role="button">Click Me</button>
<script>
jQuery(".my_button").click(function(){
jQuery.get(ajaxurl,{'action': 'sayhello'},
function (msg) { alert(msg);});
});
</script>
UPD:
To display returned data in your website content:
<script>
jQuery(".my_button").click(function(){
jQuery.get(ajaxurl,{'action': 'sayhello'},
function (msg) { jQuery(".result_area").html(msg);});
});
</script>
To get above code working you need to have a div with "result_area" class.
<div class="result_area"></div>
The best pratice is using WP Rest API
Wordpress provide an simple and organized way to add API Routes that return JSON.
You can register your routes in function.php or another loaded file.
Major WP files will be loaded and you can use your functions.
WP example:
<?php
/**
* Grab latest post title by an author!
*/
function my_awesome_func( $data ) {
$posts = get_posts( array(
"author" => $data["id"],
) );
if ( empty( $posts ) ) {
return null;
}
return $posts[0]->post_title;
}
add_action( "rest_api_init", function () {
register_rest_route( "myplugin/v1", "/author/(?P<id>\d+)", array(
"methods" => "GET",
"callback" => "my_awesome_func",
) );
} );
I'm trying to return a query made in a controller to the view file so I can use that data in my form. But I am unable to successfully return the data without errors. I know the function is working because it returns the right data but has an error.
Here is my CustomersController fill function which is running the sql query.
public function fill(){
$layout = 'ajax';
$this->autoRender = false;
if ($this->request->is('post')) {
$id = $this->request->data['id'];
$query = $this->Customers->find()
->where([
'id' => $id
])->first();
echo json_encode($query);
}
}
and here is my blah.ctp which is the view file.
<?php use Cake\Routing\Router; ?>
<?= $this->Form->create(Null, ['type' => 'POST']) ?>
<?php
echo $this->Form->input('customer_id', ['options' => $customers, 'empty' => true,'id'=>'customers']);
?>
<?= $this->Form->end() ?>
<script>
document.getElementById('customers').addEventListener('change',function(){
var id = this.value;
var csrfToken = $('[name=_csrfToken]').val();
$.ajax({
type: "POST",
url: '<?php echo Router::url(array("controller" => "Customers", "action" => "fill")); ?>',
data: {'id' : id},
beforeSend: function(xhr){
xhr.setRequestHeader('X-CSRF-Token', csrfToken);
},
success: function(data){
alert(data);
}
});
});
</script>
Currently this is what happens when I select a customer in my drop down box which triggers the script in the view.
As you can see it returns the array of data I need but also has the error cannot emit headers. I have tried solving this error following other questions on stack overflow but can't solve it.
I've tried using $this->set instead of echo json_encode but it always returns nothing. I'm not sure what other way to do this.
First of all, If you're selecting a single record by a unique ID, you can call
->get($id) on the table object directly, instead of building a query chain with ->find().
CakePHP 3.x should automatically handle converting your view to JSON by using the RequestHandlerComponent. Typically, you must enable it if your scaffolding or installation didn't.
1) Enable request handler component. (If not already enabled) https://book.cakephp.org/3.0/en/controllers/components/request-handling.html
2) Remove the echo json_encode($query) line; you should not echo anything as this will break the request/response cycle. This is the cause of your error.
Instead, you should serialize your data to the view. Assuming you have the fetched data in $data: $this->set(compact('data')). Then, make sure you add $this->set('_serialize', ['data']) (again, assuming the data is stored in variable name 'data').
3) Reference this doc for information on how you can request the json. You can use a file extension (.json, .xml).
Also, make sure you add the 'Accept: application/json' header to your request.(https://book.cakephp.org/3.0/en/development/routing.html#Cake\Routing\Router::extensions).
I apologize for the fuzzy response. There are many ways to achieve this with CakePHP3. Please see this doc page for more information: https://book.cakephp.org/3.0/en/views/json-and-xml-views.html
Please, explain to me how to run snippet CookieList with ajax?
I tried next:
1. Created snippet ajaxCookieList:
<?php
if (isset($_POST["action"])) {
$values = $modx->runSnippet('addToCookieLIst',array(
'value' => $_POST['action']
));
$output = $modx->runSnippet('pdoResources',[
'parents' => 6,
'resources' => $values,
'tpl' => 'popup.favorites.item',
'includeTVs' => 'header.bgImage,franchise.logo,franchise.price,title,subtitle',
'prepareTVs' => '1',
'hideContainers' => '1'
]);
return $output;
}
Then i created chunk with this code:
<script>
jQuery(function($){
$('a.franchise-pin, a.franchise-favorite-add').click(function(e){
var value = $(this).data('value');
$.post(document.location.href, {action: value}, function(data) {
$('#favorites').html(data);
$('#favorites').modal('show');
});
e.preventDefault();
});
});
</script>
But response is all page..
What is wrong?
What I usually do in such cases:
I place a snippet call ([[!ajaxCookieList]]) on a service page
accessible via URL like /page-with-snippet/
In JS (ajax) I use that URL to which I send parameters
The snippet has to get the parameters I send. So, I really call it like this: [[!ajaxCookieList? &action=[[!#POST.action]]]]
Access to parameters in snippets is possible like this: $option = $modx->getOption('action', $scriptProperties, 'default_value', true);
I do my stuff in the snippet
But in your case, I think, everything can be simpler. You use one of the pdoTools snippets and if I am not mistaken, you can just place pdoResources snippet call on a page (/page-with-snippet/) like this:
[[pdoResources?
&parents=`6`
&resources=`[[!addToCookieLIst? &value=`[[!#POST.action]]` ]]` // your snippet should return comma-separated list of resources` ids that you pass then to pdoResources
&tpl=`popup.favorites.item`
&includeTVs=`header.bgImage,franchise.logo,franchise.price,title,subtitle`
&prepareTVs=`1`
&hideContainers=`1`
]]
and now you can send parameters to this page (/page-with-snippet/) via AJAX and get the results if there are any. I hope I didn't mess anything - you had better check it again, but you get the idea at least :) BTW, check this article on modx.com that teaches how to write a good snippet.
Also another minor issue: as it has been pointed out here, the use of window.location is preferable to document.location.
Here is another solution I did. I used pdoResources. Hope that you will understand my code and customize it for yourselves.
Create snippet ajaxCookieList
Paste JS-code in your custom.js file
Simple markup for resources. Insert it in the chunk:
Add to wish list
Remove from wish list
Thas all:)
I am new to Laravel. I do not know the right way to construct and accept GET requests.
I need to send the following request (en and es are language codes):
translation/next-word/en/es
and in Controller I have
public function getNextWord($langfrom, $langto) {
However, now new requirement came and I also have to send a list of IDs (on my client side it is an array (for instance, [1,5,12,15]), but it could be long list (about 100 IDs). Thus I am not sure how to send this ID array to controller and also accept it in controller method.
My old client side request (without categories):
// var categories = [1,2,5,6,17,20];
var url = "translation/next-word/en/es";
$.ajax({
url: url,
method: "GET"
}).success(function(data){
...
});
For get, change your controller like this,
public function getNextWord() {
$langfrom = $_GET['langfrom'];
$langto = $_GET['langto'];
}
In ajax send the data like this,
$.ajax({
url: url,
method: "GET" ,
data: {langfrom:langfrom,langto:langto} <----- passing from GET
}).success(function(data){
...
});
If you wan to get in parameters like this,
public function getNextWord($langfrom, $langto) {
Then ajax should look like this,
$.ajax({
url: url +"/" + langfrom + "/" langto, <----- passing as parameter
method: "GET" ,
}).success(function(data){
...
});
In Laravel, you handle GET requests by making a route in your routes.php file and then a corresponding method in a controller class to actually handle the request. In your case, because you want to also pass in an unknown number of IDs, I would suggest making that into a query parameter. You can format that however you want, although I would suggest using something like commas to divide the data in your URL. So in the end, your URL would look something like this:
example.com/translation/next-word/en/es?categories=1,2,5,6,17,20
routes
Route::get('translation/{nextWord}/{from}/{to}', 'TranslationController#translate');
TranslationController
public method translate($nextWord, $from, $to, Request $request)
{
//get the categories passed in as a query parameter
$input = $request->all();
$categories = $input['categories'];
$categories = explode(',',$categories); //turn string into array
//actually translate the words here (or whatever you need to do)
$translated = magicTranslateFunction($nextWord, $from, $to);
//also you can now use the categories however you need to
//once you're done doing everything return data
return $translated;
}
Inside your javascript, you'll just want to turn your array of categories into a comma delimited string and pass that to make the URL I started the post with.
var categories = [1,2,5,6,17,20];
var categoriesString = categories.join();
var url = "translation/next-word/en/es?categories="+categoriesString;
$.ajax({
url: url,
method: "GET",
success: function(data) {
...
}
});
Edit - using $.ajax 'data' setting
Instead of appending the categories as a string to the URL, you can just pass in the array directly as part of the 'data' setting of your ajax call.
var categories = [1,2,5,6,17,20];
var url = "translation/next-word/en/es";
$.ajax({
url: url,
method: "GET",
data: {
"categories": categories
},
success: function(data) {
...
}
});
Laravel will actually convert this correctly to a PHP array, so you don't need to do any special parsing in your controller. Just take it in like normal and use it:
TranslationController
public method translate($nextWord, $from, $to, Request $request)
{
//get the categories passed in as a query parameter
$input = $request->all();
$categories = $input['categories']; //already a PHP array
//actually translate the words here (or whatever you need to do)
$translated = magicTranslateFunction($nextWord, $from, $to);
//also you can now use the categories however you need to
//once you're done doing everything return data
return $translated;
}
It's been 2 days now and still I can't get this problem to work.
So basically I am trying to call a php function through jquery ajax
but nothing is working, I am not sure what is the problem is...
here are my codes
the ajax
$(document).ready(function() {
$("#idCheck1").click(function(){
$.ajax({
url:'../../../../Controller/PostsController.php',
data: {action: 'update_checkbox'},
success:function(result){
// $("#dsa").html(result);
}
});
});
});
the view
<?php echo $this->Form->create("Posts", array("action" => "update_checkbox", "id" => "checkingBox")) ?>
<td>
<?php
echo $this->Form->input('Post.' . $i . '.id', array("type" => "hidden", "label" => false, "value" => $sum['posts']['id']))
?>
<?php
echo $this->Form->input('Post.' . $i . '.done', array("type" => "checkbox", "label" => false, "value" => "1", "id" => "idCheck1"))
?>
</td>
</tr>
<?php
$i++;
}
?>
</table>
<?php echo $this->Form->end(); ?>
the controller
public function update_checkbox() {
// debug($this->data);
$var = $this->Post->saveCheckBox($this->data);
$this->set("result", $var);
}
the model
public function saveCheckBox($checkbox) {
debug($checkbox);
$this->saveAll($checkbox['Post']);
}
The url
url:'../../../../Controller/PostsController.php'
looks wrong. Since this is an AJAX request that goes through the browser you can't use relative paths that try to go upwards in the folder hierarchy, as browsers url's don't work that way. You should be making that request so that it is passed through a web server, i.e. the url should look like one of the following:
url:'http://localhost/Controller/PostsController.php'
or
url:'/Controller/PostsController.php'
The first option is an absolute url, but this also makes the code a bit less flexible (suppose you change the domain from localhost to something else). The second option is a relative URL, but one that is relative to the domain root of your web server (i.e. in the example it would still resolve to localhost/Controller...).
In both cases based on what you've posted, your PHP file should live in a Controller/ folder in the document root of your site. The structure of your code however suggests that you are using a framework of some kind (e.g. Zend, Symfony or CodeIgniter)? If that is the case it would be helpful if you post information on what framework you're using as well as that might change the answer.
UPDATE
In the case of cakePHP, you should access the controller through the front controller, meaning the URL should look like this:
url:'/posts'
UPDATE 2
For the jquery side, a complete ajax request example could look like this:
$(".idCheck").click(
function(){
var idVal = $(this).val();
$.ajax({
url:'/posts/update_checkbox',
data: {id: idVal },
type: 'POST',
success:function(result){
$("#dsa").html(result);
}
});
});
Note that the URL already contains the update_checkbox action (i.e. the complete url to the action you want to execute), and the data object contains the value of the clicked element that you want to send to the server. If you want to send a complete form you could also use $('#myformselector').serialize() to convert all inputs in the form to a object suitable for the data property of the ajax request.