Now I know that I am at risk here of asking a duplicate question, however I don't really know what to search for because I am a complete AJAX jQuery noob. Believe me, I have tried searching what I think is the obvious, with no luck so please go easy on me.
I have a php wordpress site which shows prices in GBP as default. At the top, is a select box with onchange="this.form.submit()" which allows the user to change the default currency that all prices are quoted in.
<form method="post" action="">
<select name="ChangeCurrency" onChange="this.form.submit()">
<option value="GBP">GBP</option>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
</select>
</form>
On the home page, are several, what I call "shortcode widgets", each one containing products and price tables. A dashboard if you like.
How it currently works (inefficient):
User changes select.
Form submitted
Homepage reloaded with updated prices in selected currency.
This is not good, because whenever somebody changes currency, the whole page is reloaded (this takes time, transfers approx 1mb without caching, not to mention unnecessary load on the server).
What I want (more efficient):
When the select box is changed, I wish to asynchronously post the form which changes the currency session variable.
Each "shortcode widget" is updated one by one without having to reload the entire page.
Is this something that jquery can do? where do I start?
Just in case it makes any difference so that you can see what I mean, here is the URL so that you can see what I am talking about... http://bit.ly/10ChZys
PART 2:
I have used jQuery and ajax to update the fixTable thanks to a mashup of answers below... I am using session variables to store the users choice, that way, if they return to the site, the option will be saved.
I am having problems with my code because the session variable stored within http://goldealers.co.uk/wp-content/plugins/gd/tables.php?currency=GBP&table=fixTable appears to have a different session_id to the user's session id because the option is no longer stored.
Is there a way of telling the server that they are one and the same session?
SOLUTION
I used Ribot's Solution to start with which worked and solved the initial problem, then extended with NomikOS's solution...
NOTE: this answer show some ideas about the php backend for the AJAX process. It is a complement for the other answers talking about the frontend process.
1.- a mockup to manage AJAX request in WP, just some ideas, ok?
add_action('init', 'process_ajax_callback');
function process_ajax_callback()
{
if ( ! $_REQUEST['go_ajax'])
{
return;
}
try
{
if (isset($_REQUEST['nonce_my_ajax']))
{
$nonce = $_REQUEST['nonce_my_ajax'];
if ( ! wp_verify_nonce($nonce = $_REQUEST['nonce_my_ajax'], 'nonce_my_ajax'))
{
throw new Exception("Nonce token invalid."); // security
}
}
}
catch (Exception $e)
{
$output['result'] = false;
$output['message'] = $e->getMessage();
echo json_encode($output);
exit;
}
$result = true;
$message = '';
switch ($_REQUEST['action'])
{
case 'update_price':
try
{
// update price
// price value comes in $_REQUEST['price']
}
catch (Exception $e)
{
$result = false;
$message = $e->getMessage();
}
break;
case 'other_actions':
break;
}
$output['result'] = $result ? true : false;
$output['message'] = $message;
echo json_encode($output);
exit;
}
2.- don't forget security
// nonce_my_ajax is passed to javascript like this:
wp_localize_script('my_js_admin', 'myJsVars', array(
'nonce_my_ajax' => wp_create_nonce('nonce_my_ajax')
));
3.- in general the needed in the frontend (to use with the backend mockup showed above) is something like:
$("select[name='ChangeCurrency']").live("change", function() {
var price = $(this).val();
$.post(
window.location.href,
{
go_ajax : 1, // parse ajax
action : 'update_price', // what to do
price : price, // vars to use in backend
nonce_my_ajax : myJsVars.nonce_my_ajax // security
},
function(output) {
if ( output.result == true )
// update widgets or whatever
// $("#my_div").html("we happy, yabadabadoo!");
// or do nothing (AJAX action was successful)
else
alert(output.message)
}, 'json');
});
4.- You can use $.get() or $.post() to send/process data to/in server but .load() is not good when you update DB because you can't manage returning messages of failures with the precision of a json response (for example: multiples validation error messages). Just use .load() to load HTML views.
UPDATE:
Set session_id() where can be executed both for normal requests and for ajax requests and at the early stage as possible. I hope you are using a class to wrap your plugin, if not now is the right moment to do it... example:
class my_plugin {
function __construct()
{
if ( ! session_id())
{
session_start();
}
add_action('init', array($this, 'process_ajax_callback'));
// ...
}
function process_ajax_callback()
{
// ...
}
}
UPDATE 2:
About nonce based security:
A security feature available in WordPress is a “nonce”. Generally, a
“nonce” is a token that can only be used once and are often used to
prevent unauthorised people from submitting data on behalf of another
person.
Ref: http://myatus.com/p/wordpress-caching-and-nonce-lifespan/
In this mockup nonce_my_ajax is just an example, indeed it should be more unique like nonce_{my_plugin_name}, or even better nonce_{my_plugin_name}_{what_action} where what_action represents updating user, or inserting new book, etc...
More info about it: WP Codex: WordPress Nonces, WPtuts+: Capabilities and Nonces.
Yes, jQuery can do it using ajax.
First of all, when using ajax, you don't have to post a form to get the data. Ajax in jQuery will load the text data of an url.
You may start by giving your select an id (here id="changeCurrency") and:
$("#changeCurrency").change(function(){
currency = $('#changeCurrency option:selected').val() // get the selected option's value
$("#some_div").load("someurl.php?currency=" + currency);
});
Now read up on jQuery and ajax for what kind of ajax call you need to do that suites your needs the best.
Drop the onchange and add an ID
<select name="ChangeCurrency" id="ChangeCurrency">...
On the page give all your prices a price in your base currency as well as outputting them
<span class="price" data-base="0.12">£0.12</span>
In your JS have a conversion table
// base currency is GBP
// each currency has 0: currency symbol, 1: conversion rate
var currency={"GBP":["£", 1], "USD":["$", 0.67]};
var usercurrency=currency['GBP'];
and bind an event to the change
$('#ChangeCurrency').on('change', function(){
// post to the server to update it
$.post(...);
// set locally on the page
usercurrency=currency[$(this).val()];
// and change all the values
$('.price').each(function(){
$(this).html(usercurrency[0] + (usercurrency[1] * $(this).data('base')).toFixed(2) );
});
}).trigger('change'); // trigger this to run on page load if you want.
I haven't checked any of this code
Related
How can i add notification bubble like Facebook in my admin menu (when new user is signup) by using Ajax php also after viewing/clicking the menu bubble disappear.Anybody help???
When a user signs up, I guess you add him/her in your database? If so, I would add a field in your users database called "notificationViewed", which would be false by default when you put that user in the database.
When you connect or refresh you admin menu page, your php that serves the page should check the database if any user has a field notificationViewed == false, and COUNT the number of such returned users. In your html tag that represents the buble, add an attribute data-newUsers="<?= COUNT_OF_NEW_USERS ?>".
Now on the client-side...
Have, let's say, id="bubble" hidden by default with CSS:
#bubble {
display:none;
}
With JavaScript, you can access the data-* attributes easily:
var newUsers = document.getElementById('bubble').dataset.newUsers; // holds the number
or with jQuery:
var newUsers = $('#bubble').data('newUsers'); // same thing
At this point, you can check if newUsers > 0. If so, populate the bubble with the number (if you want), and do a nice fadeIn animation. Example in jQuery:
if (newUsers > 0) {
$('bubble').text(newUsers).fadeIn();
}
Now, we want to be able to detect when the bubble is clicked, in order to hide the bubble and discard the new users signed up. Again, with jQuery:
$('#bubble').click(function() {
$.post('discardNotifications.php', {usersNotified: newUsers}, function(data) {
if (data === "ok") { // php script returns this string if all went right
$('#bubble').fadeOut(function() {
$('#bubble').remove(); // remove the element from the DOM, to prevent further clicks of the element
}); // nice fadeOut animation of the bubble
}
}
});
The function will only be called if the POST request was successful. The POST request is directed to discardNotifications.php, which must be in the same directory as your admin-menu html file (if not, just change the relative path). The second parameter of the call is a litteral object containing the number of new users notified, which is sent to your back-end.
Back on the back-end, inside discardNotifications.php...
You must check if there's a POST parameter called "usersNotified", then query your users database and update at most the number given by "usersNotified". This takes into account that maybe new users subscribed since you refreshed your admin page, and you want the notification of these new users. Not selecting a maximum of "usersNotified" would possibly ignore them. Example (but not complete):
if (isset($_POST['usersNotified']))
{
$number = $_POST['usersNotified'];
// update the "notificationViewed" field to TRUE for at most $number different users
echo "ok"; // everything went right
} else {
echo "bad";
}
There are obviously changes you can make, and you have to implement some of the database handling. Tell me if it works!
Ps: there might be little errors in my code snippets, I didn't test everything.
wondering what the the best way to achieve something is.
To summarise, I have a form that I load by ajax which I use for to both update and insert new rows into a database. To determine whether it is an update or an insert I use the below code (updated forms use the mysql query to populate the form fields).
My code seems sloppy and not best practice. Are there any other suggestion on what would be the best way to do this?
<?
require_once("config.php");
$insert = false;
$update = false;
$targID = 0;
if(isset($_POST['targID'])){
$targID = $_POST['targID'];
$targRow = mysql_fetch_array(mysql_query("select * from events where eventid=$targID"));
$update = true;
}else{
$insert = true;
}
?>
<script type="text/javascript">
var insert = <? echo $insert; ?>+0;
var update = <? echo $update; ?>+0;
......javascript button events, validation etc based on inssert/update
</script>
You already know in the client whether it is an update or an insert, by the fact that you send or do not send the POST data item. So I would write JS in the original page to control the submit and what to do with the data that is sent back. It's difficult to write code without seeing the rest of the page, but at pseudo-code level, you could do the following:
use onsubmit() to catch original submit action
look to see if targID provided
if yes, send update request to server. When row data comes back, fill out form details and display form (you can 'show' a hidden DIV containing the form, for example)
if no - do you need to send anything? - just reveal an empty form (again, show a previously hidden DIV)
Hope this is useful in some way.
You should use native mySQL:
INSERT ... ON DUPLICATE KEY UPDATE
See:
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
What's the point in determining that on the client side? Does it make any difference?
For the server side I'd use $targID passed from the hidden field. if it's greater than zero - update, otherwise - insert.
I am making quite a large online points/purchasing system in PHP and just have a fundamental question.
All the relevant stuff is on a single PHP page within the site, with "includes" from other parts of the site such as shopping cart, points review, products etc..., but throughout the page there are stages where the user clicks a form submit button to pass values via $_POST.
As there is a main page for all this stuff, I have a part at the top of the page where it takes all the POST values and makes decisions based upon them, like so:
if($_POST['add']) {
$product_id = $_POST['add'];
}
if($_POST['remove']) {
$rid = $_POST['id'];
$cart->del_item($rid);
}
if($_POST['empty']){
$cart->empty_cart();
}
if($_POST['purchase']) {
foreach($cart->get_contents() as $item) {
$sql="INSERT INTO wp_scloyalty_orders VALUES (".$user_id.", ".$item['id'].")";
$result=mysql_query($sql);
}
$cart->empty_cart();
unset($_SESSION['cart']);
}
if($_POST['add']) {
query_posts('post_type=prizes&showposts=-1&p='.$product_id.'');
while (have_posts()) : the_post();
$my_meta = get_post_meta($post->ID,'_my_meta',TRUE);
if($calctotalnew > $my_meta['pointsvalue']){
$cart->add_item(get_the_id(), 1, $my_meta['pointsvalue'], get_the_title());
} else {
echo 'You do not have sufficient points to redeem this product...';
}
endwhile;
wp_reset_query();
}
So my question is... is this really a good way to organize a system, having the form actions go to the same page that the form is on, and have a load of IF statements to decide what to do with the POST values?
Thanks! :)
it's generally best to capture separate POST calls (grouped by type) in separate actions. I usually go as follows:
page 1 has a form, which will submit to eg. product.php?action=add. In product.php you can route the 'add' action to the function add_product() (or whatever). Then when the product is added, just header the user back to the main page (or whatever page you'd like). This immediately tackles the problem with refresh-posts (user refreshing the page which will send the same data again).
following mvc imagine you have a controller Product which handles all the product actions. The skeleton could look like this (assuming function action_x will be executed when yoursite.com/product/x is requested):
class Product_Controller {
function action_show() {
}
function action_update() {
}
function action_delete() {
}
}
if your framework supports a default action of some sort you could route your actions:
function action_default() {
if(method_exists(array($this, 'action_'. $_POST['action']))) {
return call_user_method('action_'. $_POST['action'], $this);
}
}
ofcourse the same can be achieved without controller classes;
if(function_exists('action_'. $_POST['action'])) {
call_user_func('action_'. $_POST['action']);
}
function action_show() { }
...
and to illustrate the discussion in the comments;
function action_update() {
// do some update logic, query an UPDATE to mysql etc.
if($result) {
// optionally save a success message
Message::add('Your record has been updated');
header('Location: main_page.php'); // or another intelligent redirect function
} else {
Message::add('Sorry, something went wrong');
header('Location: error_page.php'); // or also main_page
}
}
This will also keep your code cleaner, as updating/adding/deleting stuff is radically different from showing stuff, this will prevent you from mixing up stuff. You could even call the show function from within the update function if you want to skip the redirect.
But in the end it's a matter of choice, led by pragmatism or your framework ;)
I hope this'll explain everything a bit, don't hesitate to ask for clarification
if you want to separate the logic from the interface then you can simple create new file and put the all logical and database related code in that file and include OR require that file in the view file
like
view.php interface file and
logic.php is your logic file then
first line in view.php is
require_once(logic.php');
and all the logic is in this files
simple MVC
Well, it seems I have to explain.
It absolutely does not matter how much IF statements you have in the POST handler. Your current design is okay, and there is no reason to ask nor change it.
The only thing that you may wish to add to your design is a front controller, which will take both entity (cart) and action("add") and call add() method of $cart class. these methods you may store one under another in the class source.
Though it is quite huge improvement, requiring great rethinking of the whole site architecture. So, you may stick with your current one.
As for your other question, how to display errors, here is an answer: php redirection not working
I have a PHP page that uses jQuery to let a user update a particular item without needing to refresh the page. It is an availability update where they can change their availability for an event to Yes, No, or Maybe. Each time they click on the link the appropriate jQuery function is called to send data to a separate PHP file (update_avail.php) and the appropriate data is returned.
Yes
Then when clicked the params are sent to a PHP file which returns back:
No
Then, if clicked again the PHP will return:
Maybe
It all works fine and I'm loving it.
BUT--
I also have a total count at the bottom of the page that is PHP code to count the total number of users that have selected Yes as their availability by simply using:
<?php count($event1_accepted); ?>
How can I make it so that if a user changes their availability it will also update the count without needing to refresh the page?
My thoughts so far are:
$var = 1;
while ($var > 0) {
count($day1_accepted);
$var = 0;
exit;
}
Then add a line to my 'update_avail.php' (which gets sent data from the jQuery function) to make $var = 1
Any help would be great. I would like to stress that my main strength is PHP, not jQuery, so a PHP solution would be preferred, but if necessary I can tackle some simple jQuery.
Thanks!
In the response from update_avail.php return a JSON object with both your replacement html and your new counter value.
Or to keep it simple, if they click "yes" incriment the counter, if they click No or maybe and their previous action wasn't No or Maybe decrease the counter.
Assuming your users are logged into the system I'd recommend having a status field in the user table, perhaps as an enum with "offline", "available", "busy", "unavailable" or something similar and use the query the number of available users whilst updating the users status.
If you were to do this you'd need to include in extend your methods containing session)start() and session_destroy() to change the availability of the user to available / offline respectively
The best way is the one suggested by Scuzzy with some improvements.
In your php, get the count from the database and return a JSON object like:
{ count: 123, html: 'Yes' }
In your page, in the ajax response you get the values and update the elements:
...
success: function(data) {
$("#linkPlaceholder").html(data.html);
$("#countPlaceholder").html(data.count);
}
...
I have a simple web-based database using php/mysql that I use to keep track of products leaving my stockroom.
The MySQL database has a bunch of tables but the two I'm concerned with are 'Requests' and 'Salesperson' which you can see below (I've omitted irrelevant information).
Requests
R_ID ... R_Salesperson
1 ... James
2 ... Bob
3 ... Craig
Salesperson
S_ID S_Name
1 ... James
2 ... Bob
3 ... Craig
In my head section I have the following script that dynamically populates a list of our sales staff names as you type them:
// Autocomplete Salesperson Field
$("#form_specialist").autocomplete("../includes/get_salesperson_list.php", {
width: 260,
matchContains: true,
//mustMatch: true,
//minChars: 0,
//multiple: true,
//highlight: false,
//multipleSeparator: ",",
selectFirst: false
});
aaand get_salesperson_list.php:
<?php
require_once "get_config.php";
$q = strtolower($_GET["q"]);
if (!$q) return;
$sql = "select DISTINCT S_Name as S_Name from Salesperson where S_Name LIKE '%$q%'";
$rsd = mysql_query($sql);
while($rs = mysql_fetch_array($rsd)) {
$cname = $rs['S_Name'];
echo "$cname\n";
}
?>
I also have some basic javascript input validation requiring a value be entered in the Salesperson field (script is in the head section):
<!-- Input Validation -->
<script language="JavaScript" type="text/javascript">
<!--
function checkform ( form )
{
// ** Validate Salesperson Entry **
if (form.form_specialist.value == "") {
alert( "Please enter Salesperson Name" );
form.form_salesperson.focus();
return false ;
}
// ** END Salesperson Validation **
return true ;
}
//-->
</script>
Aaaaanyway - the problem is I can't figure out how to reject any names not in the 'Salesperson' table. For example - if I were to type 'Jaaames' although it would initially suggest 'James' if I were to ignore it and submit 'Jaaames' this would be entered into the 'Requests' table. This is relatively annoying given my undiagnosed OCD and I'd rather not have to go through hundreds of requests every so often editing them.
I'd say you're taking the wrong approach here.
The Requests table should NOT be storing the salesperson's NAME, it should be saving their ID. The Primary Key of the Sales Person table.
Then, instead of using auto-complete to populate a TEXT input, I'd recommend using the same approach to populate a SELECT menu that uses the Sales Person's ID as a value.
This accomplishes the following:
your database becomes more normalized
it removes redundant information from the Requests table
removes the need to validate the Sales Person's name on the client side
By defining the S_ID as a foreign key to the Requests table, you ensure that ONLY entries in the Sales Person table can exist in the Requests table.
You could try binding an AJAX request to either the submit of the form or on changing your text field or maybe when the field loses focus.
For this example I am using jQuery:
$('input[name=salesperson').blur(function(){
//when the text field looses focus
var n = $(this).val();
$.post('a_php_file_that_checks_db_for_names.php', {salesperson:n}, function(data){
//post the name to a php file which in turn looks that name up in the database
//and returns 1 or 0
if (data)
{
if (data==='1')
{
alert('name is in database');
}
else
{
alert('name is not in database');
}
}
else
{
alert('no answer from php file');
}
});
});
You would also need a PHP file for this to talk to, an example being:
if (isset($_POST['salesperson']))
{
//query here to check for $_POST['salesperson'] in the db,
//fill in the blanks :)
$yourquery='select name from db where name=?';
if ($yourquery)
{
//looks like there were results, so your name is in the db
echo '1';
}
else
{
echo '2';
}
}
A bit of filling in the blanks required but you get the idea.
Hope this helps you out
EDIT:
A second, more elegant solution just came to mind - if you could get the list of salespersons and make a hidden form field for each, you could read them all into a JS object and test against it whenever the form field is changed. Unfortunately I don't have the time to write you an example but it sounds like a nicer way of doing it to me.
It seems like you're just using Javascript to validate your input - this isn't good as it will never run if your user doesn't support or disables Javascript. As suggested above, a server side validation would be much easier to check against the database. However, client-side validation is also helpful to have as a sort of first line of defense against bad input, since it's generally faster. I can't think of a great way to do this, but one way could be to populate a PHP array of salespersons, convert it to a javascript array, and then check to see if the form value is in the array. It's probably faster (and substantially less code) to just use server-side validation here.
Try adding some sort of validation before you put it on your database? I mean, inside the script that puts the request into the table?
The mustMatch option isn't working for you? I see it commented out.
Also, your script is vulnerable to a SQL injection attack. I realize this is an in-house application, but you never know when crazy is going to show up and ruin your day. At the top of your get_salesperson_list.php, right after you retrieve the query from $_GET, you could add something like this:
if (!preg_match("/^\w+$/", $q)) {
// some kind of error handling here, or at least a refusal to fulfill the request:
exit;
}
UPDATE: Sorry, I meant to say "exit" instead of "return". I do see that your script wasn't in a function. I have edited the above to account for that. Thanks for pointing that out.