Posts Issued in August, 2014

  • Register Custom Shortcodes
  • $shortcode_tags
  • Enables [url] and [b] shortcodes in comments
  • Display Time - Limited Content, Obfuscate Email Addresses, Members Eyes Only

Register Custom Shortcodes

// Register a new shortcode: [book]
add_shortcode( 'book', 'ssd_sc1_book' );
 
// The callback function that will replace [book]
function ssd_sc1_book() {
    return 'http://www.amazon.com/dp/0470560541';
}
 
 
//shortcode with parameters
// Register a new shortcode: [books title="xxx"]
add_shortcode( 'books', 'ssd_sc2_multiple_books' );
 
// The callback function that will replace [books]
function ssd_sc2_multiple_books( $attr ) {
    switch( $attr['title'] ) {
        case 'xkcd':
            $isbn = '0615314465';
            $title = 'XKCD Volume 0';
            break;
 
        default:
        case 'prowp':
            $isbn = '0470560541';
            $title = 'Profesional WordPress';
            break;
    }
 
    return "<a href='http://www.amazon.com/dp/$isbn'>$title</a>";
}
 
/*The anchor text in the Amazon link will now be parameterized. this time with a second parameter $content , which will receive any enclosed text as a string. Replace [amazon isbn=”xxx”]book title[/amazon] */
// Register a new shortcode: [amazon isbn="123"]link title[/amazon]
add_shortcode( 'amazon', 'ssd_sc3_amazon' );
 
// Callback function for the [amazon] shortcode
function ssd_sc3_amazon( $attr, $content ) {
 
    // Get ISBN or set default
    if( isset( $attr['isbn'] ) ) {
        $isbn = preg_replace( '/[^\d]/', '', $attr['isbn'] );
    } else {
        $isbn = '0470560541';
    }
 
    // Sanitize content, or set default
    if( !empty( $content ) ) {
        $content = esc_html( $content );
    } else {
        if( $isbn == '0470560541' ) {
            $content = 'Professional WordPress';
        } else {
            $content = 'this book';
        }
    }
 
    return "<a href='http://www.amazon.com/dp/$isbn'>$content</a>";
}

Replace [amazonimage] with images from Amazon

<?php
/*
Plugin Name: Shortcode Example 4
Plugin URI: http://example.com/
Description: Replace [amazonimg] with images from Amazon
Version: 1.0
*/
 
// Register shortcodes [amazonimage] and [amazonimg]
add_shortcode( 'amazonimage', 'ssd_sc4_amazonimage' );
add_shortcode( 'amazonimg', 'ssd_sc4_amazonimage' );
 
// Callback function for the [amazonimage] shortcode
function ssd_sc4_amazonimage( $attr, $content ) {
 
    // Get ASIN or set default
    $possible = array( 'asin', 'isbn' );
    $asin = ssd_sc4_find( $possible, $attr, '0470560541' );
 
    // Get affiliate ID or set default
    $possible = array( 'aff', 'affiliate' );
    $aff = ssd_sc4_find( $possible, $attr, 'aff_id' );
 
    // Get image size if specified
    $possible = array( 'size', 'image', 'imagesize' );
    $size = ssd_sc4_find( $possible, $attr, '' );
 
    // Get type if specified
    if( isset( $attr['type'] ) ) {
        $type = strtolower( $attr['type'] );
        $type = ( $type == 'cd' or $type == 'disc' ) ? 'cd' : '';
    }
 
    // Now build the Amazon image URL
    $img = 'http://images.amazon.com/images/P/';
    $img .= $asin;
    // Image option: size
    if( $size ) {
        switch( $size ) {
            case 'small':
                $size = '_AA100';
                break;
            default:
            case 'medium':
                $size = '_AA175';
                break;
            case 'big':
            case 'large':
                $size = '_SCLZZZZZZZ';
        }
    }
    // Image option: type
    if( $type == 'cd' ) {
        $type = '_PF';
    }
    // Append options to image URL, if any
    if( $type or $size ) {
        $img .= '.01.'.$type.$size;
    }
    // Finish building the image URL
    $img .= '.jpg';
 
    // Now return the image
    return "<a href='http://www.amazon.com/dp/$asin'><img src='$img' /></a>";
}
 
// Helper function:
// Search $find_keys in array $in_array, return $default if not found
function ssd_sc4_find( $find_keys, $in_array, $default ) {
    foreach( $find_keys as $key ) {
        if( isset( $in_array[$key] ) )
            return $in_array[$key];
    }
    return $default;
}

$shortcode_tags

$shortcode_tags = array (wp_caption’ = > ‘img_caption_shortcode’,
‘caption’ = > ‘img_caption_shortcode’,
‘gallery’ = > ‘gallery_shortcode’,
‘embed’ = > ‘__return_false’,
‘amazonimage’ = > ‘ssd_sc4_amazonimage’,
‘amazonimg’ = > ‘ssd_sc4_amazonimage’,
)

A "bb code" for Comments Plugin You can now code a new plugin to enable BB - like tags in comments: Instead of using regular HTML tags such as < a > or < b > , commenters need to use [url] and [b] like in most forums. The plugin will also have the following traits: It should not change how authors write their posts (with HTML tags as usual). It should not apply to comments shortcodes otherwise egistered for posts, such as [amazonimage] in your previous plugin or [gallery] . Simple Start

/*
Plugin Name: Shortcode Example 5
Plugin URI: http://example.com/
Description: Recursive [b] and [i] shortcodes
Version: 1.0
*/
 
// add shortcodes [b] and [i]
add_shortcode( 'i', 'ssd_sc5_italic' );
add_shortcode( 'b', 'ssd_sc5_bold' );
 
// callback function: return bold text
function ssd_sc5_bold( $attr, $content ) {
    return "<strong>".do_shortcode( $content )."</strong>";
}
 
// callback function: return italic text
function ssd_sc5_italic( $attr, $content ) {
    return "<em>".do_shortcode( $content )."</em>";
}

ALGO 1. Plugin does not register new shortcodes [url] and [b] directly from the start; otherwise, they would interfere with the post contents. Instead, the plugin starts with capturing each comment’s contents. 2. The comment processing function, unregisters all shortcodes after making a copy of them. 3. New shortcodes are then registered: [url] and [b]. 4. The comment content, kept in the variable $comment , is expurgated from regular HTML tags and then applied to the newly registered shortcodes. 5. Shortcode callback function for bold text recursively calls do_shortcode() , enabling for nested structures. 6. Original shortcodes are restored; the comment shortcodes [url] and [b] are unregistered by the way. 7. The formatted comment content is returned for display.

<?php
/*
Plugin Name: Shortcode Example 6
Plugin URI: http://example.com/
Description: Enables [url] and [b] shortcodes in comments
Version: 1.0
*/
 
// Hook into 'comment_text' to process comment content
add_filter( 'comment_text', 'ssd_sc6_comments' );
 
// This function processes comment content
function ssd_sc6_comments( $comment ) {
 
    // Save registered shortcodes:
    global $shortcode_tags;
    $original = $shortcode_tags;
 
    // Unregister all shortcodes:
    remove_all_shortcodes();
 
    // Register new shortcodes:
    add_shortcode( 'url', 'ssd_sc6_comments_url' );
    add_shortcode( 'b', 'ssd_sc6_comments_bold' );
    add_shortcode( 'strong', 'ssd_sc6_comments_bold' );
 
    // Strip all HTML tags from comments:
    $comment = wp_strip_all_tags( $comment );
 
    // Process comment content with these shortcodes:
    $comment = do_shortcode( $comment );
 
    // Unregister comment shortcodes, restore normal shortcodes
    $shortcode_tags = $original;
 
    // Return comment:
    return $comment;
}
 
// the [b] or [strong] to <strong> callback
function ssd_sc6_comments_bold( $attr, $text ) {
    return "<strong>".do_shortcode( $text )."</strong>";
}
 
// the [url] to <a> callback
function ssd_sc6_comments_url( $attr, $text ) {
    $text = esc_url( $text );
    return "<a href=\"$text\">$text</a>";
}

Display Time - Limited Content

<?php
/*
Plugin Name: Shortcode Example 8
Plugin URI: http://example.com/
Description: Various shortcodes: [24hours], [members], [email]
Version: 1.0
*/
 
add_shortcode( '24hours', 'ssd_sc8_24hours' );
 
function ssd_sc8_24hours( $attr, $content ) {
    $now = time();
    $post_time = get_the_date( 'U' );
    if( ( $now - $post_time ) > 86400 ) {
        return 'Offer has expired!';
    } else {
        return $content;
    }
}
 
add_shortcode( 'members', 'ssd_sc8_loggedin' );
 
function ssd_sc8_loggedin( $attr, $content ) {
    if( is_user_logged_in() ) {
        return $content;
    } else {
        return "<p>Members Eyes Only</p>";
    }
}
 
add_shortcode( 'email', 'ssd_sc8_email' );
 
function ssd_sc8_email( $attr, $content ) {
    if( is_email( $content ) ) {
        return sprintf( '<a href="mailto:%s">%s</a>',
            antispambot( $content ),
            antispambot( $content )
        );
    } else {
        return '';
    }
}
  • Checking if a Table Already Exists
  • Plugin that displays the avatar by role
  • Plugin with User Metadata
  • Roles
  • Plugin limits the editing of admin posts
  • Plugin Forum Roles
//Checking if a Table Already Exists
$tablename = $wpdb- > prefix . “hits”;
if( $wpdb- > get_var(SHOW TABLES LIKE$tablename’”) != $tablename ) {
// table does not exist!
}

plugin that displays the avatar by role

<?php
/*
Plugin Name: User Avatars
Plugin URI: http://example.com
Description: Displays user avatars based on role.
*/
 
function boj_user_avatars( $role = 'subscriber' ) {
 
    /* Get the users based on role. */
    $users = get_users(
        array(
            'role' => $role
        )
    );
 
    /* Check if any users were returned. */
    if ( is_array( $users ) ) {
 
        /* Loop through each user. */
        foreach ( $users as $user ) {
 
            /* Display ther user's avatar. */
            echo get_avatar( $user );
        }
    }
}
 
?>

The user_contactmethods fi lter hook returns an array of meta keys and labels for these label keys. To add new meta keys, you need to add new values to the array, as shown

/* Add a filter to the hook. */
add_filter( 'user_contactmethods', 'ssd_user_contactmethods' );
 
/* Function for adding new contact methods. */
function ssd_user_contactmethods( $user_contactmethods ) {
 
    /* Add the Twitter contact method. */
    $user_contactmethods['twitter'] = 'Twitter Username';
 
    /* Add the phone number contact method. */
    $user_contactmethods['phone'] = 'Phone Number';
 
    /* Return the array with the new values added. */
    return $user_contactmethods;
}

Plugin with User Metadata

<?php
/*
Plugin Name: User Favorite Post
Plugin URI: http://example.com
Description: Allows users to select their favorite post from the site.
Version: 0.1
 
*/
 
/* Add the post form to the user/profile edit page in the admin. */
add_action( 'show_user_profile', 'ssd_user_favorite_post_form' );
add_action( 'edit_user_profile', 'ssd_user_favorite_post_form' );
 
/* Function for displaying an extra form on the user edit page. */
function ssd_user_favorite_post_form( $user ) {
 
    /* Get the current user's favorite post. */
    $favorite_post = get_user_meta( $user->ID, 'favorite_post', true );
 
    /* Get a list of all the posts. */
    $posts = get_posts( array( 'numberposts' => -1 ) );
    ?>
 
    <h3>Favorites</h3>
 
    <table class="form-table">
 
        <tr>
            <th><label for="favorite_post">Favorite Post</label></th>
 
            <td>
                <select name="favorite_post" id="favorite_post">
                    <option value=""></option>
 
                <?php foreach ( $posts as $post ) { ?>
                    <option value="<?php echo esc_attr( $post->ID ); ?>" 
                    <?php selected( $favorite_post, $post->ID ); ?>>
                        <?php echo esc_html( $post->post_title ); ?>
                    </option>
                <?php } ?>
 
                </select>
                <br />
                <span class="description">Select your favorite post.</span>
            </td>
        </tr>
 
    </table>
<?php }
 
/* Add the update function to the user update hooks. */
add_action( 'personal_options_update', 'ssd_user_favorite_post_update' );
add_action( 'edit_user_profile_update', 'ssd_user_favorite_post_update' );
 
/* Function for updating the user's favorite post. */
function ssd_user_favorite_post_update( $user_id ) {
 
    /* Check if the current user has permission to edit the user. */
    if ( !current_user_can( 'edit_user', $user_id ) )
        return false;
 
    /* Only accept numbers 0-9 since it's a post ID. */
    $favorite_post = preg_replace( "/[^0-9]/", '', $_POST['favorite_post'] );
 
    /* Update the user's favorite post. */
    update_user_meta( $user_id, 'favorite_post', $favorite_post );
}
 
?>

Therefore, as a plugin developer, you can never know exactly what roles exist or might exist for a site unless you have direct access to the install, such as when doing client work. Keep this in mind when developing your plugins. A common mistake many plugin authors make is to check a user ’ s role before executing code. There is rarely a good reason to do this. Your plugin should check for a capability because capabilities determine a user ’ s permission to do something on the site. More precisely, they grant users a set of permissions called capabilities. In general, most plugins won ’ t need to know what roles users have. Most plugins work directly with capabilities because they are what defi ne whether a user has permission to perform a task within the site.

Plugin limits the editing of admin posts

<?php
/*
Plugin Name: Restrict Admin Post Editing
Plugin URI: http://example.com
Description: Only admins can edit posts made by admins.
Version: 0.1
 
*/
 
/* Filter the 'map_meta_cap' hook. */
add_filter( 'map_meta_cap', 'ssd_restrict_admin_post_editing', 10, 4 );
 
/* Function for restricting users from editing admin posts. */
function ssd_restrict_admin_post_editing( $caps, $cap, $user_id, $args ) {
 
    /* If user is trying to edit or delete a post. */
    if ( 'edit_post' == $cap || 'delete_post' == $cap ) {
 
        /* Get the post object. */
        $post = get_post( $args[0] );
 
        /* If an admin is the post author. */
        if ( author_can( $post, 'delete_users' ) ) {
 
            /* Add a capability that only admins might have to the caps array. */
            $caps[] = 'delete_users';
        }
    }
 
    /* Return the array of capabilities. */
    return $caps;
}
 
?>

Allowing Custom Permissions

<?php
/*
Plugin Name: Private Content
Plugin URI: http://example.com
Description: Shortcode for hiding private content.
Version: 0.1
 
*/
 
/* Register shortcodes in 'init'. */
add_action( 'init', 'ssd_private_content_register_shortcodes' );
 
/* Function for registering the shortcode. */
function ssd_private_content_register_shortcodes() {
 
    /* Adds the [ssd-private] shortcode. */
    add_shortcode( 'ssd-private', 'ssd_private_content_shortcode' );
}
 
/* Function for handling shortcode output. */
function ssd_private_content_shortcode( $attr, $content = null ) {
 
    /* If there is no content, return. */
    if ( is_null( $content ) )
        return $content;
 
    /* Check if the current user has the 'read_private_content' capability. */
    if ( current_user_can( 'read_private_content' ) ) {
 
        /* Return the private content. */
        return $content;
    }
 
    /* If the user doesn't have the 'read_private_content' capability. */
    else {
 
        /* Return an alternate message. */
        return '<p>You do not have permission to read this content.</p>';
    }
 
    /* Return an empty string as a fallback. */
    return '';
}
 
?>

Plugin Forum Roles

<?php
/*
Plugin Name: Forum Roles
Plugin URI: http://example.com
Description: Creates custom roles and capabilities for a fictional forum plugin.
Version: 0.1
 
*/
 
/* Custom forum roles and capabilities class. */
class ssd_Forum_Roles {
 
    /* PHP4 Constructor method. */
    function ssd_Forum_Roles() {
 
        /* Register plugin activation hook. */
        register_activation_hook( __FILE__, array( &$this, 'activation' ) );
 
        /* Register plugin deactivation hook. */
        register_deactivation_hook( __FILE__, array( &$this, 'deactivation' ) );
    }
 
    /* Plugin activation method. */
    function activation() {
 
        /* Get the default administrator role. */
        $role =& get_role( 'administrator' );
 
        /* Add forum capabilities to the administrator role. */
        if ( !empty( $role ) ) {
            $role->add_cap( 'publish_forum_topics' );
            $role->add_cap( 'edit_others_forum_topics' );
            $role->add_cap( 'delete_forum_topics' );
            $role->add_cap( 'read_forum_topics' );
        }
 
        /* Create the forum administrator role. */
        add_role(
            'forum_administrator',
            'Forum Administrator',
            array(
                'publish_forum_topics',
                'edit_others_forum_topics',
                'delete_forum_topics',
                'read_forum_topics'
            )
        );
 
        /* Create the forum moderator role. */
        add_role(
            'forum_moderator',
            'Forum Moderator',
            array(
                'publish_forum_topics',
                'edit_others_forum_topics',
                'read_forum_topics'
            )
        );
 
        /* Create the forum member role. */
        add_role(
            'forum_member',
            'Forum Member',
            array(
                'publish_forum_topics',
                'read_forum_topics'
            )
        );
 
        /* Create the forum suspended role. */
        add_role(
            'forum_suspended',
            'Forum Suspended',
            array( 'read_forum_topics' )
        );
    }
 
    /* Plugin deactivation method. */
    function deactivation() {
 
        /* Get the default administrator role. */
        $role =& get_role( 'administrator' );
 
        /* Remove forum capabilities to the administrator role. */
        if ( !empty( $role ) ) {
            $role->remove_cap( 'publish_forum_topics' );
            $role->remove_cap( 'edit_others_forum_topics' );
            $role->remove_cap( 'delete_forum_topics' );
            $role->remove_cap( 'read_forum_topics' );
        }
 
        /* Set up an array of roles to delete. */
        $roles_to_delete = array(
            'forum_administrator',
            'forum_moderator',
            'forum_member',
            'forum_suspended'
        );
 
        /* Loop through each role, deleting the role if necessary. */
        foreach ( $roles_to_delete as $role ) {
 
            /* Get the users of the role. */
            $users = get_users( array( 'role' => $role ) );
 
            /* Check if there are no users for the role. */
            if ( count( $users ) <= 0 ) {
 
                /* Remove the role from the site. */
                remove_role( $role );
            }
        }
    }
}
 
$forum_roles = new ssd_Forum_Roles();
 
?>

Need to remember how the relationship of users, roles, and capabilities works. Capabilities control permissions. Roles are given capabilities. Users are assigned roles, and each role ’ s capabilities are extended to its users. Keeping this in mind when developing your plugins can make the development process much smoother.

  • Options API, Settings API
  • Complete Plugin Management Page
  • Example Using Transients API
  • per - user settings

The Options API is a set of functions that enable easy access to the database where WordPress, plugins, and themes save and fetch needed information. Options are stored in a database table named, by default, wp_options and can be text, integers, arrays, or objects.

THE SETTINGS API- Options can be internally created and updated by your plugin, But they are also frequently used to store settings the end user will modify through your plugin administration page. Dealing with user inputs introduces new constraints in the option process: You need to design a user interface, monitor form submissions, handle security checks, and validate user inputs. To easily manage these common tasks, WordPress wraps the option functions into a comprehensive Settings API.

Complete Plugin Management Page:

<?php
/*
Plugin Name: Settings API example
Plugin URI: http://example.com/
Description: A complete and practical example of use of the Settings API. This plugin creates a new plugin administration page.
*/
 
// Add a menu for our option page
add_action('admin_menu', 'ssd_myplugin_add_page');
function ssd_myplugin_add_page() {
    add_options_page( 'My Plugin', 'My Plugin', 'manage_options', 'ssd_myplugin', 'ssd_myplugin_option_page' );
}
 
// Draw the option page
function ssd_myplugin_option_page() {
    ?>
    <div class="wrap">
        <?php screen_icon(); ?>
        <h2>My plugin</h2>
        <form action="options.php" method="post">
            <?php settings_fields('ssd_myplugin_options'); ?>
            <?php do_settings_sections('ssd_myplugin'); ?>
            <input name="Submit" type="submit" value="Save Changes" />
        </form>
    </div>
    <?php
}
 
// Register and define the settings
add_action('admin_init', 'ssd_myplugin_admin_init');
function ssd_myplugin_admin_init(){
    register_setting(
        'ssd_myplugin_options',
        'ssd_myplugin_options',
        'ssd_myplugin_validate_options'
    );
    add_settings_section(
        'ssd_myplugin_main',
        'My Plugin Settings',
        'ssd_myplugin_section_text',
        'ssd_myplugin'
    );
    add_settings_field(
        'ssd_myplugin_text_string',
        'Enter text here',
        'ssd_myplugin_setting_input',
        'ssd_myplugin',
        'ssd_myplugin_main'
    );
}
 
// Draw the section header
function ssd_myplugin_section_text() {
    echo '<p>Enter your settings here.</p>';
}
 
// Display and fill the form field
function ssd_myplugin_setting_input() {
    // get option 'text_string' value from the database
    $options = get_option( 'ssd_myplugin_options' );
    $text_string = $options['text_string'];
    // echo the field
    echo "<input id='text_string' name='ssd_myplugin_options[text_string]' type='text' value='$text_string' />";
}
 
// Validate user input (we want text only)
function ssd_myplugin_validate_options( $input ) {
    $valid['text_string'] = preg_replace( '/[^a-zA-Z]/', '', $input['text_string'] );
 
    if( $valid['text_string'] != $input['text_string'] ) {
        add_settings_error(
            'ssd_myplugin_text_string',
            'ssd_myplugin_texterror',
            'Incorrect value entered!',
            'error'
        );        
    }
 
    return $valid;
}

The validation function you ’ ve previously defi ned could be slightly improved by letting the users know they have entered an unexpected value and that it has been modifi ed so that they can pay attention to it and maybe amend their input. The relatively unknown function add_settings_error() of the Settings API can handle this case. Your previous plugin was adding a whole new section and its input fi eld on a standalone page: You now modify it to insert this content into WordPress ’ Privacy Settings page. Of course, it can even make sense to add just one fi eld and no section header to an existing page.

Adding a Section to an Existing Page

<?php
/*
Plugin Name: Settings API example 2
Plugin URI: http://example.com/
Description: A complete and practical example of use of the Settings API. This one adds a field to the Privacy Settings page
*/
 
// Register and define the settings
add_action('admin_init', 'ssd_myplugin_admin_init');
function ssd_myplugin_admin_init(){
    register_setting(
        'privacy', 
        'ssd_myplugin_options',
        'ssd_myplugin_validate_options' 
    );
 
    add_settings_field(
        'ssd_myplugin_text_string',
        'Enter text here',
        'ssd_myplugin_setting_input',
        'privacy',
        'default'
    );
 
}
 
// Display and fill the form field
function ssd_myplugin_setting_input() {
    // get option 'text_string' value from the database
    $options = get_option( 'ssd_myplugin_options' );
    $text_string = $options['text_string'];
    // echo the field
    echo "<input id='text_string' name='ssd_myplugin_options[text_string]' type='text' value='$text_string' />";
}
 
// Validate user input (we want text only)
function ssd_myplugin_validate_options( $input ) {
    $valid['text_string'] = preg_replace( '/[^a-zA-Z]/', '', $input['text_string'] );
 
    if( $valid['text_string'] != $input['text_string'] ) {
        add_settings_error(
            'ssd_myplugin_text_string',
            'ssd_myplugin_texterror',
            'Incorrect value entered!',
            'error'
        );        
    }
 
    return $valid;
}

Example Using Transients API

<?php
/*
Plugin Name: Transients API example
Plugin URI: http://example.com/
Description: Sample plugin to illustrate how the Transients API works.
*/
 
// Fictional function that fetchs from an online radio a song title currently on air
function ssd_myplugin_fetch_song_title_from_radio() {
    /*
    Here you would find code fetching data from a remote web site.
    See Chapter 10 to learn how to do this.
 
    In this example we will just return a random song title from a few fictional ones
    */
 
    $titles = array(
        'I Heart WordPress - by  Hackers',
        'Highway to Heaven - by AB/CD',
        'WorpDress Roks - by Miss Spellings',
        'Careful With That Hack, Eugene - by Fink Ployd'
    );
 
    // Get a random song title and return it
    $random = $titles[ mt_rand(0, count($titles) - 1) ];
    return $random;
}
 
// Get song title from database and return it
function ssd_myplugin_get_song_title() {
 
    // Get transient value
    $title = get_transient( 'ssd_myplugin_song' );
 
    // If the transient does not exists or has expired, refresh it
    if( false === $title ) {
        $title = ssd_myplugin_fetch_song_title_from_radio();
        set_transient( 'ssd_myplugin_song', $title, 180 );
    }
 
    return $title;
}

Admin Lang Plugin

<?php
/*
Plugin Name: Per User Setting example
Plugin URI: http://example.com/
Description: Add a user option in Profile to allow choosing either English or Spanish in the admin area
 
*/
 
// Return user's locale
function ssd_adminlang_set_user_locale() {
    $user = wp_get_current_user();
    $userid = $user->ID;
    $locale = get_user_meta( $userid, 'ssd_adminlang_lang', true );
    return $locale;
}
// Trigger this function every time WP checks the locale value
add_filter( 'locale', 'ssd_adminlang_set_user_locale' );
 
// Add and fill an extra input field to user's profile
function ssd_adminlang_display_field( $user ) {
 
    $userid = $user->ID;
    $lang = get_user_meta( $userid, 'ssd_adminlang_lang', true );
 
    ?>
    <tr>
        <th scope="row">Language</th>
        <td>
            <select name="ssd_adminlang_lang">
                <option value="" <?php selected( '', $lang); ?>>English</option>
                <option value="es_ES" <?php selected( 'es_ES', $lang); ?>>Espa&ntilde;ol</option>
            </select>
        </td>
    </tr>
    <?php
}
add_action( 'personal_options', 'ssd_adminlang_display_field' );
 
// Monitor form submits and update user's setting if applicable
function ssd_adminlang_update_field( $userid ) {
    if( isset( $_POST['ssd_adminlang_lang'] ) ) {
        $lang = $_POST['ssd_adminlang_lang'] == 'es_ES' ? 'es_ES' : '';
        update_user_meta( $userid, 'ssd_adminlang_lang', $lang );
    }
}
add_action( 'personal_options_update', 'ssd_adminlang_update_field' );

For this plugin to work, the WordPress installation needs to include the Spanish translation fi les you can get from http://es.wordpress.org/ . Put the es_ES fi les in the directory wp - content/languages (which you might need to create fi rst).

  • Check current_user_can()
  • Nonces
  • Validating and Sanitizing Cookbook
  • $wpdb

Example Check current_user_can()

<?php
/*
Plugin Name: Simple Debug
Plugin URI: http://example.com/
Description: Append ?debug=1 to any URL to display debug information if you are an admin
*/
 
add_action( 'init', 'ssd_debug_check' );
 
function ssd_debug_check() {
    if( isset( $_GET['debug'] ) && current_user_can( 'manage_options' ) ) {
        if( !defined( 'SAVEQUERIES' ) )
            define( 'SAVEQUERIES', true );
        add_action( 'wp_footer', 'ssd_debug_output' );
    }
}
 
// Print debug information
function ssd_debug_output() {
    global $wpdb;
    echo "<pre>";
    print_r($wpdb->queries);
    echo "</pre>";
}

Nonces - Authority Versus Intention. Now imagine people maliciously crafting a link that would delete a post on your blog. They could not use it themselves, of course, because they have no admin account, But what if they trick you into clicking on this link? Because you are logged in, the action would occur, and the post would be deleted. You had authority but no intention. The malicious users just completed a Cross Site Request Forgery

In computer language, a nonce, or cryptographic nonce, is the abbreviation of “ number used once. ” In WordPress, it is a short and apparently random string such as a password, which is specifi c to the following: One WordPress user, One action (delete, update, save, and such), One object (a post, a link, a plugin setting, and such), One time frame of 24 hours. For example, http://example.com/wp - admin/post.php?post=43 & action=trash & wpnonce=83a08fcbc2

<?php
/*
Plugin Name: Unused Tags
Plugin URI: http://example.com/
Description: Find unused tags and rename or delete them
*/
 
// Add an entry for our option page to the Posts menu
add_action('admin_menu', 'ssd_utags_add_page');
function ssd_utags_add_page() {
    add_posts_page( 'Unused Tags', 'Unused Tags', 'manage_options',
        'ssd_utags', 'ssd_utags_option_page' );
}
 
// Catch any action parameter in query string
add_action( 'admin_init', 'ssd_utags_do_action' );
 
// Proceed to requested ssd_action if applicable
function ssd_utags_do_action() {
    if( !isset( $_REQUEST['ssd_action'] ) )
        return;
 
    if( !current_user_can( 'manage_options' ) )
        wp_die( 'Insufficient privileges!' );
 
    $id     = $_REQUEST['id'];
    $action = $_REQUEST['ssd_action'];
 
    if( $action == 'done' ) {
        add_action( 'admin_notices', 'ssd_utags_message' );
        return;
    }
 
    check_admin_referer( 'ssd_utags-'.$action.'_tag'.$id );
 
    switch( $action ) {
        case 'rename':
            $newtag = array( 'name' => $_POST['name'], 'slug' => $_POST['name'] );
            wp_update_term( $id, 'post_tag', $newtag );
            break;
        case 'delete':
            wp_delete_term( $id, 'post_tag' );
            break;
    }
 
    wp_redirect( add_query_arg( array( 'ssd_action' => 'done' ) ) );
 
}
 
// Admin notice
function ssd_utags_message() {
    echo "<div class='updated'><p>Action completed</p></div>";
}
 
// Draw the tag management page
function ssd_utags_option_page() {
    ?>
    <div class="wrap">
        <?php screen_icon(); ?>
        <h2>Unused Tags</h2>
 
        <?php
 
        if( $tags = ssd_utags_find_orphans() ):
 
        echo '<p>You currently have '.count( $tags ). ' unused tags:</p>';
        echo '<ol>';
 
        foreach( $tags as $tag ) {
            $id   = $tag->term_id;
            $name = esc_attr( $tag->name );
 
            $delete_url= add_query_arg( array('ssd_action'=>'delete','id'=>$id) );
            $nonced_url= wp_nonce_url( $delete_url, 'ssd_utags-delete_tag'.$id );
            ?>
            <li>
            <form action="" method="post">
            <?php wp_nonce_field( 'ssd_utags-rename_tag'.$id ); ?>
            <input type="hidden" name="ssd_action" value="rename" />
            <input type="hidden" name="id" value="<?php echo $id; ?>" />
            <input type="text" name="name" value="<?php echo $name; ?>" />
            <input type="submit" value="Rename" /> or
            <a href="<?php echo $nonced_url; ?>">delete</a> this tag
            </form>
            </li>
 
        <?php }
 
        else: ?>
        <p>You have no unused tags.</p>
 
        <?php endif; ?>
 
        </ol>
    </div>
    <?php
}
 
// Find unused tags, return them in an array
function ssd_utags_find_orphans() {
    global $wpdb;
 
    $sql = "SELECT terms.term_id, terms.name FROM {$wpdb->terms} terms
            INNER JOIN {$wpdb->term_taxonomy} taxo
            ON terms.term_id=taxo.term_id
            WHERE taxo.taxonomy = 'post_tag'
            AND taxo.count=0";
 
    return $wpdb->get_results( $sql );
}

Validating and Sanitizing Cookbook

  • Integers - intval($data) or is_int($data)
  • Strings - ctype_ family BOOL: ctype_alpha($num) - alphabetic, ctype_alnum($num) - alphanumeric, sanitize_text_field( “I am nice.\n Very < em > nice < /em > ! “ )
  • Internal Identifi er Strings validate date
function ssd_validate_date( $date ) {
    // first test: pattern matching
    if( !preg_match( '!\d{2}/\d{2}/\d{4}!', $date ) )
        return 'wrong pattern';
 
    // second test: is date valid?
    $timestamp = strtotime( $date );
    if( !$ t i m e s t a m p )
        return 'date invalid';
 
    // third test: is the date from the past?
    if( $timestamp <= time() )
        return 'past date';
 
    // So far, so good
    return true;
}
 
// Test it:
 
var_dump( ssd_validate_date( '12/12/99' ) );
// string(12) "wrong pattern"
 
var_dump( ssd_validate_date( '35/30/1980' ) );
// string(12) "date invalid"
 
var_dump( ssd_validate_date( '03/30/1980' ) );
// string(9) "past date"
 
var_dump( ssd_validate_date( '03/30/2020' ) );
// bool(true)

$wpdb

$values = array(column1’ = > ‘some string’,
‘column2’ = > 43
);
$where = array(ID’ = > 1
);
$formats_values = array( ‘%s’, ‘%d);
$formats_where = array( ‘%d);
$wpdb- > update( $wpdb- > custom, $values, $where, $formats_values, $formats_where );
 
$values = array(column1’ = > ‘new string’,
‘column2’ = > 44
);
$formats_values = array( ‘%s’, ‘%d);
$wpdb- > insert( $wpdb- > custom, $values, $formats_values );
 
$sql = “SELECT COUNT(ID) FROM {$wpdb- > posts}
WHERE post_status = ‘publishAND post_type = ‘post’”;
$num_of_posts = $wpdb- > get_var( $sql );
 
$sql = “SELECT `user_email`, `user_url`
FROM $wpdb- > users
WHERE user_login = ‘admin’”;
$object = $wpdb- > get_row( $sql, OBJECT );
$array_a = $wpdb- > get_row( $sql, ARRAY_A );
 
$sql = “SELECT `user_email` FROM $wpdb- > users”;
$emails = $wpdb- > get_col( $sql );
 
$sql = “SELECT YEAR(post_date) AS `year`, count(ID) as posts
FROM $wpdb- > posts
WHERE post_type = ‘postAND post_status = ‘publishGROUP BY YEAR(post_date)
ORDER BY post_date DESC”;
$results = $wpdb- > get_results( $sql, ARRAY_A );
 
$sql = “SELECT YEAR(post_date) AS `year`, count(ID) as posts
FROM $wpdb- > posts
WHERE post_type = ‘postAND post_status = ‘publishGROUP BY YEAR(post_date)
ORDER BY post_date DESC”;
$results = $wpdb- > get_results( $sql, ARRAY_A );
foreach( $results as $sum ) {
$year = $sum[year];
$count = $sum[posts];
echo “ < p > Posts published in $year: $count < /p > ”;
}
 
$sql = “DELETE from wp_comments
WHERE comment_author_url
LIKE ‘%evil.example.com%’”;
$deleted = $wpdb- > query( $sql );
 
$sql = “UPDATE $wpdb- > posts
SET comment_status = ‘closedWHERE post_date < DATE_SUB( NOW(), INTERVAL 90 DAY )
AND post_status = ‘publish’”;
$wpdb- > query( $sql );

plugin Internationalizing JavaScript

WordPress provides a function called wp_localize_script() that enables you to pass translated text to an external fi le. You can then use the translated strings within your JavaScript

wp_localize_script( $handle, $object_name, $l10n );

Plugin will add two input buttons to the site ’ s footer. When either of the buttons is clicked, a translated message appears. The fi rst step is to create a new plugin folder called ssd - alert - box and place a new PHP fi le called ssd - alert - box.php in this folder. In the ssd - alert - box.php fi le, add your plugin information. Next, you need to load your translation using load_plugin_textdomain. At this point, you need to load your script using the wp_enqueue_script() function. After calling that function, you can localize your script using the wp_localize_script() function. Now you add a couple of fun input buttons to the footer of the site. Notice the use of the esc_attr__() function from earlier in the chapter to translate and escape the value attributes of the buttons. The last step - add a JavaScript fi le called ssd - alert - box - script.js to your plugin folder. After it ’ s created, you can add two functions for displaying the alert boxes on screen. Within the ssd - alert - box - script.js file , add the JavaScript

<?php
/**
 * Plugin Name: ssd Alert Box
 * Plugin URI: http://example.com
 * Description: A plugin example that places two input buttons in the blog footer that when clicked display an alert box.
 * Version: 0.1
 */
 
/* Add the translation function after the plugins loaded hook. */
add_action( 'plugins_loaded', 'ssd_alert_box_load_translation' );
 
/**
 * Loads a translation file if the paged being viewed isn't in the admin.
 *
 * @since 0.1
 */
function ssd_alert_box_load_translation() {
 
    /* If we're not in the admin, load any translation of our plugin. */
    if ( !is_admin() )
        load_plugin_textdomain( 'ssd-alert-box', false, 'ssd-alert-box/languages' );
}
 
/* Add our script function to the print scripts action. */
add_action( 'wp_print_scripts', 'ssd_alert_box_load_script' );
 
/**
 * Loads the alert box script and localizes text strings that need translation.
 *
 * @since 0.1
 */
function ssd_alert_box_load_script() {
 
    /* If we're in the WordPress admin, don't go any farther. */
    if ( is_admin() )
        return;
 
    /* Get script path and file name. */
    $script = trailingslashit( plugins_url( 'ssd-alert-box' ) ) . 'ssd-alert-box-script.js';
 
    /* Enqueue our script for use. */
    wp_enqueue_script( 'ssd-alert-box', $script, false, 0.1 );
 
    /* Localize text strings used in the JavaScript file. */
    wp_localize_script( 'ssd-alert-box', 'ssd_alert_box_L10n', array(
        'ssd_box_1' => __( 'Alert boxes are annoying!', 'ssd-alert-box' ),
        'ssd_box_2' => __( 'They are really annoying!', 'ssd-alert-box' ),
    ) );
}
 
/* Add our alert box buttons to the site footer. */
add_action( 'wp_footer', 'ssd_alert_box_display_buttons' );
 
/**
 * Displays two input buttons with a paragraph.  Each button has an onClick() event that loads
 * a JavaScript alert box.
 *
 * @since 0.1
 */
function ssd_alert_box_display_buttons() {
 
    /* Get the HTML for the first input button. */
    $ssd_alert_box_buttons = '<input type="button" onclick="ssd_show_alert_box_1()" value="' . esc_attr__( 'Press me!', 'ssd-alert-box' ) . '" />';
 
    /* Get the HTML for the second input button. */
    $ssd_alert_box_buttons .= '<input type="button" onclick="ssd_show_alert_box_2()" value="' . esc_attr__( 'Now press me!', 'ssd-alert-box' ) . '" />';
 
    /* Wrap the buttons in a paragraph tag. */
    echo '<p>' . $ssd_alert_box_buttons . '</p>';
}
 
?>
 
//Code snippet ssd - alert - box - script.js
/**
 * Displays an alert box with our first translated message when called.
 */
function ssd_show_alert_box_1() {
    alert( ssd_alert_box_L10n.ssd_box_1 );
}
 
/**
 * Displays an alert box with our second translated message when called.
 */
function ssd_show_alert_box_2() {
    alert( ssd_alert_box_L10n.ssd_box_2 );
}

When translators create translations of your plugin, they use your plugin ’ s POT fi le to create two fi les: ssd - alert - box - $locale.mo and ssd - alert - box - $locale.po. ssd - alert - box is the $domain parameter used in the translation functions throughout the plugin. $locale is a variable that represents the language and regional dialect. Using Poedit from the “ Translating Tools ” section, you can create a POT fi le. You need to input only a few pieces of information, and Poedit does the rest for you.

//lang/ssd-alert-box.pot
msgid ""
msgstr ""
"Project-Id-Version: Tricks localizing\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-06-28 23:34-0600\n"
"PO-Revision-Date: 2013-06-28 23:35-0600\n"
"Last-Translator: Serhii <>\n"
"Language-Team: Serhii\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-KeywordsList: _e;__;esc_attr_e;esc_attr__;esc_html_e;esc_html__;_x;_ex;esc_attr_x;esc_html_x;_n;_nx;_n_noop;_nx_noop\n"
"X-Poedit-Basepath: ../\n"
"X-Poedit-SearchPath-0: .\n"
 
#: tom-alert-box.php:48
msgid "Alert boxes are annoying!"
msgstr ""
 
#: tom-alert-box.php:49
msgid "They are really annoying!"
msgstr ""
 
#: tom-alert-box.php:65
msgid "Press me!"
msgstr ""
 
#: tom-alert-box.php:68
msgid "Now press me!"
msgstr ""

In this post u can learn first steps in coding widgets and integrate them in WP

  • ADDING MENUS AND SUBMENUS
  • CREATING WIDGETS
  • STYLES, ICONS, ...
//Creating a Top - Level Menu
add_menu_page( page_title, menu_title, capability, menu_slug, function, icon_url, position );
 
/*
Plugin Name: WordPress Menu Examples Plugin
Plugin URI: http://example.com/wordpress-plugins/my-plugin
Description: A plugin to create menus and submenus in WordPress
Version: 1.0
License: GPLv2
*/
 
add_action( 'admin_menu', 'ssd_menuexample_create_menu' );
 
function ssd_menuexample_create_menu() {
 
    //create custom top-level menu
    add_menu_page( 'My Plugin Settings Page', 'Menu Example Settings', 'manage_options', __FILE__, 'ssd_menuexample_settings_page', plugins_url( '/images/wp-icon.png', __FILE__ ) );
 
    //create submenu items
    add_submenu_page( __FILE__, 'About My Plugin', 'About', 'manage_options', __FILE__.'_about', ssd_menuexample_about_page );
    add_submenu_page( __FILE__, 'Help with My Plugin', 'Help', 'manage_options', __FILE__.'_help', ssd_menuexample_help_page );
    add_submenu_page( __FILE__, 'Uinstall My Plugin', 'Uninstall', 'manage_options', __FILE__.'_uninstall', ssd_menuexample_uninstall_page ); 
 
}
 
//Adding a Menu Item to an Existing Menu
add_options_page( page_title, menu_title, capability, menu_slug, function);
add_action( 'admin_menu', 'ssd_menuexample_create_menu' );
 
function ssd_menuexample_create_menu() {
 
    //create a submenu under Settings
    add_options_page( 'My Plugin Settings Page', 'Menu Example Settings', 'manage_options', __FILE__, 'ssd_menuexample_settings_page' );
 
}

CREATING WIDGETS

< ?php
class My_Widget extends WP_Widget {
function My_Widget() {
// processes the widget
}
function form($instance) {
// displays the widget form in the admin dashboard
}
function update($new_instance, $old_instance) {
// process widget options to save
}
function widget($args, $instance) {
// displays the widget
}
}

First, make a new array to store your widget options called $widget_ops . This array can hold the classname and description options. The classname option is the class name added to the < li > element of the widget. Sidebars, by default, display all widgets in an nordered list. Each individual widget is a list item in that list, so by adding a custom classname and ID , you can easily create custom styles and designs for your widget. After building your options array, you then pass those values to WP_Widget: ID for the list item of your widget, widget name displayed in the Widgets screen, array of options you set earlier.

//example
// use widgets_init action hook to e xecute custom function
<?php 
/*
Plugin Name: Widget Example Plugin
Plugin URI: http://example.com/wordpress-plugins/my-plugin
Description: A plugin to create widgets in WordPress
Version: 1.0
License: GPLv2
*/
 
// use widgets_init action hook to execute custom function
add_action( 'widgets_init', 'ssd_widgetexample_register_widgets' );
 
 //register our widget
function ssd_widgetexample_register_widgets() {
    register_widget( 'ssd_widgetexample_widget_my_info' );
}
 
//ssd_widget_my_info class
class ssd_widgetexample_widget_my_info extends WP_Widget {
 
    //process the new widget
    function ssd_widgetexample_widget_my_info() {
        $widget_ops = array( 
            'classname' => 'ssd_widgetexample_widget_class', 
            'description' => 'Display a user\'s favorite movie and song.' 
            ); 
        $this->WP_Widget( 'ssd_widgetexample_widget_my_info', 'My Info Widget', $widget_ops );
    }
 
     //build the widget settings form
/*First, you create a $defaults variable to set the default values of each option. In this example, you set only the default title to My Info. Next pull in the instance values; that is, the widget settings that have been saved. If this is a new widget and was just added to a sidebar, there won ’ t be any settings 
saved, so this value will be empty*/
    function form($instance) {
        $defaults = array( 'title' => 'My Info', 'movie' => '', 'song' => '' ); 
        $instance = wp_parse_args( (array) $instance, $defaults );
        $title = $instance['title'];
        $movie = $instance['movie'];
        $song = $instance['song'];
        ?>
            <p>Title: <input class="widefat" name="<?php echo $this->get_field_name( 'title' ); ?>"  type="text" value="<?php echo esc_attr( $title ); ?>" /></p>
            <p>Favorite Movie: <input class="widefat" name="<?php echo $this->get_field_name( 'movie' ); ?>"  type="text" value="<?php echo esc_attr( $movie ); ?>" /></p>
            <p>Favorite Song: <textarea class="widefat" name="<?php echo $this->get_field_name( 'song' ); ?>" / ><?php echo esc_attr( $song ); ?></textarea></p>
        <?php
    }
 
    //save the widget settings
    function update($new_instance, $old_instance) {
        $instance = $old_instance;
        $instance['title'] = strip_tags( $new_instance['title'] );
        $instance['movie'] = strip_tags( $new_instance['movie'] );
        $instance['song'] = strip_tags( $new_instance['song'] );
 
        return $instance;
    }
 
    //display the widget
    function widget($args, $instance) {
        extract($args);
 
        echo $before_widget;
        $title = apply_filters( 'widget_title', $instance['title'] );
        $movie = empty( $instance['movie'] ) ? '&nbsp;' : $instance['movie'];
        $song = empty( $instance['song'] ) ? '&nbsp;' : $instance['song']; 
 
        if ( !empty( $title ) ) { echo $before_title . $title . $after_title; };
        echo '<p>Fav Movie: ' . $movie . '</p>';
        echo '<p>Fav Song: ' . $song . '</p>';
        echo $after_widget;
    }
}
?>

Advanced Widget create a widget that retrieves an RSS feed and displays its results, also use different types of form elements for your widget options.

  • register your new widget
  • extend the WP_Widget class for new widget
  • create the widget options (form)
  • display the widget based on the set options -function widget($args, $instance)
// use widgets_init action hook to execute custom function
add_action( 'widgets_init', 'ssd_awe_register_widgets' );
 
//register our widget
function ssd_awe_register_widgets() {
    register_widget( 'ssd_awe_widget' );
}
 
//ssd_widget_my_info class
class ssd_awe_widget extends WP_Widget {
 
    //process the new widget
    function ssd_awe_widget() {
 
        $widget_ops = array( 
            'classname' => 'ssd_awe_widget_class', 
            'description' => 'Display an RSS feed with options.' 
            ); 
 
        $this->WP_Widget( 'ssd_awe_widget', 'Advanced RSS Widget', $widget_ops );
    }
 
     //build the widget settings form
    function form($instance) {
        $defaults = array( 
            'title' => 'RSS Feed', 
            'rss_feed' => 'http://strangework.com/feed', 
            'rss_items' => '2' 
        ); 
        $instance = wp_parse_args( (array) $instance, $defaults );
        $title = $instance['title'];
        $rss_feed = $instance['rss_feed'];
        $rss_items = $instance['rss_items'];
        $rss_date = $instance['rss_date'];
        $rss_summary = $instance['rss_summary'];
        ?>
            <p>Title: <input class="widefat" name="<?php echo $this->get_field_name( 'title' ); ?>"  type="text" value="<?php echo esc_attr( $title ); ?>" /></p>
            <p>RSS Feed: <input class="widefat" name="<?php echo $this->get_field_name( 'rss_feed' ); ?>"  type="text" value="<?php echo esc_attr( $rss_feed ); ?>" /></p>
            <p>Items to Display:
                <select name="<?php echo $this->get_field_name( 'rss_items' ); ?>">
                    <option value="1" <?php selected( $rss_items, 1 ); ?>>1</option>
                    <option value="2" <?php selected( $rss_items, 2 ); ?>>2</option>
                    <option value="3" <?php selected( $rss_items, 3 ); ?>>3</option>
                    <option value="4" <?php selected( $rss_items, 4 ); ?>>4</option>
                    <option value="5" <?php selected( $rss_items, 5 ); ?>>5</option>
                </select>
            </p>
            <p>Show Date?: <input name="<?php echo $this->get_field_name( 'rss_date' ); ?>"  type="checkbox" <?php checked( $rss_date, 'on' ); ?> /></p>
            <p>Show Summary?: <input name="<?php echo $this->get_field_name( 'rss_summary' ); ?>"  type="checkbox" <?php checked( $rss_summary, 'on' ); ?> /></p>
        <?php
    }
 
    //save the widget settings
    function update($new_instance, $old_instance) {
        $instance = $old_instance;
        $instance['title'] = strip_tags( $new_instance['title'] );
        $instance['rss_feed'] = strip_tags( $new_instance['rss_feed'] );
        $instance['rss_items'] = strip_tags( $new_instance['rss_items'] );
    $instance['rss_date'] = strip_tags( $new_instance['rss_date'] );
    $instance['rss_summary'] = strip_tags( $new_instance['rss_summary'] );
 
        return $instance;
    }
 
    //display the widget
    function widget($args, $instance) {
        extract($args);
 
        echo $before_widget;
 
        //load the widget settings
        $title = apply_filters( 'widget_title', $instance['title'] );
        $rss_feed = empty( $instance['rss_feed'] ) ? '' : $instance['rss_feed'];
        $rss_items = empty( $instance['rss_items'] ) ? 2 : $instance['rss_items'];
        $rss_date = empty( $instance['rss_date'] ) ? 0 : 1; 
        $rss_summary = empty( $instance['rss_summary'] ) ? 0 : 1; 
 
        if ( !empty( $title ) ) { echo $before_title . $title . $after_title; };
 
        if ( $rss_feed ) {
            //display the RSS feed
            wp_widget_rss_output( array(
                'url' => $rss_feed,
                'title' => $title,
                'items' => $rss_items,
                'show_summary' => $rss_summary,
                'show_author' => 0,
                'show_date' => $rss_date
            ) );
        }
 
        echo $after_widget;
    }
}

Creating Dashboard Widgets wp_add_dashboard_widget( widget_id, widget_name, callback, control_callback ); parameters:

  • widget_id — The CSS ID added to the widget DIV element
  • widget_name — The name displayed in heading
  • callback — Function to display your widget
  • control_callback — Function to be called to handle for elements and submission
add_action( 'wp_dashboard_setup', 'ssd_dashboard_example_widgets' );
 
function ssd_dashboard_example_widgets() {
 
    //create a custom dashboard widget
    wp_add_dashboard_widget( 'dashboard_custom_feed', 'My Plugin Information', 'ssd_dashboard_example_display' );
 
}
 
function ssd_dashboard_example_display()
{
    echo '<p>Please contact support@example.com to report bugs.</p>';    
}

Creating a Dashboard Widget with Options

<?php 
/*
Plugin Name: RSS Dashboard Widget Example Plugin
Plugin URI: http://example.com/wordpress-plugins/my-plugin
Description: A plugin to create dashboard widgets in WordPress
Version: 1.0
License: GPLv2
*/
 
add_action( 'wp_dashboard_setup', 'ssd_dashboard_example_widgets' );
 
function ssd_dashboard_example_widgets() {
 
    //create a custom dashboard widget
    wp_add_dashboard_widget( 'dashboard_custom_feed', 'My Plugin Information', 'ssd_dashboard_example_display', 'ssd_dashboard_example_setup' );
 
}
 
function ssd_dashboard_example_setup() {
 
    //check if option is set before saving
    if ( isset( $_POST['ssd_rss_feed'] ) ) {
        //retrieve the option value from the form
        $ssd_rss_feed = esc_url_raw( $_POST['ssd_rss_feed'] );
 
        //save the value as an option
        update_option( 'ssd_dashboard_widget_rss', $ssd_rss_feed );
    }
 
     //load the saved feed if it exists
    $ssd_rss_feed = get_option( 'ssd_dashboard_widget_rss ');
 
    ?>
    <label for="feed">
        RSS Feed URL: <input type="text" name="ssd_rss_feed" id="ssd_rss_feed" value="<?php echo esc_url( $ssd_rss_feed ); ?>" size="50" />
    </label>
    <?php
}
 
function ssd_dashboard_example_display()
{
    //load our widget option
    $ssd_option = get_option( 'ssd_dashboard_widget_rss ');
 
    //if option is empty set a default
    $ssd_rss_feed = ( $ssd_option ) ? $ssd_option : 'http://wordpress.org/news/feed/';
 
    //retireve the RSS feed and display it
    echo '<div class="rss-widget">';
 
    wp_widget_rss_output( array(
        'url' => $ssd_rss_feed,
        'title' => 'RSS Feed News',
        'items' => 2,
        'show_summary' => 1,
        'show_author' => 0,
        'show_date' => 1 
    ) );
 
    echo '</div>';    
}
?>

Adding a Custom Meta Box To create a custom meta box in WordPress, you use the add_meta_box() function. This function enables you to defi ne all aspects of your meta box. Following is how this function is used: < ?php add_meta_box( id, title, callback, page, context, priority, callback_args ); ? > Parameters:

  • id — The CSS ID added to the DIV element that wraps your meta box
  • title — The name of your meta box displayed in its heading
  • callback — Function to be called to display your meta box
  • page — The screen where your meta box should show
  • context — The part of the page where the meta box should be shown
  • priority — The priority in which your meta box should be shown
  • callback_args — Arguments to pass into your callback function
<?php 
/*
Plugin Name: Meta Box Example Plugin
Plugin URI: http://example.com/wordpress-plugins/my-plugin
Description: A plugin to create meta boxes in WordPress
Version: 1.0
License: GPLv2
*/
 
//hook to add a meta box
add_action( 'add_meta_boxes', 'ssd_mbe_create' );
 
function ssd_mbe_create() {
 
    //create a custom meta box
    add_meta_box( 'ssd-meta', 'My Custom Meta Box', 'ssd_mbe_function', 'post', 'normal', 'high' );
 
}
 
function ssd_mbe_function( $post ) {
 
    //retrieve the meta data values if they exist
    $ssd_mbe_name = get_post_meta( $post->ID, '_ssd_mbe_name', true );
    $ssd_mbe_costume = get_post_meta( $post->ID, '_ssd_mbe_costume', true );
 
    echo 'Please fill out the information below';
    ?>
    <p>Name: <input type="text" name="ssd_mbe_name" value="<?php echo esc_attr( $ssd_mbe_name ); ?>" /></p>
    <p>Costume: 
    <select name="ssd_mbe_costume">
        <option value="vampire" <?php selected( $ssd_mbe_costume, 'vampire' ); ?>>Vampire</option>
        <option value="zombie" <?php selected( $ssd_mbe_costume, 'zombie' ); ?>>Zombie</option>
        <option value="smurf" <?php selected( $ssd_mbe_costume, 'smurf' ); ?>>Smurf</option>
    </select>
    </p>
    <?php
}
 
//hook to save the meta box data
add_action( 'save_post', 'ssd_mbe_save_meta' );
 
function ssd_mbe_save_meta( $post_id ) {
 
    //verify the meta data is set
    if ( isset( $_POST['ssd_mbe_name'] ) ) {
 
        //save the meta data
        update_post_meta( $post_id, '_ssd_mbe_name', strip_tags( $_POST['ssd_mbe_name'] ) );
        update_post_meta( $post_id, '_ssd_mbe_costume', strip_tags( $_POST['ssd_mbe_costume'] ) );
 
    }
 
}
?>

WordPress features many different icons for each section head (the dashboard header icon is a house icon):

< div id=”icon-indexclass=”icon32> < /div >
< div id=”icon-editclass=”icon32> < /div >
< div id=”icon-uploadclass=”icon32> < /div >
< div id=”icon-link-managerclass=”icon32> < /div >
< div id=”icon-edit-pagesclass=”icon32> < /div >
< div id=”icon-edit-commentsclass=”icon32> < /div >
< div id=”icon-themesclass=”icon32> < /div >
< div id=”icon-pluginsclass=”icon32> < /div >
< div id=”icon-usersclass=”icon32> < /div >
< div id=”icon-toolsclass=”icon32> < /div >
< div id=”icon-options-generalclass=”icon32> < /div >

Messages

< ?php
function ssd_styling_settings() {
? >
< div class=”wrap” >
< h2 > My Plugin < /h2 >
< div id=”messageclass=”updated” > Settings saved successfully < /div >
< div id=”messageclass=”error” > Error saving settings < /div >
< /div >
< ?php
}
? >

Form Fields WordPress has a special table class just for forms called form - table. This class is used on all WordPress admin dashboard forms, including every Settings page. This is a useful class when creating any type of options in plugin.

A plugin in WordPress is a PHP script that extends or alters the core functionality of WordPress.

  • List of the main available APIs
  • ADVANTAGES OF PLUGINS
  • Commands: Paths, Activate/DE, Uninstall
  • Hooks

List of the main available APIs in WordPress:

  • Plugin — Provides a set of hooks that enable plugins access to specifi c parts of WordPress.
  • Widgets — Create and manage widgets in your plugin.
  • Shortcode — Adds shortcode support to your plugin. A shortcode is a simple hook that enables call a PHP function by adding something such as [shortcode] to a post or page.
  • HTTP — Sends HTTP requests from your plugin.
  • Settings — Inserts settings or a settings section for your plugin.
  • Options — Stores and retrieves options in your plugin
  • Dashboard Widgets — Creates admin dashboard widgets
  • Rewrite — Creates custom rewrite rules in your plugin
  • Transients — Creates temporary options (cached data) in your plugins
  • Database — Accesses the WordPress database

ADVANTAGES OF PLUGINS:

  • Not Modifying Core
  • Why Reinvent the Wheel
  • Separating Plugins and Themes
  • Easy Updates
  • Easier to Share and Reuse
  • Plugin Sandbox

Paths

plugin_dir_path( $file );
//$file - (string) (required) — The fi lename of a plugin
 
//determine the local path to your plugin folder
plugin_dir_path( __FILE__ );
 
plugins_url();// Full plugins directory URL
includes_url(); // Full includes directory URL
content_url(); // Full content directory URL (example.com/wp - content )
admin_url(); // Full admin URL
site_url(); // Site URL
home_url(); // Home URL
 
//examples
echo ' < img src=”' .plugins_url( 'images/icon.png' , __FILE__ ). '” > ';

ACTIVATE/DEACTIVATE FUNCTIONS & Uninstall

//Plugin Activation Function
register_activation_hook( __FILE__, 'ssd_myplugin_install' );
function ssd_myplugin_install() {
   If ( version_compare( get_bloginfo( 'version' ), '3.1', ' < ' ) ) {
deactivate_plugins( basename( __FILE__ ) ); // Deactivate our plugin
}
 
function ssd_install() {
$ssd_myplugin_options = array(
'view' = > 'grid',
'food' = > 'bacon',
'mode' = > 'zombie'
);
update_option( 'ssd_myplugin_options', $ssd_myplugin_options );
}
}
 
//Plugin Deactivation Function
register_deactivation_hook( __FILE__, 'ssd_myplugin_uninstall' );
function ssd_myplugin_uninstall() {
//do something
}
 
//Uninstall.php - preferred way
// If uninstall not called from WordPress exit
if( !defined( 'WP_UNINSTALL_PLUGIN' ) )
exit ();
// Delete option from options table
delete_option( 'ssd_myplugin_options' );
//remove any additional options and custom tables
 
/*If you delete a plugin in WordPress and
uninstall.php does not exist, WordPress executes the uninstall hook (if it exists).*/
register_activation_hook( __FILE__, 'ssd_myplugin_activate' );
function ssd_myplugin_activate() {
//register the uninstall function
register_uninstall_hook( __FILE__, 'ssd_myplugin_uninstaller' );
}
function ssd_myplugin_uninstaller() {
//delete any options, tables, etc the plugin created
delete_option( 'ssd_myplugin_options' );
}

Hooks Action hooks enable to fire a function at specific points in the WordPress loading process or when an event occurs. You need to understand the do_action() function. When hooking into WordPress, your plugin won ' t call this function directly; however, your plugin will almost always use it indirectly.

do_action( $tag, $arg = '' );
do_action('save_post', $post_ID, $post);
//That ' s where plugins come in. You develop custom functions (actions) that perform a specifi c task when the action hook is fi red.
add_action( $tag, $function, $priority, $accepted_args );
add_action( 'wp_footer', 'ssd_example_footer_message', 100 );
function ssd_example_footer_message() {
echo 'This site is built using < a href=”http://wordpress.org”
title=”WordPress publishing platform” > WordPress < /a > .';
}
 
//e xecutes this hook before loading
posts, enabling plugins to change how posts are queried
add_action( 'pre_get_posts', 'ssd_randomly_order_blog_posts' );
function ssd_randomly_order_blog_posts( $query ) {
if ( $query- > is_home & & empty( $query- > query_vars['suppress_filters'] ) )
$query- > set( 'orderby', 'rand' );
}
 
remove_action( $tag, $function_to_remove, $priority, $accepted_args );
remove_all_actions( 'wp_head' );
 
//if a hook has any actions added 
if ( has_action( 'wp_footer' ) )
echo ' < p > An action has been registered for the footer. < /p > ';
else
echo ' < p > An action hasn\'t been registered for the footer. < /p > ';
 
//enables check if an action hook e xecuted
if ( did_action( 'plugins_loaded' ) )
define( 'ssd_MYPLUGIN_READY', true );

Commonly Used Action Hooks

/*fi red after most of the WordPress fi les are loaded but before the pluggable functions and WordPress starts e xecuting anything*/
add_action( 'plugins_loaded', 'ssd_footer_message_plugin_setup' );
function ssd_footer_message_plugin_setup() {
/* Add the footer message action. */
add_action( 'wp_footer', 'ssd_example_footer_message', 100 );
}
function ssd_example_footer_message() {
echo 'This site is built using < a href=”http://wordpress.org”
title=”WordPress publishing platform” > WordPress < /a > .';
}
 
/*The init hook is fi red after most of WordPress is set up. Because nearly everything in WordPress is ready at this point, your plugin will probably use this hook for anything it needs to do when all the information from WordPress is available*/
add_action( 'init', 'ssd_add_excerpts_to_pages' );
function ssd_add_excerpts_to_pages() {
add_post_type_support( 'page', array( 'excerpt' ) );
}
 
//The admin_menu hook is called only when an administration page loads
add_action( 'admin_menu', 'ssd_admin_settings_page' );
function ssd_admin_settings_page() {
add_options_page(
'ssd Settings',
'ssd Settings',
'manage_options',
'ssd_admin_settings',
'ssd_admin_settings_page'
);
}
 
/*The template_redirect action hook is important because it ' s the point where WordPress knows which page a user is viewing, but before the theme template is chosen for the
particular page view. It is fi red only on the front end of the site and not in the administration area. This is a good hook to use when you need to load code only for specifi c page views.*/
add_action( 'template_redirect', 'ssd_singular_post_css' );
function ssd_singular_post_css() {
if ( is_singular( 'post' ) ) {
wp_enqueue_style(
'ssd-singular-post',
'ssd-example.css',
false,
0.1,
'screen'
);
}
}
 
/*wp_head - add HTML between the opening < head >and < /head >*/
add_action( 'wp_head', 'ssd_front_page_meta_description' );
function ssd_front_page_meta_description() {
/* Get the site description. */
$description = esc_attr( get_bloginfo( 'description' ) );
/* If a description is set, display the meta element. */
if ( !empty( $description ) )
echo ' < meta name=”description” content=”' . $description . '” / > ';
}

Filter hooks are much different than action hooks. They enable you to manipulate the output of code. Whereas action hooks enable you to insert code, fi lter hooks enable you to overwrite code that WordPress passes through the hook. Without a fi lter, fi lter hooks don ' t do anything. They exist so that plugin developers can change different variables.

add_filter( $tag, $function, $priority, $accepted_args );
apply_filters( 'wp_title', $title, $sep, $seplocation );
/*wp_title — The name of the hook.
$title — A string and the value that you want to fi lter and return back to WordPress
$sep — A string that tells you what the separator should be between elements in the 
< title > element
$seplocation — The location of the separator.*/
add_filter( 'wp_title', 'ssd_add_site_name_to_title', 10, 2 );
function ssd_add_site_name_to_title( $title, $sep ) {
/* Get the site name. */
$name = get_bloginfo( 'name' );
/* Append the name to the $title variable. */
$title .= $sep . ' ' . $name;
/* Return the title. */
return $title;
}
 
/*
apply_filters_ref_array() function works  same as apply_filters(), butit accepts an array of arguments.
*/
add_filter( 'posts_results', 'ssd_custom_home_page_posts' );
function ssd_custom_home_page_posts( $results ) {
global $wpdb, $wp_query;
/* Check if viewing the home page. */
if ( is_home() ) {
/* Posts per page. */
$per_page = get_option( 'posts_per_page' );
/* Get the current page. */
$paged = get_query_var( 'paged' );
/* Set the $page variable. */
$page = ( ( 0 == $paged || 1 == $paged ) ? 1 : absint( $paged ) );
/* Set the number of posts to offset. */
$offset = ( $page - 1 ) * $per_page . ', ';
/* Set the limit by the $offset and number of posts to show. */
$limits = 'LIMIT '. $offset . $per_page;
/* Get results from the database. */
$results = $wpdb- > get_results(S ELECT SQL_CALC_FOUND_ROWS $wpdb- > posts.*
FROM $wpdb- > posts
w h e r e post_type = 'page'
AND post_status = 'publish'
ORDER BY post_title ASC
$limits);
}
return $results;
}
 
remove_filter( $tag, $function_to_remove, $priority, $accepted_args );
remove_all_filters( $tag, $priority );
 
if ( has_filter( 'the_content' ) )
echo 'The content filter hook has at least one filter.';
else
echo 'The content filter hook has no filters.';
 
if ( has_filter( 'the_content', 'wpautop' ) )
echo 'Paragraphs are automatically formatted for the content.';
 
/*current_fi lter is especially useful if you use a single function for multiple hooks but need the function to e xecute differently depending on the hook currently fi ring*/
add_filter( 'the_content', 'ssd_replace_unwanted_words' );
add_filter( 'the_title', 'ssd_replace_unwanted_words' );
function ssd_replace_unwanted_words( $text ) {
/* If the_content is the filter hook, set its unwanted words. */
if ( 'the_content' == current_filter() )
$words = array( 'profanity', 'curse', 'devil' );
/* If the_title is the filter hook, set its unwanted words. */
elseif ( 'the_title' == current_filter() )
$words = array( 'profanity', 'curse' );
/* Replace unwanted words with “Whoops!” */
$text = str_replace( $words, 'Whoops!', $text );
/* Return the formatted text. */
return $text;
}
 
add_filter( 'the_content', 'ssd_add_related_posts_to_content' );
function ssd_add_related_posts_to_content( $content ) {
/* If not viewing a singular post, just return the content. */
if ( !is_singular( 'post' ) )
return $content;
/* Get the categories of current post. */
$terms = get_the_terms( get_the_ID(), 'category' );
/* Loop through the categories and put their IDs in an array. */
$categories = array();
foreach ( $terms as $term )
$categories[] = $term- > term_id;
/* Query posts with the same categories from the database. */
$loop = new WP_Query(
array(
'cat__in' = > $categories,
'posts_per_page' = > 5,
'post__not_in' = > array( get_the_ID() ),
'orderby' = > 'rand'
)
);
/* Check if any related posts exist. */
if ( $loop- > have_posts() ) {
/* Open the unordered list. */
$content .= ' < ul class=”related-posts” > ';
while ( $loop- > have_posts() ) {
$loop- > the_post();
/* Add the post title with a link to the post. */
$content .= the_title(
' < li > < a href=”' . get_permalink() . '” > ',
' < /a > < /li > ',
false
);
}
/* Close the unordered list. */
$content .= ' < /ul > ';
/* Reset the query. */
wp_reset_query();
}
/* Return the content. */
return $content;
}
 
add_filter( 'the_title', 'ssd_strip_tags_from_titles' );
function ssd_strip_tags_from_titles( $title ) {
$title = strip_tags( $title );
return $title;
}
 
add_filter( 'comment_text', 'ssd_add_role_to_comment_text' );
function ssd_add_role_to_comment_text( $text ) {
global $comment;
/* Check if comment was made by a registered user. */
if ( $comment- > user_id > 0 ) {
/* Create new user object. */
$user = new WP_User( $comment- > user_id );
/* If user has a role, add it to the comment text. */
if ( is_array( $user- > roles ) )
$text .= ' < p > User Role: ' . $user- > roles[0] . ' < /p > ';
}
return $text;
}
 
//USING HOOKS FROM WITHIN A CLASS
class ssd_My_Plugin_Loader {
/* Constructor method for the class. */
function ssd_My_Plugin_Loader() {
/* Add the 'singular_check' method to the 'template_redirect' hook. */
add_action( 'template_redirect', array( & $this, 'singular_check' ) );
}
/* Method used as an action. */
function singular_check() {
/* If viewing a singular post, filter the content. */
if ( is_singular() )
add_filter( 'the_content', array( & $this, 'content' ) );
}
/* Method used as a filter. */
function content( $content ) {
/* Get the date the post was last modified. */
$date = get_the_modified_time( get_option( 'date_format' ) );
/* Append the post modified date to the content. */
$content .= ' < p > Post last modified: ' . $date . ' < /p > ';
/* Return the content. */
return $content;
}
}
$ssd_myplugin_loader = new ssd_My_Plugin_Loader();

Examples of transactions

//AR and rollback of transactions
public function actionCreate()
    {
        /** @var BaseActiveRecord $model */
        $model = new $this->modelClass('create');
 
        $this->performAjaxValidation($model);
 
        $model->attributes = Yii::app()->request->getParam($this->modelClass, array());
 
        if (Yii::app()->request->isPostRequest && !Yii::app()->request->isAjaxRequest) {
            $transaction = $model->getDbConnection()->beginTransaction();
            try {
                $model->save();
                $transaction->commit();
                $url = array('update', 'id' => $model->primaryKey);
                $this->redirect($url);
            } catch (Exception $e) {
                $transaction->rollback();
            }
        }
 
        $this->render('create', array('model' => $model));
    }
 
public function actionCreate()
    {
        /** @var BaseActiveRecord $model */
        $model = new $this->modelClass('create');
 
        $this->performAjaxValidation($model);
 
        $model->attributes = Yii::app()->request->getParam($this->modelClass, array());
 
        if (Yii::app()->request->isPostRequest && !Yii::app()->request->isAjaxRequest) {
            $transaction = $model->getDbConnection()->beginTransaction();
 
            // Сохраняем состояние объекта
            $transaction->storeModelStateForRollback($model);
 
            try {
                $model->save();
                $transaction->commit();
                $url = array('update', 'id' => $model->primaryKey);
                $this->redirect($url);
            } catch (Exception $e) {
                $transaction->rollback();
            }
        }
 
        $this->render('create', array('model' => $model));
    }
 
// check if transaction started
if(($transaction=$connection->getCurrentTransaction())===null)
   $transaction=$connection->beginTransaction();
try
{
   $connection->createCommand($sql1)->e xecute();
   $connection->createCommand($sql2)->e xecute();
   //.... other SQL executions
   $transaction->commit();
}
catch(Exception $e)
{
   $transaction->rollBack();
}

Yii DAO consists: CDbConnection, CDbCommand, CDbDataReader and CDbTransaction. Post of examples

$connection=new CDbConnection($dsn,$username,$password);
$connection->active=true;
$connection->active=false;  // close connection
 
to use, configure in a db app component in the app config
 
array(
    ......
    'components'=>array(
        ......
        'db'=>array(
            'class'=>'CDbConnection',
            'connectionString'=>'mysql:host=localhost;dbname=testdb',
            'username'=>'root',
            'password'=>'password',
            'emulatePrepare'=>true,  // needed by some MySQL installations
        ),
    ),
)
 
//if done can use as
$connection=Yii::app()->db;
$command=$connection->createCommand($sql);
 
//if INSERT, UPDATE and DELETE
$rowCount=$command->e xecute();
 
//if SELECT   
$dataReader=$command->query(); 
// if return all rows of result  
$rows=$command->queryAll();      
 
 
// go through every row of data
foreach($dataReader as $row) { ... }
// get all in a single array
$rows=$dataReader->readAll();
 
//4th part of DAO - transaction
$transaction = $connection->beginTransaction();
try
{
    $connection->createCommand($sql1)->e xecute();// etc
    $transaction->commit();
}
catch(Exception $e) // an exception is raised if a query fails
{
    $transaction->rollback();
}
//Binding Parameters
$sql="INSERT INTO user (username, email) VALUES(:username,:email)";
$command=$connection->createCommand($sql);
$command->bindParam(":username",$username,PDO::PARAM_STR);
$command->bindParam(":email",$email,PDO::PARAM_STR);
$command->e xecute();
// possible for Binding Columns
 
//create query builder and e xecute with DAO
$user = Yii::app()->db->createCommand()
    ->select('id, username, profile')
    ->from('user u')
    ->join('profile p', 'u.id=p.user_id')
    ->where('id=:id', array(':id'=>$id))
    ->queryRow();
 
// using CDbCriteria with DAO, no AR used
$criteria = new CDbCriteria;//config then
$builder = new CDbCommandBuilder(Yii::app()->db->gets chema());
//use table name and criteria
$command = $builder->createFindCommand('product', $criteria); 
$productIds = $command->queryAll();
 
//CArrayDataProvider implements a data provider based on a raw data array
$rawData=Yii::app()->db->createCommand('SELECT * FROM tbl_user')->queryAll();
// or using: $rawData=User::model()->findAll();
$dataProvider=new CArrayDataProvider($rawData, array(
    'id'=>'user',
    'sort'=>array(
        'attributes'=>array(
             'id', 'username', 'email',
        ),
    ),
    'pagination'=>array(
        'pageSize'=>10,
    ),
));
// $dataProvider->getData() will return a list of arrays.
 
//LEFT JOIN DAO
$criteria=new CDbCriteria(array(
'select'=>'*',
'distinct'=>true,
'alias'=>'c',
'join'=>'left join category_description cs ON c.category_id=cd.category.id',
'condition'=>'c.category_id=:category and cd.site_id=:site',
'params'=>array(
':category'=>(int)$category_id,
':site'=>(int)$site_id,
),
));
$dataReader=Yii::app()->db->commandBuilder->createFindCommand('category',$criteria)->query();
foreach($dataReader as $row)
{
//обработка результата
}

Yeeh, it's IT blog, but... being activist is fun! This post will make u smile or laugh if u know what's policy or civic activity is. I'm in human rights movement for a couple of years and all of the feelings from the pix I know very well... Enjoy! #4, 5, 6 and last one made my day! It's awesome)

When you meet someone who gets just as worked up about an issue as you - marry me!

When you meet someone who gets just as worked up about an issue as you - marry me!

When people think they know all about an issue because they saw a movie or read in FB

When people think they know all about an issue because they saw a movie or read in FB

When a friend suggests you go to McDonalds or Wal-mart - I wish I could... but I don't want to)))

When a friend suggests you go to McDonalds or Wal-mart

An hour ago u were dead (exhausted), but when you are about to go street campaigning

An hour ago u were dead (exhausted), but when you are about to go street campaigning

Forget first 10 minutes - they are rude... But how you feel after 30 minutes of street campaigning

Forget first 10 minutes - they are rude... But how you feel after 30 minutes of street campaigning

How you feel after a day of street campaigning

How you feel after a day of street campaigning

When your someone says something you really disagree with… but you don’t want to argue

When your someone says something you really disagree with… but you don’t want to argue

All the time people assume you are vegan or a non-drinker

All the time people assume you are vegan or a non-drinker

When a well-meaning person or the one u respect tries to give you money instead of signing your petition

When a well-meaning person or the one u respect tries to give you money instead of signing your petition

Ready to go and kill in the streets when got a standard reply to that detailed and well-researched email (query) you sent

Ready to go and kill in the streets when got a standard reply to that detailed and well-researched email (query) you sent

The moment you get a lobby meeting agreed

The moment you get a lobby meeting agreed

Just before your lobby meeting

Just before your lobby meeting

When your campaign target says they agree with you. Works for family as well

When your campaign target says they agree with you. Works for family as well

When u get a 1000 likes or someone famous re-tweets you

When u get a 1000 likes or someone famous re-tweets you

When people tell you to chill out about the thing you’re campaigning on

When people tell you to chill out about the thing you’re campaigning on

When that drunk person at a party is determined to argue with you all night (or relatives)

When that drunk person at a party is determined to argue with you all night (or relatives)

When best newsmaker of your state wants to write your story or make a movie about YOUR issue

When best newsmaker of your state wants to write your story or make a movie about YOUR issue

When people tell you there’s no point, things will never change

When people tell you there’s no point, things will never change

When you win a campaign. This moment gives a lot. U'll remember that for all of your life... Not graduating, marriage or vocation)))

When you win a campaign. This moment gives a lot. U'll remember that for all of your life... Not graduating, marriage or vocation)))

Pix from http://www.one.org/


Go to page: