Custom ajax call in woocommerce

sometimes you need to update database via ajax. wordpress has tools to make it easy. Well not that easy…

here for example, we want to create a link that when clicked, automatically change the order status of a woocommerce order and insert some notes.

In the template,

<script>
function installer_action(id,istatus) {
	jQuery.ajax({
	   type: "post",
	   url: '<?php echo admin_url( 'admin-ajax.php' ); ?>',
	   data: "action=update_order_installer_status&nonce=<?php echo wp_create_nonce('nonce_update_order_installer_status'); ?>&id="+id+"&status="+istatus,  
	   success: function(data){
	   	console.log(data);
	   		jQuery('#order_status_'+id).html(data.status);
	   		jQuery('#installer_actions_'+id).html(data.note);
	   },
	   error: function(xhr, textStatus, errorThrown) {
	     // console.log(xhr.responseText);
	   }
	});
}
</script>

Note that we have to use nonce to prevent csrf. Now we need the html for the link:

<span id="installer_actions_<?php echo $post->ID; ?>">
  <?php
    echo "<a href=\"#\" onclick=\"installer_action('$post->ID','accepted')\">Accept Request</a> | <a href=\"#\" onclick=\"installer_action('$post->ID', 'rejected')\">Reject Request</a>";
  ?>
</span>

The content in the span will be replaced by the ajax.

then in your functions.php, you have a function that deals with the ajax call and return some json. For eg.

function update_order_installer_status() {
  check_ajax_referer( 'nonce_update_order_installer_status', 'nonce' );
  // we are safe now
  $order = new WC_Order($_POST['id']);
  $new_order_status = ($_POST['status'] == 'accepted') ? 'install-accepted' : 'install-rejected' ;
  $note = "Installer ".$_POST['status']." job on ".date('j F Y, g:i a');
  $order->update_status($new_order_status);
  $order->add_order_note($note, 1);

  $notes = $order->get_customer_order_notes();
  $order->note = $notes[0]->comment_content;
  $order->status = wc_get_order_status_name($order->get_status());
  wp_send_json($order);
}

add_action( 'wp_ajax_update_order_installer_status', 'update_order_installer_status' );
add_action( 'wp_ajax_nopriv_update_order_installer_status', 'update_order_installer_status' );

Deploying to wordpress from git

If you are using git and are writing plugins for wordpress, its a hassle to switch between the 2 SCM. Why not commit once and deploy to 2 places? that is what many people are trying to do.

this script does exactly that: https://github.com/benbalter/Github-to-WordPress-Plugin-Directory-Deployment-Script

Create a plugin first. I suggest using all lowercase, eg blarblar-blarblar-blarblar. create a repo for it in github. git clone that plugin in your plugins folder. Make all changes.

Create the version number in the readme and plugin master file.

copy the deploy.sh into the wp-content/plugins folder, one level above your plugin. then run:

 ./deploy.sh

you will be prompted to enter the name of the plugin and everything should work.

simple ways to optimise wordpress

No you don’t have to use w3tc or wp super cache. wordpress becomes slow when db queries grow. a quick way is to find the expensive queries and speed them up by caching them.

for example,

$sql = "select post_id from {$wpdb->prefix}postmeta where meta_key='_blar' and meta_value='$value'";

$id = wp_cache_get( 'id_'.$value );
if ( false === $id ) {
  $id = $wpdb->get_var($sql);
  wp_cache_set( 'id_'.$value, $id );
}

transient is also a fantastic way of caching – http://speckyboy.com/2011/12/14/website-speed-part-3-caching-wordpress/

Prevent wordpress redirect / rewrite for certain pages

WordPress intelligently creates nice url for seo but there are times when you don’t want wordpress to redirect certain url. For eg, you might have a custom application in a protected area, hence having the old school url like blarblar.php?test=true&page=2 might be easier to work with. The trick lies in the parse_query hook.


function do_not_redirect_on_these_pages( $query ) {
  // print_r($query) for yourself to see.
  if( $query-&gt;query_vars['pagename'] == 'your_page' ) {
  remove_filter( 'template_redirect', 'redirect_canonical' );
  }
}
add_action( 'parse_query', 'do_not_redirect_on_these_pages' );

also avoid appending wordpress variables as query, such as s= , p=, post_type= …etc to save you some headaches. create your own variables.

WordPress redirection plugins are the source of all evil

If you have a plugin that does page redirection, it is most likely going to interfere with other plugins you have.

Take logging in for example, wp_login hook is called after the common wp_signon function. Most plugin hooks on to wp_login and do a redirection header and an exit after that. This means that other plugins will not have a chance for their wp_login to be called because the php has already exited. The same theory applies for other redirection plugins. Once an exit or die function is called, php has to end and hence stopping other plugins from functioning correctly. This then becomes a battle of plugins priority…bad.

I shared some tips on how to troubleshoot wordpress.

have fun

Troubleshooting wordpress and wordpress plugins

Troubleshooting wordpress and its plugins can be a time consuming and a tedious process. WordPress plugins use hooks to add on new functionalities. The problem is that different plugins have different priorities. Worst still, some commercial plugins have their code obfuscated so its impossible to see what their code is doing. Fortunately, there are still some tricks that we can do to troubleshoot what’s going on.

1) Look at wp-includes/plugin.php. Most of the plugins will use add_action or add_filter. Just print out the variables in these functions so you know what hook it is calling and what function it is hooking on. eg

// in about line 82 of wp-includes/plugin.php
function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
  global $wp_filter, $merged_filters;

  // print_r to see the variables
  echo $tag.' '.$function_to_add;

  .....
}

2) Things become tricky if you the plugins that uses functions within a custom defined class. These classes have to be globally accessible before you can access the functions from other places. One good way to look for global variables is to use

print_r(array_keys($GLOBALS));

3) Say some plugin do this

class my_class {
  ...
  add_action('wp_login', array($this, 'xx_redirect'), 5, 2);

  function xx_redirect() {
    ..
  }
}

to remove the add_action from my_class, in your functions.php, you have to

global $my_class;
remove_action('wp_login', array($my_class, 'xx_redirect'), 5, 2);

Note that you have to specify the same no. of params and priority, ie 5 , 2.

4) Install xdebug and turn on error logging in your php.ini. Turn WP_DEBUG on in your wp-config.php

define('WP_DEBUG', false);

5) Use var_dump() and print_r() with exit to see your errors. Printing out $GLOBALS might crash your browser if you have lots of heavy plugins. Another way is to print them out in your log file.

error_log(print_r($var, 1));

6) Disable all plugins quickly can help troubleshooting

// backup your db and dump them somewhere, then quickly disable all plugins. after you've done your troubleshooting, re-enable them again
UPDATE wp_options SET option_value = 'a:0:{}' WHERE option_name = 'active_plugins';

7) View actual SQL

As most people are using wordpress functions to run queries, it is hard to see what the query actually is. One easy way to do it is to

// in config.php, add
define('SAVEQUERIES', true);

then in the part of the code that you want to see the query,

global $wpdb;
$posts_array = get_posts( $post_args );
// I don't know what get_posts is doing and like to see the sql for example, I will insert $wpdb->queries here
// note that you will be getting tonnes of saved queries.. but look at the last one. It will be the last query before exiting.
print_r($wpdb->queries);exit;

8) View your apache, php and mysql logs. Looking at these logs often gives you an idea of where went wrong.

These are my tips so far. Do you have any more to share?

cheers.

WordPress redirection after login fails

If you create your own login form or use the wordpress wp_login_form function to create one, you have the option to redirect user to certain pages after login by including a “redirect_to” variable upon submission. If it doesn’t work, it means that you have certain plugins that hook on to the wp_login action. Commercial plugins are hard to debug because the code is encrypted. One way around this is to intercept the wp_login earlier than other plugin, perhaps using a higher priority. Eg

add_action( 'wp_login', 'my_login_redirect', 2, 2 );
function my_login_redirect( $login, $user ) {
  // $login is the username 
  // $user is the WP_USER object

   // don't redirect the wp-login.php. else you get infinite loop
   if ($_SERVER['REQUEST_URI'] != '/wp-login.php') {
     // if you are using the wp_login_form function, you can get the $_POST['redirect_to'] variable and redirect user to the right place.
     // allows get as well.
     if (isset($_REQUEST['redirect_to'])) {
        $referrer = $_REQUEST['redirect_to'];
     }
     else {
       // redirect to the referrer page
       $referrer = $_SERVER['HTTP_REFERER'];
     }
    wp_safe_redirect($referrer); 
    exit;
  }
}

Create wordpress language file with poedit

Giving users the ability to translate your plugin is important. So you should be using __, _e, _x …etc in your plugins as myuch as possible.

In your plugin folder, create a lang sub-foldder to store your language files. In your init plugin file, make sure you have the localisation code:

$domain = 'your-plugin-name';
$locale = apply_filters('plugin_locale', get_locale(), $domain);
// let user customise the lang in a dfferent folder.
load_textdomain($domain, WP_LANG_DIR.'/my-plugin/'.$domain.'-'.$locale.'.mo');
// load plugin locale
load_plugin_textdomain( 'your-plugin-name', false, dirname( plugin_basename( __FILE__ ) ) . '/lang/' );

next download poedit from http://www.poedit.net/

1) Open poedit and fill in the project info.
2) Under the paths tab, fill in the base path, eg /home/username/your-wordpress-project/wp-content/plugins/plugin-name/. Then add a “.” under the Paths input box below.
3) Under the keywords tab, add “__” and “_e”
4) Click ok and when prompted to save the file, save it in your plugin lang folder in the form of your-plugin-name_lang_locale format, eg your-plugin-name_en_AU

You should get 2 files of with the .mo and .po extension.

good luck.

Best way to prevent autosave and revisions in wordpress

wordpress by default tries to be clever by saving revisions to your posts frequently. This can be a good thing if everything went kaboom and you won’t loose too much data. The downside is that your database will become bloated really quickly, meaning that queries will become slower as time goes by. To stop wordpress from saving revisions, the best thing to do is to deregister the javascript responsible for the autosave.

// disable autosave throughout the site. Note that this will also break the preview changes. If you don't need preview changes, this is the best solution.
function disable_autosave(){
  wp_deregister_script('autosave');
}
add_action( 'wp_print_scripts', 'disable_autosave' );

In your wp-config.php file

define( 'WP_POST_REVISIONS', false ); // no revisions