Sie sind auf Seite 1von 13

Advertise Here

Build a Short URL Service with WordPress Custom Post Types


Vinh Quc Nguyn on Aug 29th 2011 with 19 comments

Tutorial Details
Program: WordPress Version (if applicable): 3.0+ Difficulty: Advanced (seriously!) Estimated Completion Time: 60 minutes

Final Product What You'll Be Creating

wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/

1/13

WordPress is normally used as a blog engine or as a content management system (CMS), but those are not the only things it can be used for. With a little imagination, you can do virtually anything you want with it! In this tutorial I will teach you how to build a shortened URL service, write some plugin code using object oriented techniques, and deal with WordPress routers and custom error messages. Note that this is an advanced tutorial well be using some relatively advanced PHP techniques, but Ill make sure to link you over to any resources articles that you might need to understand along the way. Just remember, the point of this tutorial is to push the limits of WordPress, and thats going to take some real thought!

Overview
You should be familiar with the idea of what a short URL service is nowadays. If not, check out Goo.gl, bit.ly, or any of the others out there. Those are all fine and well, but what if you want your own? There a few reasons that you might want this (not just for vanity purposes), and this is an excellent chance to look at some of the more advanced areas of WordPress that you might not be familiar with. The Goal: We will create a Custom Post Type called url, its post title will be used as the original url. For each post (actually each url now), we generate a key for it, or the user enters his/her own key, which we will call the vanity key from now on. This vanity key will be appended to sites url and we have a short url. Heres the breakdown of what well be doing in laymans terms: 1. Assume your site has domain: h t : / p t t p u . e . tp/w.uslsnt 2. We have a very long url: h t : / e . u s l s c m t t r a s w r p e s c e t - - u t - a o t p r f l o w t tp/ntttpu.o/uoil/odrs/raeamlilyu-otoi-ih wrpes. odrs/ 3. We will assign it a vanity key of 1A, so short url will be: h t : / p t t p u . e / A tp/w.uslsnt1. 4. Anyone who hits it gets redirected to: h t : / e . u s l s c m t t r a s w r p e s c e t - - u t - a o t tp/ntttpu.o/uoil/odrs/raeamlilyuprflowt-odrs/ otoi-ihwrpes.

If you are not very familiar with plugin development yet, you should take a look at these useful tutorials before going further: How to Write a WordPress Plugin Create WordPress Plugins with OOP Techniques Custom Post Types Custom Meta Boxes Also make sure you have mod_rewrite installed, and enable the Pretty Permalink. We will use a custom field called _ a i y k yto store vnt_e this vanity key for each post. Enough chatting, lets get started!

Step 1 Setting up the plugin class


We will use OOP here. Lets call this plugin wp-vanity. We create a folder wp-vanity in wp-content/plugins. Then we create a main file call vanity.php and put it in folder wp-vanity.

File vanity.php
view plaincopy to clipboardprint? 1. class Vanity { 2. 3. static private $_self = null;
wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/ 2/13

4. const POST_TYPE = 'url'; 5. 6. /** 7. * Always return the same instance of plugin so we can access its property and its method 8. * from anywhere 9. * @return Vanity 10. */ 11. static public function singleton() { 12. if (!self::$_self) { 13. $classname = __CLASS__; 14. self::$_self = new $classname; 15. self::$_self->_bootstrap(); 16. } 17. return self::$_self; 18. } 19. 20. /** 21. * Construct plugin and set useful property for later reference 22. */ 23. public function __construct() { 24. } 25. 26. /** 27. * Init cache class! 28. * Load all styles, script, define JavaScript var with useful URL 29. */ 30. private function _bootstrap() { 31. //Add action, filter should be put here 32. } 33. 34. } 35. 36. $wp_vanity = Vanity::singleton(); We organize code into a class called Vanity. We also define a class constant P S _ Y Efor the name of our post type. Then we use the OTTP singleton() pattern, so that in the future you can make the plugin bigger without needing to deal with global variables since we always get the same instance of the Vanity class when we use method singleton(). You see the method b o s r p )will be automatically called after creating object in method s n l t n ) Thus, everything related to otta( igeo(. add_action, add_filter should be put here. If you are not familiar with Singleton pattern, then read A beginners guide to design patterns. Experienced PHP devs may wonder why I didnt put that code in _ c n t u t )method. This is for reasons of safety. If you have too _osrc( much long-execution code in method _ c n t u t ) then what might happen if one of those lines calls to method s n l t n )again. _osrc(, igeo( Well, at that time, the executing of __construct() has not finished yet, thus, the object is not yet returned; Therefore Vanity::$_self is not assigned. As the result method s n l t n )will create an object one more time. In order to be safe, we should not put code which call igeo( method s n l t n )in constructing method. igeo( We manually call b o s r p )in method s n l t n )after object is created. Of course, if you make sure nothing goes wrong you can otta( igeo( just put it in _ o s r c ( straight away. cntut) For now, we will put every code related to add_action, add_filter in method b o s r p ) otta(.

Step 2 Dealing with custom post type


wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/ 3/13

In this step, we will register our custom post type, add a meta box to display our vanity key and short link.

Registering Our Custom Post Type


We register post type whose name is stored in s l : P S _ Y E I didnt use hard-coding so you can easily change post type name to ef:OTTP. anything. Also, we just need WordPress to show a title field, and an author field for our post type. We just need title field to enter original URL. A custom field is used for the vanity key. You will handle it later. Now lets create method i i ( to register the post type: nt) view plaincopy to clipboardprint? 1. public function init() { 2. $args = array( 3. 'labels' => array( 4. 'name' => _x('Short Urls', 'post type general name'), 5. 'singular_name' => _x('Short Url', 'post type singular name'), 6. 'add_new' => _x('Add Url', self::POST_TYPE), 7. 'add_new_item' => __('Add New Url'), 8. 'edit_item' => __('Edit Url'), 9. 'new_item' => __('New Url'), 10. 'all_items' => __('All Urls'), 11. 'view_item' => __('View Url'), 12. 'search_items' => __('Search Urls'), 13. 'not_found' => __('No url found'), 14. 'not_found_in_trash' => __('No urls found in Trash'), 15. 'parent_item_colon' => '', 16. 'menu_name' => 'Urls' 17. ), 18. 'public' => true, 19. 'publicly_queryable' => true, 20. 'show_ui' => true, 21. 'show_in_menu' => true, 22. 'query_var' => true, 23. 'rewrite' => true, 24. 'capability_type' => 'post', 25. 'has_archive' => true, 26. 'hierarchical' => false, 27. 'menu_position' => null, 28. 'supports' => array('title','author') 29. ); 30. register_post_type(self::POST_TYPE, $args); 31. } Theres not that I can add to the code above. We register with r g s e _ o t t p and set a label and text for it. Now well let eitrps_ye WordPress know we want to hook into it with the i i hook! We use modified method _ o t t a ( : nt bosrp) view plaincopy to clipboardprint? 1. private function _bootstrap() { 2. add_action('init', array($this, 'init')); 3. }

Adding Custom Meta Box


To store the vanity key, we use a custom field called _ a i y k y As editing/adding post, we display a form or in other words, custom vnt_e.
wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/ 4/13

meta box, with information about short link (via appending _ a i y k yto the sites url), and a text box to let the user enter their own vnt_e vanity key instead of generating key automatically. view plaincopy to clipboardprint? 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. private function _bootstrap() { add_action('init', array($this, 'init')); add_action('add_meta_boxes', array($this, 'add_meta_box')); } public function add_meta_box() { add_meta_box("vanity-meta", "Short URL", array($this, 'meta_box_content'), self::POST_TYPE, "normal", "low"); } public function meta_box_content() { global $post; wp_nonce_field('my_vanity_nonce', 'vanity_nonce'); $_vanity_key = get_post_meta($post->ID, '_vanity_key', true); <p> <label><?php echo __('URL Key') ?>:</label> <input name="_vanity_key" type="text" value="<?php echo $_vanity_key ?>" /> You can put your custom url key here if wanted! </p> <?php if (!empty($_vanity_key)) : ?> <p> <label><?php echo __('Your whole shorted url') ?>:</label> <input size="50" type="text" value="<?php echo trailingslashit(get_bloginfo('url')), $_vanity_key ?>" /> <a target="_blank" href="<?php echo trailingslashit(get_bloginfo('url')), $_vanity_key ?>">Try it</a> </p> <?php endif ?> <?php } You can use get_post_meta to get the value of any custom field of a post. If you are still not familiar with meta box and custom field, let read this amazing tutorial again. We use action a d m t _ o e to register our new meta box, then we use the method, m t _ o _ o t n ( , to render its inside d_eabxs eabxcnet) content! When displaying meta box, we try to get the value of custom field _ a i y k y If we got a non empty value, we display the vnt_e. whole short url with that vanity key and a Try it link so that the user can click on it to try short url in a new window! At this point, if you try to add a new URL you have form like this:

wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/

5/13

If you edit an URL, you have form like this:

Saving the custom field


When we save the post, WordPress just saves title of post, we must handle our custom field in meta box ourselves. When any post is saved, action s v _ o tis called, so well hook into this action: aeps view plaincopy to clipboardprint? 1. private function _bootstrap() { 2. add_action('init', array(&$this, 'init')); 3. add_action('add_meta_boxes', array($this, 'add_meta_box')); 4. add_action('save_post', array($this, 'save_url')); 5. } 6. 7. public function save_url($post_id) { 8. global $post; 9. if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) 10. return; 11.
wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/ 6/13

12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27.

// if our nonce isn't there, or we can't verify it, bail if (!isset($_POST['vanity_nonce']) || !wp_verify_nonce($_POST['vanity_nonce'], 'my_vanity_nonce')) return; // if our current user can't edit this post, bail if (!current_user_can('edit_post')) return; $_vanity_key = empty($_POST['_vanity_key']) ? base_convert($post_id, 10, 36) : preg_replace('/[^a-z09_]/i', '_', $_POST['_vanity_key']); $old_key = get_post_meta($post_id, '_vanity_key', true); if ($_vanity_key == $old_key) { //We are updating post, and the key is not changed so it's not necessary to save again return; } update_post_meta($post_id, '_vanity_key', $_vanity_key); }

If we are saving the post automatically, there is no point to save our custom field. We also checked to make sure form has a valid n n e oc field to avoid double submit and to make sure data came from the right place. If the users entered a value in the vanity field, then value of $ P S [ _ a i y k y ]in PHP is not empty, lets use it, otherwise we _OT'vnt_e' automatically generate a key by converting the id of post into base 36 number. Then we use u d t _ o t m t to save it. Before saving, paeps_ea we get the current value of custom field _ a i y k yand compare it with our new key which is entered by the user or generated by our vnt_e code to see if we really need to save it. If the old value and new value are the same there is no point to save it again.

Error handling
Everything is looking pretty good at this point, but maybe youre wondering what happens if the user enters a vanity key which has been used before? Or what if the user enters an invalid url? We need some sort of error handling to help the users along the way here. Firstly, lets create a method called _ e 2 r . As its name says about it, it will receive a key, and try to find if we already have an URL kyul corresponding to this key. view plaincopy to clipboardprint? 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. /** * Find the original url respond to this key * @global wpdb $wpdb * @param string $key * @return bool or string * false if not found and original url corresponding otherwise */ private function _key2url($key) { global $wpdb; $sql = " SELECT m.post_id, p.post_title as url FROM {$wpdb->prefix}postmeta as m LEFT JOIN {$wpdb->prefix}posts as p ON m.post_id=p.id WHERE m.meta_key='_vanity_key' AND m.meta_value='%s' "; $result = $wpdb->get_row($wpdb->prepare($sql, $key)); if (!$result) { return false; } 'http://' != substr($result->url, 0, '7') && $result->url = 'http://' . $result->url;
7/13

wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/

21. return $result->url; 22. } If a vanity key has not already been used, then a false value will be returned. Otherwise, the URL which matches with that key in database will be returned. We also prepend http:// to URL if needed. We must do this because of missing leading http:// can make WordPress redirect to ourdomain.com/original.com instead http://original.com. WordPress stores custom fields in the table wp_postmeta, and posts are stored in the table wp_posts. Here wp_ is a prefix which we can access via $wpdb->prefix. We use MySql JOIN clause to match data. Below is a figure on how WordPress store our custom field (our vanity key in this case)

Okay, lets change our method s v _ r for some error handling. Note that I added two new methods: i v l d k yand aeul nai_e i v l d u l We will detail this later. nai_r. view plaincopy to clipboardprint? 1. public function save_url($post_id) { 2. global $post; 3. if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) 4. return; 5. 6. // if our nonce isn't there, or we can't verify it, bail 7. if (!isset($_POST['vanity_nonce']) || !wp_verify_nonce($_POST['vanity_nonce'], 'my_vanity_nonce')) 8. return; 9. 10. // if our current user can't edit this post, bail 11. if (!current_user_can('edit_post')) 12. return; 13. 14. //Also, if the url is invalid, add custom message 15. if (!preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $post->post_title)) { 16. add_filter('redirect_post_location', array($this, 'invalid_url')); 17. } 18. 19. $_vanity_key = empty($_POST['_vanity_key']) ? base_convert($post_id, 10, 36) : preg_replace('/[^a-z09_]/i', '_', $_POST['_vanity_key']); 20. $old_key = get_post_meta($post_id, '_vanity_key', true); 21. if ($_vanity_key == $old_key) { 22. //We are updating post, and the key is not changed so it's not necessary to save again 23. return; 24. } 25. //If our key already exists! Let regenerate till we get a new key 26. while ($this->_key2url($_vanity_key)) { 27. $_vanity_key = base_convert(time() + rand(1, 10000), 10, 36); 28. add_filter('redirect_post_location', array($this, 'invalid_key')); 29. } 30. update_post_meta($post_id, '_vanity_key', $_vanity_key); 31. } 32.
wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/ 8/13

33. 34. 35. 36. 37. 38. 39.

public function invalid_key($location, $errnum) { return $location . '&vanity_message=2'; } public function invalid_url($location, $errnum) { return $location . '&vanity_message=1' ; }

We use p e _ a c ( | h t ( ) : / a z - - + . a z - - + * : 0 9 + ? / * ? | ' $ o t > o t t t e to check if rgmth'^tps?/[-09]([-09])([-])(.)$i, ps-ps_il) we have a valid URL. preg_match returns the number of times pattern matches. In this case, | h t ( ) : / a z - - + . a z - - + * : 0 9 + ? / * ? | is a regular expression pattern for an URL which ^tps?/[-09]([-09])([-])(.)$i start with http or https. URL is $ o t > o t t t e(remember we use title of the post as original url). ps-ps_il If URL is not valid, we will call add_filter to warning error. Dont worry about what it means now, I will cover it later. Also, once we got the new vanity key which we assigned to $ v n t _ e , we call method _ e 2 r in while loop to make sure no post is used that vanity key _aiyky kyul before. If the vanity key is already used, we generate a new key. We get the current time by using function t m ( which returns an i tnumber ie) n then plus with a random number and convert total result to a base 36 number . So, how do we notify the user of these on WordPress back-end? The mechanism for solving this inside WordPress looks like this: after saving post, WordPress redirects the user to the post editing page, and appends some parameters to URL as flags to display messages. Try to look at these to figure out and notice the parameter message in URL and the actual message in yellow. If you look at the URL of WordPress after saving a post, you see something like this: h t : / o s . x o o c m v n t / p tp/hueact.o/aiywa m n p s . h ? o t 1 & c i n e i & e s g = and a message is shown as in the picture below: di/otppps=3ato=dtmsae1

If you try to modify the message parameter on URL you have:

wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/

9/13

Unfortunately, WordPress doesnt have a document for filter r d r c _ o t l c t o now but you can understand simply eietps_oain that this hook gives us a simple way to modify the URL which WordPress will redirect to after saving a post. Well, you should understand now how WordPress shows notifications to the user via parameters on URL. So when saving our post type in method s v _ r , if any error happens, we will alter the URL which WordPress will redirect to and append our custom parameter. aeul WordPress provides filter r d r c _ o t l c t o to do this. This is an extract from above code for you see it more clearly: eietps_oain view plaincopy to clipboardprint? 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. //.. add_filter('redirect_post_location', array($this, 'invalid_key')); add_filter('redirect_post_location', array($this, 'invalid_url')); //.. public function invalid_key($location, $errnum) { return $location . '&vanity_message=2'; } public function invalid_url($location, $errnum) { return $location . '&vanity_message=1' ; }

In each case, we append a custom parameter vanity_message with a value: 1 means invalid URL, 2 means the key is already use. Next. we must show our custom message with this vanity_message. Lets modify our method m t _ o _ o t n : eabxcnet view plaincopy to clipboardprint? 1. public function meta_box_content() { 2. global $post; 3. wp_nonce_field('my_vanity_nonce', 'vanity_nonce'); 4. 5. $_vanity_key = get_post_meta($post->ID, '_vanity_key', true); 6. 7. if (!empty($_GET['vanity_message'])) : 8. switch ((int) $_GET['vanity_message']) : 9. case 1: 10. echo '<div class="updated"><p> URL is not valid</p></div>'; 11. break; 12. case 2: 13. echo '<div class="updated"><p>Your custom key is already existed so we generated other key</p></div>';
wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/ 10/13

14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. }

break; endswitch; endif ?> <p> <label><?php echo __('URL Key') ?>:</label> <input name="_vanity_key" type="text" value="<?php echo $_vanity_key ?>" /> You can put your custom url key here if wanted! </p> <?php if (!empty($_vanity_key)) : ?> <p> <label><?php echo __('Your whole shorted url') ?>:</label> <input size="50" type="text" value="<?php echo trailingslashit(get_bloginfo('url')), $_vanity_key ?>" /> <a target="_blank" href="<?php echo trailingslashit(get_bloginfo('url')), $_vanity_key ?>">Try it</a> </p> <?php endif ?> <?php

We can output the error message in our meta box. But the good thing is as long as you set the class of any element on the page to updated then WordPress automatically grabs it and moves it to right place like this:

You maybe say wow after reading this! But as I told you, WordPress is really clever and does many things for you, just they cannot document everything.

Step 3 Detecting url and redirecting


At this moment, you were able to add a new URL and save the URL. Its now time to try shorten the URL now! What happens if an user hits short url? Well, WordPress loads up, and will process URL into query property of class w _ u r . pqey This class has a global instance: $ p q e y We will hook into one of the WordPress hooks before header is printed out to redirect the w_ur. users to the original url. If the header is printed out, how come we can make redirect, right? To make it easier to understand, lets hook into action get_header. view plaincopy to clipboardprint? 1. private function _bootstrap() { 2. add_action('init', array($this, 'init')); 3. add_action('add_meta_boxes', array($this, 'add_meta_box'));
wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/ 11/13

4. add_action('save_post', array($this, 'save_url')); 5. 6. add_action('get_header', array($this, 'check_url')); 7. } 8. 9. public function check_url() { 10. global $wp_query; 11. global $wpdb; 12. if (!$wp_query->is_404) { 13. //This is a valid URL of WordPress! 14. return false; 15. } 16. $key = empty($wp_query->query['pagename']) ? false : $wp_query->query['pagename']; 17. if ($key && $url = $this->_key2url($key)) { 18. wp_redirect($url); 19. } 20. } So, when you go to url domain.com/foo WordPress will store foo as pagename of $ p q e y > u r if it cannot detect any w_ur-qey permalink (post slug, category name,..) which matched this URL. Once we got the key, we call method _ e 2 r to get URL of that key. kyul If it found one, we redirect to that original URL. Alternatively, we just call _ e 2 r if WordPress output did not find a page! There is no kyul point to call _ e 2 r every time because it needs query database and this can be a performance issue if your site has huge traffic. Finally, kyul you have done it! Thats all that you need to do to have a shorten url service with WordPress.

Step 4 Making it even better


At this point, you can add a url and have a list of url posts in WordPress dashboard! But to see the short url and vanity key, you must edit a post to see it Thats really annoying! So, lets put this vanity key on post listing page. We can achieve this with filter manage_edit{post_type}_columns and action manage_{post_type}_custom_column Filter allows us add more columns when listing our custom post type besides normal columns such as: title, author,etc. Action lets us really build content for that column. As always, you must inject a d a t o and a d f l e to the _ o t t a method: d_cin d_itr bosrp view plaincopy to clipboardprint? 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. private function _bootstrap() { add_action('init', array($this, 'init')); add_action('add_meta_boxes', array($this, 'add_meta_box')); add_action('save_post', array($this, 'save_url')); add_action('get_header', array($this, 'check_url')); add_filter('manage_edit-' . self::POST_TYPE . '_columns', array($this, 'custom_column')); add_action('manage_' . self::POST_TYPE . '_posts_custom_column', array($this, 'column_content'), 10, 2); } /** * WordPress will pass an array of columns to this function. * The key of each element is the name of column. * @param array of columns */ public function custom_column($columns) { $columns['_vanity_key'] = __('Vanity Key', 'wp-vanity'); return $columns; } public function column_content($column_name, $post_id) {
12/13

wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/

22. 23. 24. 25. 26. 27. 28. 29. 30. 31.

global $wpdb; switch ($column_name) { case '_vanity_key': $key = get_post_meta($post_id, '_vanity_key', true); if ($key) { echo sprintf('<a target="_blank" href="%s" title="Original URL">%s</a>', trailingslashit(get_bloginfo('url')), $key, $key); } break; } }

Columns are stored in an array which is passed to our filter method. We add a new column via appending a new element to that array. Method custom_column takes care of this. The modified array is returned, WordPress grabs returned value and recognizes the new column. The name of column is _ a i y k y We use it to reference our column later. The title of column is Vanity Key this is the text vnt_e. which appears on table header. We use method column_content to output content of this column. WordPress passes two parameters to functions which hooked action
mng_ps aae{ot t p n m } p s s c s o _ o u n The first one is name of column, ye ae_ot_utmclm:

the second one is the id of the post which is rendering.

Based on this, we check to make sure value of variable $ o u n n m is _ a i y k y the name of our column. Then we use clm_ae vnt_e, g t p s _ e ato read the custom field _ a i y k y Finally, we print out an a element with target=_blank to open it in a new e_otmt vnt_e. window. If you had other columns, you could continue with other case statements for those columns. Now you can take a look at two pictures: before and after using above filter, action. The first one doesnt have a vanity column while second one has a vanity column with each posts vanity key.

Conclusion
Finally, you now have your own shorten url service with just around 60-70 minutes of coding and can use your current WordPress site with current domain. Hopefully, youve found this tutorial to be of help. Feel free to reuse this code elsewhere in your projects. If you have something to say or share, or even teach me as well, then please leave me a comment!
Like 37 people like this. Be the first of your friends.

Tags: CMSCodecustomHTMLMeta BoxesPHPpluginRoutersServiceTutorialURLwordpress

By Vinh Quc Nguyn


I'm a developer from Vietnam, a beautiful sunny country, fall in love with PHP, Ruby, JavaScript. I run a small web development business called Axcoto specializing in WordPress/ExpressionEngine, Facebook development. I also contribute someopen source plugins. To me, code is poetry. I'm enjoy writing code which is short, elegant, rhythmic. wp-vanity.zip is the source code for downloading. Also, I'm an author on CodeCanyon too. This is my profile http://codecanyon.net/user/kureikain/

wp.tutsplus.com/tutorials/build-a-short-url-service-with-wordpress-custom-post-types/

13/13

Das könnte Ihnen auch gefallen