Posts Issued in August, 2014

Тестовое задание на разработку Плагина новостей:

  • создать программно post type newspages;
  • создать собственный список новостей (список постов post type newspages) в админ части;
  • возможность сортировать список по полям в хедере (title, date);
  • удаление, редактирование новостей;
  • добавить новые поля: комментарий админа (textarea) и альтернативный тайтл (input);
  • сделать виждет с 3 последними новостями ;
  • написать shortcode с последними 3 новостями ;
  • все исходники плагина

Скачать ZIP архив плагина (версия 0.5)

Плагин установлен в моем бложике - см здесь

Решаем задачу редактированием файла темы functions.php и копированием файлов single.php & archive.php.

// custom function to register a "story" post type
function ssd_register_post_type_story() {
    register_post_type( 'story',
        array(
            'labels' => array(
                'name' => __( 'Story' ),
                'singular_name' => __( 'Story' )
            ),
        'public' => true,
        'has_archive' => true,
        )
    );
}
// call our custom function with the init hook
add_action( 'init', 'ssd_register_post_type_story' );

В админке появился тип контента, с вкладками добавить и список, на последней возможно сортировка по дате и названию. В админке появились пункты "Редагувати | Швидке Редагування | Сміття | Переглянути". ИТОГО - 4 пункта выполнено.

Пункт "добавить новые поля" - Metadata в CPT. Попытка №1:

// use the add_meta_boxes hook to call a custom function to add a new meta box
add_action( 'add_meta_boxes', 'ssd_story_add_meta_boxes' );
 
// this is the callback function called from add_meta_box
function ssd_story_add_meta_boxes( $post ){
 
    // set meta data if already exists
    $admin_comment = get_post_meta( $post->ID, 
        '_ssd_story_admin_comment', "No comment" );
 
    $alt_title = get_post_meta( $post->ID, 
        '_ssd_story_alt_title', "No title" );
    // output meta data fields
    if ( $post != "story" ) return;
    ?>
    <p>
    Input admin comment
    <input type="text" name="admin_comment" value="<?php echo $admin_comment;?>">
    </p>
    <p>
    Alt title:
    <input type="text" name="alt_title" id="alt_title" value="<?php echo $alt_title;?>">
    </p>
 
    <?php
}
 
// function for saving custom meta data to the database
function ssd_story_save_post( $post_id ){
 
  // don't save anything if WP is auto saving
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) 
      return $post_id;
 
  // check if correct post type and that the user has correct permissions
  if ( 'story' == $_POST['post_type'] ) {
 
    if ( ! current_user_can( 'edit_page', $post_id ) )
        return $post_id;
 
  } else {
 
    if ( ! current_user_can( 'edit_post', $post_id ) )
        return $post_id;
  }
 
  // update story meta data
  update_post_meta( $post_id, 
      '_ssd_story_admin_comment', 
      $_POST['admin_comment'] 
  );
  update_post_meta( $post_id, 
      '_ssd_story_alt_title', 
      $_POST['alt_title'] 
  );
 
}
// call a custom function to handle saving our meta data
add_action( 'save_post', 'ssd_story_save_post' );

Попытка закончилась успешно, но с версткой возникли прогнозируемые трудности, но ведь в таске нет ни слова о божеском виде ;)

Переходим к пункту сделать "виждет с 3 последними новостями". Стандартная задача, вопрос только - какую информацию выводтиь в виджет? Решил название и дату публикации. Исходник виджета, проверен в бложике ;)

<?php
/*
        Plugin Name: Show Recent CPTs
        Tags: menu, CPT, widget
        Description: Creates menus from Wordpress recent custom post type
        Author: Serhii Dymenko
        Version: 1.1.0
        Author URI: http://www.proserge.kh.ua
*/
 
class Recent_CPT extends WP_Widget 
{
function __construct() {
    parent::__construct(
        'recent_CPT', // Base ID
        'Recent News', // Name
        array('description' => __( 'Displays your latest news. Outputs the post thumbnail, title and date per listing'))
       );
}
function update($new_instance, $old_instance) {
        $instance = $old_instance;
        $instance['title'] = strip_tags($new_instance['title']);
        $instance['numberOfListings'] = strip_tags($new_instance['numberOfListings']);
        return $instance;
}
 
/*The method form() builds the form that we have in the admin section. 
What we’re building is a very simple form with 2 fields: a text field 
for the Widget title, and a drop down list for the number of listings 
we want to show:*/
 
function form($instance) {
    if( $instance) {
        $title = esc_attr($instance['title']);
        $numberOfListings = esc_attr($instance['numberOfListings']);
    } else {
        $title = '';
        $numberOfListings = '';
    }
    ?>
        <p>
        <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title', 'recent_CPT'); ?></label>
        <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" />
        </p>
        <p>
        <label for="<?php echo $this->get_field_id('numberOfListings'); ?>"><?php _e('Number of Listings:', 'recent_CPT'); ?></label>        
        <select id="<?php echo $this->get_field_id('numberOfListings'); ?>"  name="<?php echo $this->get_field_name('numberOfListings'); ?>">
            <?php for($x=1;$x<=10;$x++): ?>
            <option <?php echo $x == $numberOfListings ? 'selected="selected"' : '';?> value="<?php echo $x;?>"><?php echo $x; ?></option>
            <?php endfor;?>
        </select>
        </p>         
    <?php
    } 
 
 
function widget($args, $instance) { 
    extract( $args );
    $title = apply_filters('widget_title', $instance['title']);
    $numberOfListings = $instance['numberOfListings'];
    echo $before_widget;
    if ( $title ) {
        echo $before_title . $title . $after_title;
    }
    $this->getNewsListings($numberOfListings);
    echo $after_widget;
}
 
function getNewsListings($numberOfListings) { //html
    global $post;
    add_image_size( 'news_widget_size', 85, 45, false );
    $listings = new WP_Query();
    $listings->query('post_type=story&posts_per_page=' . $numberOfListings );    
    if($listings->found_posts > 0) {
        echo '<ul class="story_widget">';
            while ($listings->have_posts()) {
                $listings->the_post();
                $image = (has_post_thumbnail($post->ID)) ? get_the_post_thumbnail($post->ID, 'news_widget_size') : '<div class="noThumb"></div>'; 
                $listItem = '<li>' . $image; 
                $listItem .= '<a href="' . get_permalink() . '">';
                $listItem .= get_the_title() . '</a>';
                $listItem .= '<span>Added ' . get_the_date() . '</span></li>'; 
                echo $listItem; 
            }
        echo '</ul>';
        wp_reset_postdata(); 
    }else{
        echo '<p style="padding:25px;">No News found</p>';
    } 
}
 
function styleRecentNews() {
wp_register_style('ssd_recent_news_css', plugins_url('recent_news.css',__FILE__ ));
wp_enqueue_style('ssd_recent_news_css');
}
 
 
 
} //end class Realty_Widget
 
 
function register_recent_CPT_widget() {
register_widget('Recent_CPT');
}
 
add_action('widgets_init', 'register_recent_CPT_widget');

Таск "написать shortcode с последними 3 новостями". Ну, рискну переписать function widget в функцию для вывода шорткода. Протестим, загнав в functions.php - РАБОТАЕТ!!!

////////-----------------------------   SHORTCODE ----------------------
// Register a new shortcode: [ssd_recent]
add_shortcode( 'ssd_recent', 'ssd_recent_story_newes' );
 
// The callback function that will replace [ssd_recent]
function ssd_recent_story_newes() {
    global $post;
    $blockRecent = "<div class=\"recentShort\">";
    add_image_size( 'news_widget_size', 85, 45, false );
    $listings = new WP_Query();
    $listings->query('post_type=story&posts_per_page=3');    
    if($listings->found_posts > 0) {
        $blockRecent .= "<ul class=\"story_widget\">";
            while ($listings->have_posts()) {
                $listings->the_post();
                $image = (has_post_thumbnail($post->ID)) ? get_the_post_thumbnail($post->ID, 'news_widget_size') : '<div class="noThumb"></div>'; 
                $listItem = "<li>" . $image; 
                $listItem .= "<a href=\"get_permalink()\">";
                $listItem .= get_the_title() . "</a></br>";
                $listItem .= "<span>Added  get_the_date() </span></li>"; 
                $blockRecent .= $listItem;
                //DebugBreak(); 
            }
        $blockRecent .= "</ul>";
        wp_reset_postdata(); 
    }else{
        $blockRecent .= "<p style=\"padding:25px;\">No News found</p>";
    }
    $blockRecent .= "</div>";
    return $blockRecent;
}

Теперь осталось собрать Плагин новостей из функций и виджета, подчистить functions.php и файлы темы (single.php & archive.php). Радует, что по отдельности все работает ;)

Конечный вариант плагина (исходники всех файлов: story.php, admin.php, functions.php, meta.php, post-types.php, widget3news.php, uninstall.php, readme.txt):

//story.php 
<?php
/**
 * Plugin Name: Custom Content Newspage
 * Plugin URI: http://proserge.kh.ua/coding/index.php/post/85/WP+News+Plugin
 * Description: newspage manager for WordPress.  This plugin allows you to manage, edit, and create new newspage items in an unlimited number of newspages.
 * Version: 0.4
 * Author: Serhii Dymenko
 * Author URI: http://proserge.kh.ua/coding/
 *
 * plugin was created because of the need of users who are using WordPress with newspage management built in, which causes problems with content portability. I did my best for give users possibility to switch themes without losing content.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.
 *
 * @package   CustomContentNewspage
 * @version   0.5.0
 * @copyright Copyright (c) 2014, Serhii Dymenko
 * @link      http://proserge.kh.ua/coding/index.php/post/85/WP+News+Plugin
 * @license   http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 */
 
class Custom_Content_Newspage {
 
    public function __construct() {
 
        /* Set the constants needed by the plugin. */
        add_action( 'plugins_loaded', array( &$this, 'constants' ), 1 );
 
        /* Load the functions files. */
        add_action( 'plugins_loaded', array( &$this, 'includes' ), 2 );
 
        /* Load the admin files. */
        add_action( 'plugins_loaded', array( &$this, 'admin' ), 3 );
 
        /* Register activation hook. */
        register_activation_hook( __FILE__, array( &$this, 'activation' ) );
    }
 
    /**
     * Defines constants used by the plugin.
     */
    public function constants() {
 
        /* Set constant path to the plugin directory. */
        define( 'SSD_DIR', trailingslashit( plugin_dir_path( __FILE__ ) ) );
 
        /* Set the constant path to the plugin directory URI. */
        define( 'SSD_URI', trailingslashit( plugin_dir_url( __FILE__ ) ) );
 
        /* Set the constant path to the includes directory. */
        define( 'SSD_INCLUDES', SSD_DIR . trailingslashit( 'includes' ) );
 
        /* Set the constant path to the admin directory. */
        define( 'SSD_ADMIN', SSD_DIR . trailingslashit( 'admin' ) );
    }
 
    /**
     * Loads the initial files needed by the plugin.
     */
    public function includes() {
 
        require_once( SSD_INCLUDES . 'functions.php' );
        require_once( SSD_INCLUDES . 'meta.php' );
        require_once( SSD_INCLUDES . 'post-types.php' );
        require_once( SSD_INCLUDES . 'widget3news.php' );
    }
 
    public function i18n() {}
 
    /**
     * Loads the admin functions and files.
     */
    public function admin() {
 
        if ( is_admin() )
            require_once( SSD_ADMIN . 'admin.php' );
    }
 
    /**
     * Method that runs only when the plugin is activated.
     */
    function activation() {
 
        /* Get the administrator role. */
        $role =& get_role( 'administrator' );
 
        /* If exists, add capabilities. */
        if ( !empty( $role ) ) {
 
            $role->add_cap( 'manage_newspage' );
            $role->add_cap( 'create_newspage_items' );
            $role->add_cap( 'edit_newspage_items' );
        }
    }
}
 
new Custom_Content_Newspage();
 
?>
 
//admin.php
<?php
/**
 * Admin functions for the plugin.
 *
 * @package    CustomContentNewspage
 * @subpackage Admin
 * @since      0.5.0
 * @copyright Copyright (c) 2014, Serhii Dymenko
 * @link      http://proserge.kh.ua/coding/index.php/post/85/WP+News+Plugin
 * @license    http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 */
 
/* Set up the admin functionality. */
add_action( 'admin_menu', 'ssd_admin_setup' );
 
/**
 * Adds actions where needed for setting up the plugin's admin functionality.
 */
function ssd_admin_setup() {
 
    /* Custom columns on the edit newspage items screen. */
    add_action( 'manage_newspage_item_posts_custom_column', 'ssd_manage_newspage_item_columns', 10, 2 );
 
    /* Add meta boxes an save metadata. */
    add_action( 'add_meta_boxes', 'ssd_add_meta_boxes' );
    add_action( 'save_post', 'ssd_newspage_item_info_meta_box_save', 10, 2 );
 
    /* Add 32px screen icon. */
    add_action( 'admin_head', 'ssd_admin_head_style' );
}
 
/**
 * Sets up custom columns on the newspage items edit screen.
 */
function ssd_edit_newspage_item_columns( $columns ) {
}
 
/**
 * Displays the content of custom newspage item columns on the edit screen.
 */
function ssd_manage_newspage_item_columns( $column, $post_id ) {
    global $post;
 
    switch( $column ) {
 
        case 'thumbnail' :
 
            if ( has_post_thumbnail() )
                the_post_thumbnail( array( 40, 40 ) );
 
            elseif ( function_exists( 'get_the_image' ) )
                get_the_image( array( 'image_scan' => true, 'width' => 40, 'height' => 40 ) );
 
            break;
 
        /* Just break out of the switch statement for everything else. */
        default :
            break;
    }
}
 
/**
 * Registers new meta boxes for the 'newspage_item' post editing screen in the admin.
 */
function ssd_add_meta_boxes( $post_type ) {
 
    if ( 'newspage_item' === $post_type ) {
 
        add_meta_box( 
            'ssd-admin-comment', 
            __( 'Admin Comment', 'custom-content-newspage' ), 
            'ssd_newspage_meta_comment_display', 
            $post_type, 
            'normal', 
            'core'
        );
 
        add_meta_box( 
            'ssd-alt-title', 
            __( 'Alt Title', 'custom-content-newspage' ), 
            'ssd_newspage_meta_title_display', 
            $post_type, 
            'normal', 
            'core'
        );
    }
}
 
/**
 * Displays the content of the newspage item info meta box.
 */
function ssd_newspage_meta_comment_display( $post, $metabox ) {
 
    wp_nonce_field( basename( __FILE__ ), 'ssd-newspage-item-info-nonce' ); ?>
 
    <p>
        <label for="ssd-admin-comment"><?php _e( 'Input admin comment <abbr title="Uniform Resource Locator">URL</abbr>', 'ssd-admin-cooment' ); ?></label>
        <br />
        <textarea rows="5" cols="50" name="ssd-admin-comment" style="width: 99%;"><?php echo get_post_meta( $post->ID, 'ssd-admin-comment')[0];?></textarea>
    </p>
    <?php
 
}
 
function ssd_newspage_meta_title_display( $post, $metabox ) {
 
    wp_nonce_field( basename( __FILE__ ), 'ssd-newspage-item-info-nonce' ); ?>
 
    <p>
        <label for="ssd-alt-title"><?php _e( 'Input alt title <abbr title="Uniform Resource Locator">URL</abbr>', 'ssd-alt-title' ); ?></label>
        <br />
        <input type="text" name="ssd-alt-title" id="ssd-alt-title" value="<?php echo get_post_meta( $post->ID, 'ssd-alt-title')[0]; ?>" size="30" tabindex="30" style="width: 99%;" />
    </p>
    <?php
 
}
/**
 * Saves the metadata for the newspage item info meta box.
 */
function ssd_newspage_item_info_meta_box_save( $post_id, $post ) {
 
    if ( !isset( $_POST['ssd-newspage-item-info-nonce'] ) || !wp_verify_nonce( $_POST['ssd-newspage-item-info-nonce'], basename( __FILE__ ) ) )
        return;
 
    $meta = array(
        'ssd-admin-comment' => $_POST['ssd-admin-comment'] ,
        'ssd-alt-title' => $_POST['ssd-alt-title']
    );
 
    foreach ( $meta as $meta_key => $new_meta_value ) {
 
        /* Get the meta value of the custom field key. */
 
        $meta_value = get_post_meta( $post_id, $meta_key, true );
 
        /* If there is no new meta value but an old value exists, delete it. */
        if ( current_user_can( 'delete_post_meta', $post_id, $meta_key ) && '' == $new_meta_value && $meta_value )
            delete_post_meta( $post_id, $meta_key, $meta_value );
 
        /* If a new meta value was added and there was no previous value, add it. */
        elseif ( current_user_can( 'add_post_meta', $post_id, $meta_key ) && $new_meta_value && '' == $meta_value )
            add_post_meta( $post_id, $meta_key, $new_meta_value, true );
 
        /* If the new meta value does not match the old value, update it. */
        elseif ( current_user_can( 'edit_post_meta', $post_id, $meta_key ) && $new_meta_value && $new_meta_value != $meta_value )
 
            update_post_meta( $post_id, $meta_key, $new_meta_value );
    }
}
 
/**
 * Adds plugin settings.  At the moment, this function isn't being used because we're waiting for a bug fix
 * in core.  For more information, see: http://core.trac.wordpress.org/ticket/9296
 */
function ssd_plugin_settings() {
 
    /* Register settings for the 'permalink' screen in the admin. */
    register_setting(
        'permalink',
        'plugin_custom_content_newspage',
        'ssd_validate_settings'
    );
 
    /* Adds a new settings section to the 'permalink' screen. */
    add_settings_section(
        'ssd-permalink',
        __( 'Newspage Settings', 'custom-content-newspage' ),
        'ssd_permalink_section',
        'permalink'
    );
 
    /* Get the plugin settings. */
    $settings = get_option( 'plugin_ssd', ssd_get_default_settings() );
 
    add_settings_field(
        'ssd-root',
        __( 'Newspage Archive', 'custom-content-newspage' ),
        'ssd_root_field',
        'permalink',
        'ssd-permalink',
        $settings
    );
 
    add_settings_field(
        'ssd-item-base',
        __( 'newspage item slug', 'custom-content-newspage' ),
        'ssd_item_base_field',
        'permalink',
        'ssd-permalink',
        $settings
    );
}
 
/**
 * Validates the plugin settings.
 */
function ssd_validate_settings( $settings ) {
 
    // @todo Sanitize for alphanumeric characters
    // @todo Both the newspage_base and newspage_item_base can't match.
 
    $settings['newspage_base'] = $settings['newspage_base'];
 
    $settings['newspage_item_base'] = $settings['newspage_item_base'];
 
    $settings['newspage_root'] = !empty( $settings['newspage_root'] ) ? $settings['newspage_root'] : 'newspage';
 
    return $settings;
}
 
/**
 * Adds the newspage permalink section.
 */
function ssd_permalink_section() { ?>
    <table class="form-table">
        <?php do_settings_fields( 'permalink', 'custom-content-newspage' ); ?>
    </table>
<?php }
 
/**
 * Adds the newspage root settings field.
 */
function ssd_root_field( $settings ) { ?>
    <input type="text" name="plugin_ssd[newspage_root]" id="ssd-newspage-root" class="regular-text code" value="<?php echo esc_attr( $settings['newspage_root'] ); ?>" />
    <code><?php echo home_url( $settings['newspage_root'] ); ?></code> 
<?php }
 
/**
 * Adds the newspage (taxonomy) base settings field.
 */
function ssd_base_field( $settings ) { ?>
    <input type="text" name="plugin_ssd[newspage_base]" id="ssd-newspage-base" class="regular-text code" value="<?php echo esc_attr( $settings['newspage_base'] ); ?>" />
    <code><?php echo trailingslashit( home_url( "{$settings['newspage_root']}/{$settings['newspage_base']}" ) ); ?></code> 
<?php }
 
/**
 * Adds the newspage item (post type) base settings field.
 */
function ssd_item_base_field( $settings ) { ?>
    <input type="text" name="plugin_ssd[newspage_item_base]" id="ssd-newspage-item-base" class="regular-text code" value="<?php echo esc_attr( $settings['newspage_item_base'] ); ?>" />
    <code><?php echo trailingslashit( home_url( "{$settings['newspage_root']}/{$settings['newspage_item_base']}" ) ); ?>%postname%</code> 
<?php }
 
/**
 * Overwrites the screen icon for newspage screens in the admin.
 */
function ssd_admin_head_style() {
        global $post_type;
 
    if ( 'newspage_item' === $post_type ) { ?>
        <style type="text/css">
            #icon-edit.icon32-posts-newspage_item {
                background: transparent url( '<?php echo ssd_URI . 'images/screen-icon.png'; ?>' ) no-repeat;
            }
        </style>
    <?php }
}
 
?>
 
//functions.php
<?php
/**
 * Various functions, filters, and actions used by the plugin.
 *
 * @package    CustomContentNewspage
 * @subpackage Includes
 * @since      0.4.0
 * @copyright Copyright (c) 2014, Serhii Dymenko
 * @link      http://proserge.kh.ua/coding/index.php/post/85/WP+News+Plugin
 
/* Filter the post type archive title. */
add_filter( 'post_type_archive_title', 'ssd_post_type_archive_title' );
 
/**
 * Returns the default settings for the plugin.
 */
function ssd_get_default_settings() {
 
    $settings = array(
        'newspage_root'      => 'newspage',
        'newspage_base'      => '',          // defaults to 'newspage_root'
        'newspage_item_base' => ''
    );
 
    return $settings;
}
 
/**
 * Filter on 'post_type_archive_title' to allow for the use of the 'archive_title' label that isn't supported 
 * by WordPress.  That's okay since we can roll our own labels.
 */
function ssd_post_type_archive_title( $title ) {
 
    if ( is_post_type_archive( 'newspage_item' ) ) {
        $post_type = get_post_type_object( 'newspage_item' );
        $title = isset( $post_type->labels->archive_title ) ? $post_type->labels->archive_title : $title;
    }
 
    return $title;
}
 
function ssd_post_type_link( $post_link, $post ) {}
 
function ssd_breadcrumb_trail_items( $items ) {}
 
?>
 
//meta.php
<?php
/**
 * Registers metadata and related functions for the plugin.
 *
 * @package    CustomContentNewspage
 * @subpackage Includes
 * @since      0.5.0
 * @copyright Copyright (c) 2014, Serhii Dymenko
 * @link      http://proserge.kh.ua/coding/index.php/post/85/WP+News+Plugin
/* Register meta on the 'init' hook. */
add_action( 'init', 'ssd_register_meta' );
 
/**
 * Registers custom metadata for the plugin.
 */
function ssd_register_meta() {
 
    register_meta( 'newspage_item', 'ssd-admin-comment', 'ssd_sanitize_meta' );
    register_meta( 'newspage_item', 'ssd-alt-title', 'ssd_sanitize_meta' );
}
 
function ssd_sanitize_meta( $meta_value, $meta_key, $meta_type ) {
 
    if ( 'ssd-admin-comment' === $meta_key || 'ssd-alt-title' === $meta_key)
        return esc_url( $meta_value );
 
    return strip_tags( $meta_value );
}
 
?>
 
//post-types.php
<?php
/**
 * File for registering custom post types.
 *
 * @package    CustomContentNewspage
 * @subpackage Includes
 * @since      0.5.0
 * @copyright Copyright (c) 2014, Serhii Dymenko
 * @link      http://proserge.kh.ua/coding/index.php/post/85/WP+News+Plugin
 * @license    http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 */
 
/* Register custom post types on the 'init' hook. */
add_action( 'init', 'ssd_register_post_types' );
 
/**
 * Registers post types needed by the plugin.
 */
function ssd_register_post_types() {
 
    /* Get the plugin settings. */
    $settings = get_option( 'plugin_custom_content_newspage', ssd_get_default_settings() );
 
    /* Set up the arguments for the newspage item post type. */
    $args = array(
        'description'         => '',
        'public'              => true,
        'publicly_queryable'  => true,
        'show_in_nav_menus'   => false,
        'show_in_admin_bar'   => true,
        'exclude_from_search' => false,
        'show_ui'             => true,
        'show_in_menu'        => true,
        'menu_position'       => 12,
        'menu_icon'           => ssd_URI . 'images/menu-icon.png',
        'can_export'          => true,
        'delete_with_user'    => false,
        'hierarchical'        => false,
        'has_archive'         => $settings['newspage_root'],
        'query_var'           => 'newspage_item',
        'capability_type'     => 'newspage_item',
        'map_meta_cap'        => true,
 
        /* Only 3 caps are needed: 'manage_newspage', 'create_newspage_items', and 'edit_newspage_items'. */
        'capabilities' => array(
 
            // meta caps (don't assign these to roles)
            'edit_post'              => 'edit_newspage_item',
            'read_post'              => 'read_newspage_item',
            'delete_post'            => 'delete_newspage_item',
 
            // primitive/meta caps
            'create_posts'           => 'create_newspage_items',
 
            // primitive caps used outside of map_meta_cap()
            'edit_posts'             => 'edit_newspage_items',
            'edit_others_posts'      => 'manage_newspage',
            'publish_posts'          => 'manage_newspage',
            'read_private_posts'     => 'read',
 
            // primitive caps used inside of map_meta_cap()
            'read'                   => 'read',
            'delete_posts'           => 'manage_newspage',
            'delete_private_posts'   => 'manage_newspage',
            'delete_published_posts' => 'manage_newspage',
            'delete_others_posts'    => 'manage_newspage',
            'edit_private_posts'     => 'edit_newspage_items',
            'edit_published_posts'   => 'edit_newspage_items'
        ),
 
        /* The rewrite handles the URL structure. */
        'rewrite' => array(
            'slug'       => !empty( $settings['newspage_item_base'] ) ? "{$settings['newspage_root']}/{$settings['newspage_item_base']}" : $settings['newspage_root'],
            'with_front' => false,
            'pages'      => true,
            'feeds'      => true,
            'ep_mask'    => EP_PERMALINK,
        ),
 
        /* What features the post type supports. */
        'supports' => array(
            'title',
            'editor',
            'excerpt',
            'author',
            'thumbnail'
        ),
 
        /* Labels used when displaying the posts. */
        'labels' => array(
            'name'               => __( 'newspage Items',                   'custom-content-newspage' ),
            'singular_name'      => __( 'newspage Item',                    'custom-content-newspage' ),
            'menu_name'          => __( 'newspage',                         'custom-content-newspage' ),
            'name_admin_bar'     => __( 'newspage Item',                    'custom-content-newspage' ),
            'add_new'            => __( 'Add New',                           'custom-content-newspage' ),
            'add_new_item'       => __( 'Add New newspage Item',            'custom-content-newspage' ),
            'edit_item'          => __( 'Edit newspage Item',               'custom-content-newspage' ),
            'new_item'           => __( 'New newspage Item',                'custom-content-newspage' ),
            'view_item'          => __( 'View newspage Item',               'custom-content-newspage' ),
            'search_items'       => __( 'Search newspage',                  'custom-content-newspage' ),
            'not_found'          => __( 'No newspage items found',          'custom-content-newspage' ),
            'not_found_in_trash' => __( 'No newspage items found in trash', 'custom-content-newspage' ),
            'all_items'          => __( 'newspage Items',                   'custom-content-newspage' ),
 
            // Custom labels b/c WordPress doesn't have anything to handle this.
            'archive_title'      => __( 'newspage',                         'custom-content-newspage' ),
        )
    );
 
    /* Register the newspage item post type. */
    register_post_type( 'newspage_item', $args );
}
 
?>
 
//widget3news.php
<?php
/*
        Plugin Name: Show Recent CPTs
        Tags: menu, CPT, widget
        Description: Creates menus and shortcode from Wordpress recent custom post type
        Author: Serhii Dymenko
        Version: 0.5.0
        Author URI: http://proserge.kh.ua/coding/index.php/post/85/WP+News+Plugin
*/
 
class Recent_CPT_Plugin extends WP_Widget 
{
    public $SSD_CPT_type = "newspage_item";
 
    //TODO - add a list of CPTs to choose which type to view as $SSD_CPT_type
 
function __construct() {
    parent::__construct(
        'recent_CPT_Plugin', // Base ID
        'Recent Newspage Plugin', // Name
        array('description' => __( 'Displays your latest news. Outputs the post thumbnail, title and date per listing'))
       );
}
function update($new_instance, $old_instance) {
        $instance = $old_instance;
        $instance['title'] = strip_tags($new_instance['title']);
        $instance['numberOfListings'] = strip_tags($new_instance['numberOfListings']);
        return $instance;
}
 
/*The method form() builds the form that we have in the admin section. 
What we’re building is a very simple form with 2 fields: a text field 
for the Widget title, and a drop down list for the number of listings 
we want to show:*/
 
function form($instance) {
    if( $instance) {
        $title = esc_attr($instance['title']);
        $numberOfListings = esc_attr($instance['numberOfListings']);
    } else {
        $title = '';
        $numberOfListings = '';
    }
    ?>
        <p>
        <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title', 'recent_CPT'); ?></label>
        <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" />
        </p>
        <p>
        <label for="<?php echo $this->get_field_id('numberOfListings'); ?>"><?php _e('Number of Listings:', 'recent_CPT'); ?></label>        
        <select id="<?php echo $this->get_field_id('numberOfListings'); ?>"  name="<?php echo $this->get_field_name('numberOfListings'); ?>">
            <?php for($x=1;$x<=10;$x++): ?>
            <option <?php echo $x == $numberOfListings ? 'selected="selected"' : '';?> value="<?php echo $x;?>"><?php echo $x; ?></option>
            <?php endfor;?>
        </select>
        </p>         
    <?php
    } 
 
 
function widget($args, $instance) { 
    extract( $args );
    $title = apply_filters('widget_title', $instance['title']);
    $numberOfListings = $instance['numberOfListings'];
    echo $before_widget;
    if ( $title ) {
        echo $before_title . $title . $after_title;
    }
    $this->getNewsListings($numberOfListings);
    echo $after_widget;
}
 
function getNewsListings($numberOfListings) { //html
    global $post;
    add_image_size( 'news_widget_size', 85, 45, false );
    $listings = new WP_Query();
    $listings->query('post_type='.$this->SSD_CPT_type.'&posts_per_page=' . $numberOfListings );    
    if($listings->found_posts > 0) {
        echo '<ul class="newspage_widget">';
            while ($listings->have_posts()) {
                $listings->the_post();
                $image = (has_post_thumbnail($post->ID)) ? get_the_post_thumbnail($post->ID, 'news_widget_size') : '<div class="noThumb"></div>'; 
                $listItem = '<li>' . $image; 
                $listItem .= '<a href="' . get_permalink() . '">';
                $listItem .= get_the_title() . '</a>';
                $listItem .= '<span>Added ' . get_the_date() . '</span></li>'; 
                echo $listItem; 
            }
        echo '</ul>';
        wp_reset_postdata(); 
    }else{
        echo '<p style="padding:25px;">No News found</p>';
    } 
}
 
function styleRecentNews() {
wp_register_style('ssd_recent_news_css', plugins_url('recent_news.css',__FILE__ ));
wp_enqueue_style('ssd_recent_news_css');
}
 
 
 
} //end class Realty_Widget
 
 
function register_recent_CPT_widget_plugin() {
register_widget('Recent_CPT_Plugin');
}
 
add_action('widgets_init', 'register_recent_CPT_widget_plugin');
 
////////-----------------------------   SHORTCODE ----------------------
// Register a new shortcode: [book]
add_shortcode( 'ssd_recent', 'ssd_recent_newspage_newes_plugin' );
 
// The callback function that will replace [ssd_recent]
function ssd_recent_newspage_newes_plugin() {
    global $post;
    $blockRecent = "<div class=\"recentShort\">";
    add_image_size( 'news_widget_size', 85, 45, false );
    $listings = new WP_Query();
    $listings->query('post_type='.$this->SSD_CPT_type.'&posts_per_page=3');    
    if($listings->found_posts > 0) {
        $blockRecent .= "<ul class=\"newspage_widget\">";
            while ($listings->have_posts()) {
                $listings->the_post();
                $image = (has_post_thumbnail($post->ID)) ? get_the_post_thumbnail($post->ID, 'news_widget_size') : '<div class="noThumb"></div>'; 
                $listItem = "<li>" . $image; 
                $listItem .= "<a href=\"get_permalink()\">";
                $listItem .= get_the_title() . "</a></br>";
                $listItem .= "<span>Added  get_the_date() </span></li>"; 
                $blockRecent .= $listItem;
                //DebugBreak(); 
            }
        $blockRecent .= "</ul>";
        wp_reset_postdata(); 
    }else{
        $blockRecent .= "<p style=\"padding:25px;\">No News found</p>";
    }
    $blockRecent .= "</div>";
    return $blockRecent;
}
 
//uninstall.php
<?php
/**
 * Uninstall procedure for the plugin.
 *
 * @package    CustomContentNewspage
 * @since      0.5.0
 * @copyright  Copyright (c) 2014, Serhii Dymenko
 * @link       http://proserge.kh.ua/coding/index.php/post/85/WP+News+Plugin
/* Make sure we're actually uninstalling the plugin. */
if ( !defined( 'WP_UNINSTALL_PLUGIN' ) )
    wp_die( sprintf( __( '%s should only be called when uninstalling the plugin.', 'custom-content-newspage' ), '<code>' . __FILE__ . '</code>' ) );
 
/* === Delete plugin options. === */
delete_option( 'plugin_custom_content_newspage' );
 
/* === Remove capabilities added by the plugin. === */
$role =& get_role( 'administrator' );
/* If the administrator role exists, remove added capabilities for the plugin. */
if ( !empty( $role ) ) {
 
    $role->remove_cap( 'manage_newspage' );
    $role->remove_cap( 'create_newspage_items' );
    $role->remove_cap( 'edit_newspage_items' );
}
 
?>
 
//readme.txt
=== Custom Content newspage ===
Contributors: snb4crazy
Tags: news, newsnewspage, post type
Requires at least: 3.9.2
Tested up to: 3.9.2
Stable tag: 0.1
License: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 
A complete newspage plugin built with custom post type.
 
== Description ==
 
**Support Questions:**  The official support forum for this plugin is located at <a href="http://proserge.kh.ua/coding/index.php/post/85/WP+News+Plugin">Author's Post</a>.
 
Custom Content newspage is a newspage management plugin for people such as PR - managers, journalists to show events organized.
 
This plugin was created because of the rising need from users who are downloading WordPress themes with newspage management built in (not a good idea for content portability).  I did my best for give users possibility to switch themes without losing content.
 
**Credits**
 
== Installation ==
 
1. Upload `custom-content-newspage` to the `/wp-content/plugins/` directory.
1. Activate the plugin through the 'Plugins' menu in WordPress.
1. Go to "Settings > Permalinks" in the admin to re-save your permalinks.
 
== Frequently Asked Questions ==
 
= How do I use it? =
 
It works just like posts or pages.  You'll get a new menu item in the admin called "newspage".  From there, you can create new stories.
 
= I'm getting 404 errors. How can I fix this? =
 
Just visit "Settings > Permalinks" in your WordPress admin to flush your rewrite rules.  After that, you shouldn't have any 404 issues.
 
= I don't see the "newspage" section. =
 
It should be located just below "Media" in the WordPress admin menu.  By default, only administrators can see this menu item.  If you are an administrator and can't see it after activating the plugin, deactivate and reactivate the plugin.  This should add the required permissions to your administrator role.
 
== Screenshots ==
 
== Changelog ==
 
**Version 0.1**
 
* Plugin launch.  Everything's new!

Building online school based on WP. I do understand how to go on with frameworks, but WP??? Analyzing articles and writing notes.

  • WordPress vs MVC Frameworks
  • Model of Site
  • Users, Roles, and Capabilities
  • Extending the WP_User Class

WordPress Versus MVC Frameworks Exist MVC plugins for WordPress: WP MVC, Churro, ... I would argue), but They say Models = plugins, Views = themes, Controllers = template loader. In WordPress, plugins are the proper place to store new data structures, complex business logic, and custom post type definitions; themes are the proper place to store templating code and logic; all page requests (unless they are accessing a cached .html file) are processed through the index.php file and processed by WordPress according to the Template Hierarchy. The template loader figures out which file in the template should be used to display the page to the end user. For example, use search.php to show search results, single.php to show a single post.

Model of Site

  • Schools can purchase a unique subdomain (specify a school name and slug admin)
  • The school admin then invites teachers. Teachers can invite students to the classes they create
  • Roles. Teacher gives access to create and edit classes, moderate discussion in their class forums, and create and manage assignments 4 classes through frontend forms created for this purpose. Students - the default Subscriber role in WordPress, only have access to view and participate in classes they are invited to by their teachers.
  • Classes Are BuddyPress Groups, forums are powered by the bbPress plugin, new forum is generated for each class
  • Assignments are a custom post type (CPT). Submissions are also CPTs linked to assignments by setting the submission’s post_parent field to the ID of the assignment it was submitted to. Students can post text content and also add one or more attachments to a submission.
  • Semesters Are a Taxonomy on the Class CPT. A custom taxonomy called “Department” is also set up for the group/class CPT.
  • Proposals Free Plugins: BadgeOS, Custom Post Type UI, Posts 2 Posts (allows you to create many-to-many relationships between posts, pages, and custom post types as well as users. For an example, you could use P2P to make connections between custom post types for schools, teachers, and subjects), Members, W3 Total Cache, WP All Import, BuddyPress (plus BuddyPress Toolbar, BuddyPress FollowMe, BuddyPress Media, BuddyPress Registration Options,BuddyMobile, BadgeOS Community Add-on, bbPress

The** functions.php** file of active theme (and parent theme if applicable) is loaded every time WordPress loads. For this reason, the functions.php file is a popular place to add little hacks and other random bits of code, the file can quickly become a mess. Developing a well-planned WordPress app, and function.php we break up the core functions of our main app plugin into smaller includes: functions.php, settings.php, sidebars.php

Users, Roles, and Capabilities The workhorse for managing WordPress users in code is the WP_User class.

<?php
// get the WP_User object WordPress creates for the currently logged-in user
global $current_user;
 
// get the currently logged-in user with the wp_get_current_user() function
$user = wp_get_current_user();
 
// set some variables
$user_id = 1;
$username = 'jason';
$email = 'jason@strangerstudios.com';
 
// get a user by ID
$user = wp_getuserdata( $user_id );
 
// get a user by another field
$user1 = wp_get_user_by( 'login', $username );
$user2 = wp_get_user_by( 'email', $email );
 
// use the WP_User constructor directly
$user = new WP_User( $user_id );
 
//use the WP_User constructor with a username
$user = new WP_User( $username );
 
// get the currently logged-in user
$user = wp_get_current_user();
 
// echo the user's display_name
echo $user->display_name;
 
// use user's email address to send an email
wp_mail( $user->user_email, 'Email Subject', 'Email Body' );
 
// get any user meta value
echo 'Department: ' . $user->department;
 
$full_name = trim( $user->first_name . ' ' . $user->last_name );
$full_name = trim( get_user_meta( $user->ID, 'first_name' ) . 
    ' ' . get_user_meta( $user->ID, 'last_name' ) );
 
//using MAGIC METHODS
function __get( $key ) {    
if ( isset( $this->data->$key ) ) {
        $value = $this->data->$key;
    } else {
        $value = get_user_meta( $this->ID, $key, true );
    }
 
    return $value;
}
 
// dump all meta data for a user
$user_meta = get_user_meta( $user_id );
foreach( $user_meta as $key => $value )
    echo $key . ': ' . $value . '<br />';
 
// Split assignments into multiple lines when using magic methods.
$user->graduation_year = '2012';
$year = '2012';
 
//To test if a meta value is empty, set a local variable first.
$year = $user->graduation_year;
if ( empty( $year ) )
    $year = '2012';
 
//---------------Add, Update, and Delete Users
// insert user from values we've gathered
$user_id = wp_insert_user( array(
    'user_login' => $username,                          
    'user_pass' => $password,
    'user_email' => $email,
    'first_name' => $firstname,
    'last_name' => $lastname
    )
);
 
// check if username or email has already been used
if ( is_wp_error( $user_id ) ){
    echo $return->get_error_message();
} else {
    // continue on with whatever you want to do with the new $user_id
}
 
// okay, log them in to WP                          
$creds = array();
$creds['user_login'] = $username;
$creds['user_password'] = $password;
$creds['remember'] = true;
$user = wp_signon( $creds, false ); 
 
// this will update a user's email and leave other values alone
$userdata = array( 'ID' => 1, 'user_email' => 'jason@strangerstudios.com' );
wp_update_user( $userdata );
 
// this function is also perfect for updating multiple user meta fields at once
wp_update_user( array(
    'ID' => 1,
    'company' => 'Stranger Studios',
    'title' => 'CEO',
    'personality' => 'crescent fresh'
));

Updating users is as easy as adding them with the wp_update_user() function. You pass in an array of user data and metadata. As long as there is an ID key in the array with a valid user ID as the value, WordPress will set any specified user values. You can also update one user meta value at a time using the up date_user_meta($user_id, $meta_key, $meta_value, $prev_value) function.

<?php
// arrays will get serialized
$children = array( 'Isaac', 'Marin');
update_user_meta( $user_id, 'children', $children );
 
// you can also store array by storing multiple values with the same key
update_user_meta( $user_id, 'children', 'Isaac' );
update_user_meta( $user_id, 'children', 'Marin' );
 
// when storing multiple values, specify the $prev_value parameter 
// to select which meta value is updated
update_user_meta( $user_id, 'children', 'Isaac Ford', 'Isaac' );
update_user_meta( $user_id, 'children', 'Marin Josephine', 'Marin' );
 
//delete all user meta by key
delete_user_meta( $user_id, 'children' );
 
//delete just one row when there are multiple values for one key
delete_user_meta( $user_id, 'children', 'Isaac Ford' );
?>
 
 
<?php
// get the IDs of all users with children named Isaac
$parents_of_isaac = $wpdb->get_col( "SELECT user_id 
    FROM $wpdb->usermeta 
    WHERE meta_key = 'children' 
    AND meta_value = 'Isaac'" );
?>
 
<?php
//this file contains wp_delete_user and is not always loaded, so let's make sure
require_once( ABSPATH . '/wp-admin/includes/user.php' );
 
//delete the user
wp_delete_user( $user_id );
 
//or delete a user and reassign their posts to user with ID #1
wp_delete_user( $user_id, 1 );
?>

Hooks and Filters

<?php
//create a new "course" CPT when a teacher registers
function sp_user_register( $user_id ){
    // check if the new user is a teacher (see Chapter 15 for details)
    if ( pmpro_hasMembershipLevel( 'teacher', $user_id ) ) {
        // add a new "course" CPT with this user as author
        wp_insert_post( array(
            'post_title' => 'My First Course',
            'post_content' => 'This is a sample course...',
            'post_author' => $user_id,
            'post_status' => 'draft',
            'post_type' => 'course'
 
        ) );
    }
}
add_action( 'user_register', 'sp_user_register' );
?>
 
<?php
// send an email when a user is being deleted
function sp_delete_user( $user_id ){
    $user = get_userdata( $user_id );
    wp_mail( $user->user_email, 
        "You've been deleted.", 
        'Your account at SchoolPress has been deleted.'
    );
}
// want to be able to get user_email so hook in early
add_action( 'delete_user', 'sp_delete_user' );
?>

Checking a User’s Role and Capabilities

<?php
if ( current_user_can( 'manage_options' ) ) { 
    // has the manage options capability, typically an admin
}
 
if ( current_user_can( 'edit_user', $user_id ) ) {
    // can edit the user with ID = $user_id. 
    // typically either the user himself or an admin 
}
 
if ( current_user_can( 'edit_post', $post_id ) ) {
    // can edit the post with ID = $post_id. 
    // typically the author of the post or an admin or editor
}
 
if ( current_user_can( 'subscriber' ) ) {
    // one way to check if the current user is a subscriber
}
?>
 
<?php
/*
    Output comments for the current post,
    highlighting anyone who has capabilities to edit it.
*/
global $post;   // current post we are looking at
 
$comments = get_comments( 'post_id=' . $post->ID );
foreach( $comments as $comment ){
    // default CSS classes for all comments
    $classes = 'comment';
 
    // add can-edit CSS class to authors
    if ( user_can( $comment->user_id, 'edit_post', $post->ID ) )
        $classes .= ' can-edit';
?>
<div id="comment-<?php echo $comment->comment_ID;?>" 
    class="<?php echo $classes;?>">
    Comment by <?php echo $comment->comment_author;?>:
    <?php echo wpautop( $comment->comment_content );?>
</div>
<?php
}
?>

Extending the WP_User Class

<?php
class Student extends WP_User {
    // no constructor so WP_User's constructor is used
 
    // method to get assignments for this Student
    function getAssignments() {
        // get assignments via get_posts if we haven't yet
        if ( ! isset( $this->data->assignments ) )
            $this->data->assignments = get_posts( array(
                'post_type' => 'assignment',    // assignments
                'numberposts' => -1,            // all posts
                'author' => $this->ID           // user ID for this Student
            ));
 
        return $this->data->assignments;
    }
 
    // magic method to detect $student->assignments
    function __get( $key ) {
        if ( $key == 'assignments' )
        {
            return $this->getAssignments();
        }
        else
        {
            // fallback to default WP_User magic method
            return parent::__get( $key );
        }
    }    
}
?>

The getAssignments() method uses the get_posts() function to get all posts of type assignment that are authored by the user associated with this Student store the array of assignment posts in the $data property, which is defined in the WP_User class and stores all of the base user data and metadata. This allows us to use code like $student->assignments to get the assignments ,normally if $student->assignments is a defined property of $student, the value of that property will be returned. But if there is no property, PHP will send assignments as the $key parameter to __get method. Here we check that $key == "assignments" and then return the value of the getAssignments() method defined later. If $key is something other than assignments pass it to the __get() method of the parent WP_User class, which checks for the value in the $data property of the class instance or failing that sends the key to the get_user_meta() function.

Couldnot answer such questions on an interview, cheat sheet is needed. The database s c h e m a with specific functions found to work with each table described with real world examples.

  • wp_options
  • wp_users
  • wp_usermeta
  • wp_posts
  • wp_postmeta
  • wp_comments
  • wp_commentsmeta
  • wp_terms, wp_term_taxonomy, wp_term_relationships

wp_options - stores the name, description, and admin email that you entered , also come prepopulated with a few records that store the various default settings.

<?php
// add option
$twitters = array( '@ssd', '@bmess', '@jason_coleman' );
add_option( 'ssd_twitter_accounts', $twitters );
 
// get option
$ssd_twitter_accounts = get_option( 'ssd_twitter_accounts' );
echo '<pre>';
print_r( $ssd_twitter_accounts );
echo '</pre>';
 
// update option
$twitters = array_merge( 
    $twitters, 
    array( 
        '@webdevstudios', 
        '@strangerstudios' 
    ) 
);
update_option( 'ssd_twitter_accounts', $twitters );
 
// get option
$ssd_twitter_accounts = get_option( 'ssd_twitter_accounts' );
echo '<pre>';
print_r( $ssd_twitter_accounts );
echo '</pre>';
 
// delete option
delete_option( 'ssd_twitter_accounts' );
 
 
/*
The output from the above example should look something like this:
Array
(
    [0] => @ssd
    [1] => @bmess
    [2] => @jason_coleman
)
Array
(
    [0] => @ssd
    [1] => @bmess
    [2] => @jason_coleman
    [3] => @webdevstudios
    [4] => @strangerstudios
)
*/
?>

wp_users When log in to WordPress with your username and password, you are referencing data stored in this table. All users and their default data are stored in the wp_users table.

<?php
// insert user
$userdata = array(
    'user_login'    => 'brian',
    'user_pass'     => 'KO03gT7@n*',
    'user_nicename' => 'Brian',
    'user_url'      => 'http://webdevstudios.com/',
    'user_email'    => 'brian@schoolpress.me',
    'display_name'  => 'Brian',
    'nickname'      => 'Brian',
    'first_name'    => 'Brian',
    'last_name'     => 'Messenlehner',
    'description'   => 'This is a SchoolPress Administrator account.',
    'role'          => 'administrator'
);
wp_insert_user( $userdata );
 
// create users
wp_create_user( 'jason', 'YR529G%*v@', 'jason@schoolpress.me' );
 
// get user by login
$user = get_user_by( 'login', 'brian' );
echo 'email: ' . $user->user_email  . ' / ID: ' . $user->ID . '<br>';
echo 'Hi: ' . $user->first_name . ' ' . $user->last_name . '<br>';
 
// get user by email
$user = get_user_by( 'email', 'jason@schoolpress.me' );
echo 'username: ' . $user->user_login . ' / ID: ' . $user->ID . '<br>';
 
// update user - add first and last name to brian and change role to admin
$userdata = array(
    'ID'         => $user->ID,
    'first_name' => 'Jason',
    'last_name'  => 'Coleman',
    'user_url'   => 'http://strangerstudios.com/',
    'role'       => 'administrator'
);
wp_update_user( $userdata );
 
// get userdata for brian
$user = get_userdata( $user->ID );
echo 'Hi: ' . $user->first_name . ' ' . $user->last_name . '<br>';
 
// delete user - delete the original admin and set their posts to our new admin
// wp_delete_user( 1, $user->ID );
 
/*
The output from the above example should look something like this:
email: brian@schoolpress.me / ID: 2
Hi: Brian Messenlehner
username: jason / ID: 3
Hi: Jason Coleman
*/
?>

wp_usermeta - to store additional data along with a user. WordPress provides an easy way to do this without having to add additional columns to the users table. Each record is associated to a user ID in the wp_user table by the user_id field

<?php
// get brian's id
$brian_id = get_user_by( 'login', 'brian' )->ID;
 
// add user meta - unique is set to true. no polygamy! only one wife at a time.
add_user_meta( 
    $brian_id, 
    'ssd_wife', 
    'Robin Jade Morales Messenlehner', 
    true
);
 
// get user meta - returning a single value
$brians_wife = get_user_meta( $brian_id, 'ssd_wife', true);
echo "Brian's wife: " . $brians_wife . "<br>";
 
// add user meta - no 3rd parameter/unique. 
// can have as many kids as wife will let me.
add_user_meta( $brian_id, 'ssd_kid', 'Dalya' );
add_user_meta( $brian_id, 'ssd_kid', 'Brian' );
add_user_meta( $brian_id, 'ssd_kid', 'Nina' );
 
// update user meta - this will update brian to brian jr.
update_user_meta( $brian_id, 'ssd_kid', 'Brian Jr', 'Brian' );
 
// get user meta - returning an array
$brians_kids = get_user_meta( $brian_id, 'ssd_kid' );
echo "Brian's kids:";
echo '<pre>';
print_r($brians_kids);
echo '</pre>';
 
// delete brian's user meta
delete_user_meta( $brian_id, 'ssd_wife' );
delete_user_meta( $brian_id, 'ssd_kid' );
 
// get jason's id
$jason_id = get_user_by( 'login', 'jason' )->ID;
 
// update user meta - creates user meta if key doesn't exist for the user.
update_user_meta( $jason_id, 'ssd_wife', 'Kimberly Ann Coleman' );
 
// get user meta - returning an array
$jasons_wife = get_user_meta( $jason_id, 'ssd_wife' );
echo "Jason's wife:";
echo '<pre>';
print_r($jasons_wife);
echo '</pre>';
 
// add user meta - storing as an array
add_user_meta( $jason_id, 'ssd_kid', array( 'Isaac', 'Marin' ) );
 
// get user meta - returning a single value which happens to be an array.
$jasons_kids = get_user_meta( $jason_id, 'ssd_kid', true );
echo "Jason's kids:";
echo '<pre>';
print_r($jasons_kids);
echo '</pre>';
 
// delete jason's user meta
delete_user_meta( $jason_id, 'ssd_wife' );
delete_user_meta( $jason_id, 'ssd_kid' );
 
/*
The output from the above example should look something like this:
Brian's wife: Robin Jade Morales Messenlehner
Brian's kids:
Array
(
    [0] => Dalya
    [1] => Brian Jr
    [2] => Nina
)
Jason's wife:
Array
(
    [0] => Kimberly Ann Coleman
)
Jason's kids:
Array
(
    [0] => Isaac
    [1] => Marin
)
*/
?>

wp_posts table is where most of post data is stored. By default, WordPress comes with posts and pages. Both are technically posts and are stored in this table. The post_type field is distinguishes type of post: post, a page, a menu item, a revision, or any custom post type

<?php
// insert post - set post status to draft
$args = array(
    'post_title'   => 'Building Web Apps with WordPress',
    'post_excerpt' => 'WordPress as an Application Framework',
    'post_content' => 'WordPress is the key to successful cost effective 
    web solutions in most situations. Build almost anything on top of the 
    WordPress platform. DO IT NOW!!!!',
    'post_status'  => 'draft',
    'post_type'    => 'post',
    'post_author'  => 1,
    'menu_order'   => 0
);
$post_id = wp_insert_post( $args );
echo 'post ID: ' . $post_id . '<br>';
 
// update post - change post status to publish
$args = array(
    'ID'          => $post_id,
    'post_status' => 'publish'
);
wp_update_post( $args );
 
// get post - return post data as an object
$post = get_post( $post_id );
echo 'Object Title: ' . $post->post_title . '<br>';
 
// get post - return post data as an array
$post = get_post( $post_id, ARRAY_A );
echo 'Array Title: ' . $post['post_title'] . '<br>';
 
// delete post - skip the trash and permanently delete it
wp_delete_post( $post_id, true );
 
// get posts - return 100 posts
$posts = get_posts( array( 'posts_per_page' => '100') );
// loop all posts and display the ID & title
foreach ( $posts as $post ) {
    echo $post->ID . ': ' .$post->post_title . '<br>';
}
 
/*
The output from the above example should look something like this:
post ID: 589
Object Title: Building Web Apps with WordPress
Array Title: Building Web Apps with WordPress
"A list of post IDs and Titles from your install"
*/
?>

wp_postmeta to store additional data along with a post without having to add additional fields to the posts table. Store as much post metadata as you need to in the wp_postmeta table. Each record is associated to a post through the post_id field. When editing any post in the backend of WordPress, you can add/update/delete metadata or Custom Fields via the UI.

<?php
// get posts - return the latest post
$posts = get_posts( 
    array( 
        'posts_per_page' => '1', 
        'orderby' => 'post_date', 
        'order' => 'DESC' 
    ) 
);
foreach ( $posts as $post ) {
    $post_id = $post->ID;
 
    // update post meta - public meta data
    $content = 'You SHOULD see this custom field when editing your latest post.';
    update_post_meta( $post_id, 'ssd_displayed_field', $content );
 
    // update post meta - hidden meta data
    $content = str_replace( 'SHOULD', 'SHOULD NOT', $content );
    update_post_meta( $post_id, '_ssd_hidden_field', $content );
 
    // array of student logins
    $students[] = 'dalya';
    $students[] = 'ashleigh';
    $students[] = 'lola';
    $students[] = 'isaac';
    $students[] = 'marin';
    $students[] = 'brian';
    $students[] = 'nina';
 
    // add post meta - one key with serialized array as value
    add_post_meta( $post_id, 'ssd_students', $students, true );
 
    // loop students and add post meta record for each student
    foreach ( $students as $student ) {
        add_post_meta( $post_id, 'ssd_student', $student );
    }
 
    // get post meta - get all meta keys
    $all_meta = get_post_meta( $post_id );
    echo '<pre>';
    print_r( $all_meta );
    echo '</pre>';
 
    // get post meta - get 1st instance of key
    $student = get_post_meta( $post_id, 'ssd_student', true );
    echo 'oldest student: ' . $student;
 
    // delete post meta
    delete_post_meta( $post_id, 'ssd_student' );
}
 
/*
The output from the above example should look something like this:
Array
(
    [_ssd_hidden_field] => Array
        (
            [0] => You SHOULD NOT see this custom field 
            when editing your latest post.
        )
 
    [ssd_displayed_field] => Array
        (
            [0] => You SHOULD see this custom field when editing 
            your latest post.
        )
 
    [ssd_students] => Array
        (
            [0] => a:7:{i:0;s:5:"dalya";i:1;s:8:"ashleigh";i:2;
            s:4:"lola";i:3;s:5:"isaac";i:4;s:5:"marin";i:5;
            s:5:"brian";i:6;s:4:"nina";}
        )
 
    [ssd_student] => Array
        (
            [0] => dalya
            [1] => ashleigh
            [2] => lola
            [3] => isaac
            [4] => marin
            [5] => brian
            [6] => nina
        )
)
oldest student: dalya
*/
?>

wp_comments Comments can be left against any post. The wp_comments table stores individual comments for any post and default associated data

<?php
// insert post
$args = array(
    'post_title'   => '5 year anniversary on 9/10/16',
    'post_content' => 'Think of somthing cool to do, make a comment!',
    'post_status'  => 'publish'
);
$post_id = wp_insert_post( $args );
echo 'post ID: ' . $post_id . ' - ' . $args['post_title'] . '<br>';
 
// make comments array
$comments[] = 'Take a trip to South Jersey';
$comments[] = 'Dinner at Taco Bell';
$comments[] = 'Make a baby';
 
// loop comments array
foreach ( $comments as $comment ) {
    // insert comments
    $commentdata = array(
        'comment_post_ID' => $post_id,
        'comment_content' => $comment,
    );
    $comment_ids[] = wp_insert_comment( $commentdata );
}
echo 'comments:<pre>';
print_r( $comments );
echo '</pre>';
 
// update comment
$commentarr['comment_ID'] = $comment_ids[0];
$commentarr['comment_content'] = 'Take a trip to Paris, France';
wp_update_comment( $commentarr );
 
// insert comment - sub comment from parent id
$commentdata = array(
    'comment_post_ID' => $post_id,
    'comment_parent' => $comment_ids[0],
    'comment_content' => 'That is a pretty good idea...',
);
wp_insert_comment( $commentdata );
 
// get comments - search taco bell
$comments = get_comments( 'search=Taco Bell&number=1' );
foreach ( $comments as $comment ) {
    // insert comment - sub comment of taco bell comment id
    $commentdata = array(
        'comment_post_ID' => $post_id,
        'comment_parent' => $comment->comment_ID,
        'comment_content' => 'Do you want to get smacked up?',
    );
    wp_insert_comment( $commentdata );
}
 
// get comment - count of comments for this post
$comment_count = get_comments( 'post_id= ' . $post_id . '&count=true' );
echo 'comment count: ' . $comment_count . '<br>';
 
// get comments - get all comments for this post
$comments = get_comments( 'post_id=' .$post_id );
foreach ( $comments as $comment ) {
    // update 1st comment
    if ( $comment_ids[0] == $comment->comment_ID ) {
        $commentarr = array(
            'comment_ID' => $comment->comment_ID,
            'comment_content' => $comment->comment_content . 
            ' & make a baby!',
        );
        wp_update_comment( $commentarr );
        // delete all other comments
    }else {
        // delete comment
        wp_delete_comment( $comment->comment_ID, true );
    }
}
 
// get comment - new comment count
$comment_count = get_comments( 'post_id= ' . $post_id . '&count=true' );
echo 'new comment count: ' . $comment_count . '<br>';
 
// get comment - get best comment
$comment = get_comment( $comment_ids[0] );
echo 'best comment: ' . $comment->comment_content;
 
/*
The output from the above example should look something like this:
post ID: 91011 - 5 year anniversary on 9/10/16
comments:
Array
(
    [0] => Take a trip to South Jersey
    [1] => Dinner at Taco Bell
    [2] => Make a baby
)
comment count: 5
new comment count: 1
best comment: Take a trip to Paris, France & make a baby!
*/
?>

wp_commentsmeta Just like the wp_usermeta and wp_postmeta table, this table stores any custom, additional data tied to a comment by the comment_id fields

<?php
// get comments - last comment ID
$comments = get_comments( 'number=1' );
foreach ( $comments as $comment ) {
    $comment_id = $comment->comment_ID;
 
    // add comment meta - meta for view date & ip address
    $viewed = array( date( "m.d.y" ), $_SERVER["REMOTE_ADDR"] );
    $comment_meta_id = add_comment_meta( 
        $comment_id, 
        'ssd_view_date', 
        $viewed, 
        true 
    );
    echo 'comment meta id: ' . $comment_meta_id;
 
    // update comment meta - change date format to fomrat like 
    // October 23, 2020, 12:00 am instead of 10.23.20
    $viewed = array( date( "F j, Y, g:i a" ), $_SERVER["REMOTE_ADDR"] );
    update_comment_meta( $comment_id, 'ssd_view_date', $viewed );
 
    // get comment meta - all keys
    $comment_meta = get_comment_meta( $comment_id );
    echo '<pre>';
    print_r( $comment_meta );
    echo '</pre>';
 
    // delete comment meta
    delete_comment_meta( $comment_id, 'ssd_view_date' );
}
 
/*
The output from the above example should look something like this:
comment meta id: 16
Array
(
    [ssd_view_date] => Array
        (
            [0] => a:2:{i:0;s:24:"August 11, 2013, 4:16 pm";
            i:1;s:9:"127.0.0.1";}
        )
 
)
*/
?>

wp_terms table stores each category name or term name , Each record is tied to its taxonomy in the wp_term_taxonomy table by the term_id, each category or tag is stored in this table, and technically they are both taxonomies. The wp_term_taxonomy table stores each taxonomy type you are using. The wp_term_relationships table relates a taxonomy term to a post. Every time assign a category or tag to a post, it’s being linked to that post in this table.

<?php
// list all taxonomies
$taxonomies = get_taxonomies();
echo '<pre>';
print_r( $taxonomies );
echo '</pre>';
 
// list all taxonomies tied to the post post type that have an available ui
$args = array(
    'public' => 1,
    'show_ui' => 1,
    'object_type' => array( 'post')
);
$taxonomies = get_taxonomies( $args );
echo '<pre>';
print_r( $taxonomies );
echo '</pre>';
 
// add some new terms for the category and post_tag taxonomies
wp_insert_term( 'Fun',    'post_tag' );
wp_insert_term( 'Boring', 'post_tag' );
wp_insert_term( 'Home',   'category' );
wp_insert_term( 'Work',   'category' );
wp_insert_term( 'School', 'category' );
 
// get school term id
$term = get_term_by( 'slug', 'school', 'category' );
$term_id = $term->term_id;
echo $term_id;
 
// add sub terms under the school term
wp_insert_term( 'Math',      'category', array( 'parent' => $term_id ) );
wp_insert_term( 'Science',   'category', array( 'parent' => $term_id ) );
wp_insert_term( 'WordPress', 'category', array( 'parent' => $term_id ) );
 
// list all terms for the category and post_tag taxonomies
$args = array(
     'orderby'    => 'count',
     'hide_empty' => 0
);
$terms = get_terms( $taxonomies, $args );
echo '<pre>';
print_r( $terms );
echo '</pre>';
 
 
// get posts - return the latest post
$posts = get_posts( array( 'posts_per_page' => '1', 'orderby' => 'post_date', 'order' => 'DESC' ) );
foreach ( $posts as $post ) {
    $post_id = $post->ID;
 
    echo $post_id;
}
?>
  • Register a CPT ("homework" post type)
  • Register Taxonomy
  • The Theme Archive and Single Template Files
  • Metadata with CPTs
  • Custom Wrapper Classes for CPTs

Register a CPT with the function register_post_type( $post_type, $args );, and in most cases, you are going to register your CPT in your theme’s functions.php file or in a custom plugin file.

<?php
// custom function to register a "homework" post type
function ssd_register_post_type_homework() {
    register_post_type( 'homework',
        array(
            'labels' => array(
                'name' => __( 'Homework' ),
                'singular_name' => __( 'Homework' )
            ),
        'public' => true,
        'has_archive' => true,
        )
    );
}
// call our custom function with the init hook
add_action( 'init', 'ssd_register_post_type_homework' );
 
// custom function to register a "submissions" post type
function ssd_register_post_type_submission() {
    register_post_type( 'submissions',
        array(
            'labels' => array(
                'name' => __( 'Submissions' ),
                'singular_name' => __( 'Submission' )
            ),
        'public' => true,
        'has_archive' => true,
        )
    );
}
// call our custom function with the init hook
add_action( 'init', 'ssd_register_post_type_submission' );
?>

Taxonomies group posts by terms. Think post categories and post tags; these are just builtin taxonomies attached to the default post type. You can define as many custom taxonomies or categories as you want and span them across multiple post types. Tax or Meta? Since we’ll be able to pre-filter to get all assignments by textbook or by student, we can use a chapter meta field, or possibly a textbook_chapter meta field with data like “PrinciplesOfMath.Ch1” to order the assignments for the report.

<?php
// custom function to register the "subject" taxonomy
function ssd_register_taxonomy_subject() {
   register_taxonomy(
      'subject',
      'homework',
      array(
         'label' => __( 'Subjects' ),
         'rewrite' => array( 'slug' => 'subject' ),
         'hierarchical' => true
      )
   );
}
// call our custom function with the init hook
add_action( 'init', 'ssd_register_taxonomy_subject' );
?>
/*What if you wanted to use a default taxonomy on a custom post type? Say you want to
use the same tags taxonomy attached to the posts post type on our homework post type.*/
<?php
function ssd_register_taxonomy_for_object_type_homework(){
    register_taxonomy_for_object_type( 'post_tag', 'homework' );
}
add_action( 'init', 'ssd_register_taxonomy_for_object_type_homework' );
?>

The Theme Archive and Single Template Files Make a copy of archive.php and name it archive-homework.php. You should now automatically have a listing archive page of all of your homework assignment posts in the same format of your regular posts archive page (at domain.com/homework/). This same method can be applied to the single.php file. Make a copy if it and call it singlehomework. php. You should now have a single page for each of your homework assignments (at domain.com/homework/science-worksheet/). Now you can change the markup of the CPT archive or single file to display your data differently from how your blog posts are displayed. Good Old WP_Query and get_posts() you can set the post_type parameter to query and loop through your CPT posts the same way you would with regular posts.

//submission form
<?php
function ssd_the_content_homework_submission($content){
 
    global $post;
 
    // Don't do this for any other post type than homework
    // and if a user is not logged in
    $current_user = wp_get_current_user();
    if ( ! is_single() || $post->post_type != 'homework' || ! $current_user )
        return $content;
 
    // get current user's submission to this homework assignment
    $submissions = get_posts( array( 
        'post_author'    => $current_user->ID, 
        'posts_per_page' => '1',
        'post_type'      => 'submissions', 
        'meta_key'       => '_submission_homework_id', 
        'meta_value'     => $post->ID  
    ) );
    foreach ( $submissions as $submission ) {
        $submission_id = $submission->ID;
    }
 
    // Process the form submission if the user hasn't already
    if ( !$submission_id && 
            isset( $_POST['submit-homework-submission'] ) && 
            isset( $_POST['homework-submission'] ) ) {
 
        $submission = $_POST['homework-submission'];
        $post_title = $post->post_title; 
        $post_title .= ' - Submission by ' . $current_user->display_name;
        // Insert submission as a post into our submissions CPT.
        $args = array(
            'post_title'   => $post_title,
            'post_content' => $submission,
            'post_type'    => 'submissions',
            'post_status'  => 'publish',
            'post_author'  => $current_user->ID
        );
        $submission_id = wp_insert_post( $args );
        // add post meta to tie this submission post to the homework post
        add_post_meta( $submission_id, 
            '_submission_homework_id', 
            $post->ID 
        );
        // create a custom message
        $message = __( 
            'Homework submitted and is awaiting review.', 
            'ssd' 
        );
        $message = '<div class="message">' . $message . '</div>';
        // drop message before the filtered $content variable
        $content = $message . $content;
    }
 
    // Add a link to the user's submission
    if( $submission_id ) {
 
        $message = sprintf( __( 
            'Click %s here %s to view your submission.',
            'ssd' ), 
            '<a href="' . get_permalink( $submission_id ) . '">',
            '</a>' );
        $message = '<div class="link">' . $message . '</div>';
        $content .= $message;
 
    // Add a form after the $content variable being filtered.
    } else {
 
        ob_start();
        ?>
        <h3>
        <?php _e( 'Submit your Homework below!', 'ssd' );?>
        </h3>
        <form method="post">
        <?php 
        wp_editor( '', 
            'homework-submission', 
            array( 'media_buttons' => false ) 
        );
        ?>
        <input type="submit" name="homework-submission" value="Submit" />
        </form>
        <?php 
        $form = ob_get_contents();
        ob_end_clean();
        $content .= $form;
    }
 
    return $content;
 
}
// add a filter on 'the_content' to run our homework submissions code
add_filter( 'the_content', 
    'ssd_the_content_homework_submission',
    999 
);
?>

Using ob_start(), wp_editor(), ob_get_contents(), ob_end_clean() because the wp_editor() function does not currently have an argument to return the editor as a variable and outputs it to the browser when it’s called. If we didn’t use these functions, we wouldn’t be able to put our editor after the $content variable passed into the the_content filter

<?php
function ssd_submissions_template_redirect(){
    global $post, $user_ID;
 
    // only run this function for the submissions post type
    if ( $post->post_type != 'submissions' )
        return;
 
    // check if post_author is the current user_ID 
    if ( $post->post_author == $user_ID )
        $no_redirect = true;
 
    // check if current user is an administrator
    if ( current_user_can( 'manage_options' ) )
        $no_redirect = true;
 
    // if $no_redirect is false redirect to the home page
    if ( ! $no_redirect ) {
        wp_redirect( home_url() );
        exit();
    }
}
// use the template_redirect hook to call a function that decides if the
// current user can access the current homework submission
add_action( 'template_redirect', 'ssd_submissions_template_redirect' );
?>

Metadata with CPTs

<?php
// function for adding a custom meta box
function ssd_homework_add_meta_boxes(){
 
    add_meta_box(
        'homework_meta',
        'Additonal Homework Info',
        'ssd_homework_meta_box',
        'homework',
        'side'
    );
 
}
// use the add_meta_boxes hook to call a custom function to add a new meta box
add_action( 'add_meta_boxes', 'ssd_homework_add_meta_boxes' );
 
// this is the callback function called from add_meta_box
function ssd_homework_meta_box( $post ){
    // doing this so the url will fit in the book ;)
    $jquery_url = 'http://ajax.googleapis.com/ajax/libs/';
    $jquery_url.= 'jqueryui/1.8.2/themes/smoothness/jquery-ui.css';
 
    // enqueue jquery date picker
    wp_enqueue_script( 'jquery-ui-datepicker' );
    wp_enqueue_style( 'jquery-style', $jquery_url );
 
    // set meta data if already exists
    $is_required = get_post_meta( $post->ID, 
        '_ssd_homework_is_required', 1 );
 
    $due_date = get_post_meta( $post->ID, 
        '_ssd_homework_due_date', 1 );
    // output meta data fields
    ?>
    <p>
    <input type="checkbox" 
    name="is_required" value="1" <?php checked( $is_required, '1' ); ?>>
    This assignment is required.
    </p>
    <p>
    Due Date:
    <input type="text" 
    name="due_date" id="due_date" value="<?php echo $due_date;?>">
    </p>
    <?php // attach jquery date picker to our due_date field?>
    <script>
    jQuery(document).ready(function() {
        jQuery('#due_date').datepicker({
            dateFormat : 'mm/dd/yy'
        });
    });
    </script>
    <?php
}
 
// function for saving custom meta data to the database
function ssd_homework_save_post( $post_id ){
 
  // don't save anything if WP is auto saving
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) 
      return $post_id;
 
  // check if correct post type and that the user has correct permissions
  if ( 'homework' == $_POST['post_type'] ) {
 
    if ( ! current_user_can( 'edit_page', $post_id ) )
        return $post_id;
 
  } else {
 
    if ( ! current_user_can( 'edit_post', $post_id ) )
        return $post_id;
  }
 
  // update homework meta data
  update_post_meta( $post_id, 
      '_ssd_homework_is_required', 
      $_POST['is_required'] 
  );
  update_post_meta( $post_id, 
      '_ssd_homework_due_date', 
      $_POST['due_date'] 
  );
 
}
// call a custom function to handle saving our meta data
add_action( 'save_post', 'ssd_homework_save_post' );
?>

Custom Wrapper Classes for CPTs CPTs are just posts. So you can use a call like get_post($post_id) to get an object of the WP_Post class to work with. For complex CPTs, it helps to create a wrapper class so you can interact with your CPT in a more object-oriented way. The basic idea is to create a custom-defined PHP class that includes as a property a post object generated from the ID of the CPT post. In addition to storing that post object, the wrapper class also houses methods for all of the functionality related to that CPT.

//CPT wrapper class
<?php
/*
    Class Wrapper for Homework CPT
    /wp-content/plugins/ssd/classes/class.homework.php
*/
class Homework {
    //constructor can take a $post_id
    function __construct( $post_id = NULL ) {
        if ( !empty( $post_id ) )
            $this->getPost( $post_id );
    }
 
    //get the associated post and prepopulate some properties
    function getPost( $post_id ) {
        //get post
        $this->post = get_post( $post_id );
 
        //set some properties for easy access
        if ( !empty( $this->post ) ) {
        $this->id = $this->post->ID;
        $this->post_id = $this->post->ID;
        $this->title = $this->post->post_title;
        $this->teacher_id = $this->post->post_author;
        $this->content = $this->post->post_content;
        $this->required = $this->post->_ssd_homework_is_required;
        $this->due_date = $this->post->due_date;
        }
 
        //return post id if found or false if not
        if ( !empty( $this->id ) )
            return $this->id;
        else
            return false;
    }
}
?>
 
//Get and print a specific homework assignment
 
<?php
$assignment_id = 1;
$assignment = new Homework($assignment_id);
echo '<pre>'; 
print_r($assignment);
echo '</pre>';
//Outputs:
/*
Homework Object
(
    [post] => WP_Post Object
        (
            [ID] => 1
            [post_author] => 1
            [post_date] => 2013-03-28 14:53:56
            [post_date_gmt] => 2013-03-28 14:53:56
            [post_content] => This is the assignment...
            [post_title] => Assignment #1
            [post_excerpt] => 
            [post_status] => publish
            [comment_status] => open
            [ping_status] => open
            [post_password] => 
            [post_name] => assignment-1
            [to_ping] => 
            [pinged] => 
            [post_modified] => 2013-03-28 14:53:56
            [post_modified_gmt] => 2013-03-28 14:53:56
            [post_content_filtered] => 
            [post_parent] => 0
            [guid] => http://ssd.me/?p=1
            [menu_order] => 0
            [post_type] => homework
            [post_mime_type] => 
            [comment_count] => 3
            [filter] => raw
            [format_content] => 
        )
 
    [id] => 1
    [post_id] => 1
    [title] => Assignment 1
    [teacher_id] => 1
    [content] => This is the assignment...
    [required] => 1
    [due_date] => 2013-11-05
)
*/
?>

Why Use Wrapper Classes? Building a wrapper class for your CPT is a good idea for a few reasons:

  • put all of your code to register the CPT in one place.
  • put all of your code to register related taxonomies in one place.
  • build all of your CPT-related functionality as methods on the wrapper class.
  • code will read better.

Keep Your CPTs and Taxonomies Together Put all of your code to register the CPT and taxonomies in one place. Instead of having one block of code to register a CPT and define the taxonomies and a separate class wrapper to handle working with the CPT, you can simply place your CPT and taxonomy definitions into the class wrapper itself:

<?php
/*
    Class Wrapper for Homework CPT with Init Function
    /wp-content/plugins/ssd/classes/class.homework.php
*/
class Homework {
    //constructor can take a $post_id
    function __construct( $post_id = NULL ) {
        if ( !empty( $post_id ) )
            $this->getPost( $post_id );
    }
 
    //get the associated post and prepopulate some properties
    function getPost( $post_id ) {
        /* snipped */
    }
 
    //register CPT and Taxonomies on init
    function init() {
        //homework CPT
        register_post_type(
            'homework',
            array(
                'labels' => array(
                    'name' => __( 'Homework' ),
                    'singular_name' => __( 'Homework' )
                ),
                'public' => true,
                'has_archive' => true,
            )
        );
 
        //subject taxonomy
        register_taxonomy(
            'subject',
            'homework',
            array(
                'label' => __( 'Subjects' ),
                'rewrite' => array( 'slug' => 'subject' ),
                'hierarchical' => true
            )
        );
    }
 
 
 
//Adding methods to the Homework class
 
    /*
        Get related submissions.
        Set $force to true to force the method to get children again.
    */
    function getSubmissions( $force = false ) {
        //need a post ID to do this
        if ( empty( $this->id ) )
            return array();
 
        //did we get them already?
        if ( !empty( $this->submissions ) && !$force )
            return $this->submissions;
 
        //okay get submissions
        $this->submissions = get_children( array(
                'post_parent' => $this->id,
                'post_type' => 'submissions',
                'post_status' => 'published'
            ) );
 
        //make sure submissions is an array at least
        if ( empty( $this->submissions ) )
            $this->submissions = array();
 
        return $this->submissions;
    }
 
    /*
        Calculate a grade curve
    */
    function doFlatCurve( $maxscore = 100 ) {
        $this->getSubmissions();
 
        //figure out the highest score
        $highscore = 0;
        foreach ( $this->submissions as $submission ) {
            $highscore = max( $submission->score, $highscore );
        }
 
        //figure out the curve
        $curve = $maxscore - $highscore;
 
        //fix lower scores
        foreach ( $this->submissions as $submission ) {
            update_post_meta(
                $submission->ID,
                "score",
                min( $maxscore, $submission->score + $curve )
            );
        }
    }
}
 
//run the Homework init on init
add_action( 'init', array( 'Homework', 'init' ) );
?>

Wrapper Classes Read Better In addition to organizing code to make things easier to find, working with wrapper classes also makes code easier to read and understand. With fully wrapped Homework and Submission CPTs and special user classes, code like the following is possible:

<?php
//static function of Student class to check if the current user is a student
if ( Student::is_student() ) {
    //student defaults to current user
    $student = new Student();
 
    //let's figure out when their next assignment is due
    $assignment = $student->getNextAssignment();
 
    //display info and links
    if ( !empty( $assignment ) ) {
    ?>
    <p>Your next assignment
    <a href="<?php echo get_permalink( $assignment->id );?>">
    <?php echo $assignment->title;?></a>
    for the 
    <a href="<?php echo get_permalink( $assignment->class_id );?>">
    <?php echo $assignment->class->title;?></a>
    class is due on <?php echo $assignment->getDueDate();?>.</p>
    <?php
    }
}
?>
  • Filters: Basic filters, Child filters, Content filters, Form filters, Attribute filters, Visibility
  • Manipulating elements and content
  • Events and effects
  • The basics of a jQuery plugin
  • Top WordPress template tags

Basic filters:

jQuery(function(){
//all headers are selected, h1, h2, and so on
jQuery(":header").css("background", "#f60");
 
//all headers selected, except for headers in
list items
jQuery(":header:not(li :header)").css("background", "#f60");
jQuery("(":headers:not(li h2)").css("background", "#f60");
 
//orther examples
jQuery(".post img:not(.pIcon)").jqFn();
jQuery(".post:first").jqFn();
jQuery(".post:eq(0)").jqFn();
jQuery(".post:lt(2)")
.jqFn();
});

Child filters

jQuery(".linkcat li:nth-child(1)").css("background", "#f60");
jQuery(".linkcat li:first-child").css("background", "#f60");
//Filters down to the elements that are only-children of their parent
jQuery(".pagenav li:only-child").css("background", "#f60");
jQuery(".widget_meta li:nth-child(odd)").css("background", "#f60");

Content filters

jQuery(".post:has(.entry)")
.css("background", "#f60");
jQuery(".post:contains('Hello world')").css("background", "#f60");
//Filters down to elements that have no children. This includes text nodes.
jQuery(":empty')").css("background", "#f60");
jQuery(":parent')").css("background", "#f60");
jQuery(".widget-area li:has(h3:contains('Meta')) ul")
.css("background", "#f60");

Form filters

jQuery("form:input").css("background", "#f60");
jQuery("form:text").css("background", "#f60");
jQuery("form:password").css("background", "#f60");
jQuery("form:radio").css("background", "#f60");
jQuery("form:checkbox").css("background", "#f60");
jQuery("form:submit").css("background", "#f60");
jQuery("form:image").css("background", "#f60");
jQuery("form:file").css("background", "#f60");
jQuery("form:button").css("background", "#f60");
jQuery("form:reset").css("background", "#f60");

Attribute filters

jQuery("div [href]").css("background", "#f60");
jQuery("div [class!='entry']")
.css("background", "#f60");
//Filters for attributes that have a value that begins with a specific string
jQuery("div [href^='http://']")
.css("background", "#f60");
//ends with a specific string
jQuery("div [href$='/']")
.css("background", "#f60");
//contain a string
jQuery("div [href*='page_id']").css("background", "#f60");

Visibility

jQuery("form:input:hidden")
.css("background", "#f60");
jQuery("div .post:visible")
.css("background", "#f60");

Manipulating elements and content

jQuery(".post").append("<b>post ends here</b>");
jQuery("<b>post ends here</b>").appendTo(".post");
jQuery(".post").prepend("<b>post starts here</b>");
jQuery("<b>post starts here</b>").prependTo("
.post");
jQuery(".post").after("<b>This goes fter</b>");
jQuery("<b>This goes after</b>").insertAfter(".post");
jQuery(".post").before("<b>This goes efore</b>");
jQuery("<b>This goes before</b>").insertBefore("class");
jQuery(".post").wrap("<div class=".fun" />");
jQuery(".post").wrapAll("<div class=".fun"/>");
jQuery(".post").wrapInner("<div class=".fun" />");
jQuery(".post").html("<h2>Replacement Text</h2>");
jQuery(".post").text("Replacement Text");
jQuery(".post").remove();
jQuery(".post").clone();
 
//Working with the DOM
jQuery(".post").length;
jQuery(".post").get(3);
jQuery(".post").find(".entry b");
jQuery(".post").each(function(){
alert("one alert for each .post")
});

Events and effects: Helpers

jQuery(".post").click(function(){//code});
jQuery(".post").hover(function(){//code});
jQuery(".post").toggle(function(){//code});
//same for .mouseenter, .mouseleave, .dbclick, .keydown, .keyup
jQuery(".widget-area li ul li").hover(function(){
    jQuery(this).css("background", "#f60");
},
function(){
    jQuery(this).css("background", "none");
});
 
//Attaches a function to be triggered on a type of event to the selected elements.
jQuery(".post").bind("mouseenter", function(){//code});
 
jQuery(.post a).preventDefault();
jQuery(".post").css("background", "#f60").show("slow");
jQuery(".post").css("background", "#f60").show(200);
jQuery(".post").slideToggle('slow', function() {
    // code
});
jQuery(".post").animate({width: 200, opacity: .25}, 1000, function(){//code});
jQuery(".post").css("background", "#f60").hide().fadeIn("slow");

The basics of a jQuery plugin Note the bold .fn added to the jQuery object. This is what makes function a jQuery function. jQuery.fn.yourFunctionName = function() {//code}; jQuery fade in a child div plugin - loads data about author in popup.

//sets up the new plugin function: authorHover
jQuery.fn.authorHover = function(applyTo) {
//makes sure each item in the wrapper is run
return this.each(function(){
//if/else to determine if parameter has been passed
//no param, just looks for the child div
if(applyTo){
obj = applyTo
}else{
obj = "div";
}
//hides the child div or passed selector
jQuery(this).find(obj).hide();
//sets the main wrapper selection with a hover
jQuery(this).css("cursor", "pointer").hover(function(){
//restyles the child div or passed selector
// and fades it in
jQuery(this).find(obj).css("position","absolute")
.css("margin-top","-10px").css("margin-left","-10px")
.css("width","400px")
.css("border", "1px solid #666").fadeIn("slow");
}, function(){//fades out the child selector
jQuery(this).find(obj).fadeOut("slow");
});
});
};
/*All we have to do is embed new jQuery plugin named jquery.authover.js to theme, under the wp_enque_script call, below the
wp_head hook and evoke it with a simple script:*/
<script type="text/javascript">
jQuery(function(){
jQuery(".authorName").authorHover();
});
</script>
 
//Adding new jQuery plugin to WP plugin
add_action('init', 'addjQuery');
add_action('wp_head', 'addAuthorHover');
 
function addjQuery() {
wp_enqueue_script('authover',
WP_PLUGIN_URL . '/add_author_bio-tbs/jquery.authover.js',
array('jquery'), '1.4.2' );
}
 
function addAuthorHover(){
echo '<script type="text/javascript">
jQuery(function(){
jQuery(".authorName").authorHover();
});
</script>';
}

Examples

jQuery(function(){
jQuery(".post h2").hover(function(){
jQuery(this).effect('shake', 200);
}, function(){
jQuery(this).effect('shake', 200);
});
});
 
//Color animation with jQuery UI
jQuery(".post h2").hover(function(){
jQuery(this).animate({'backgroundColor':'#ccccff'}, 2000,
'easeOutBack');
}, function(){
jQuery(this).animate({'backgroundColor': '#999999'}, 2000,
'easeOutBack');
});
 
/*Implementing tabs entirely with jQuery - instead of pages in menus*/
//add in a ul list on the About page only, before the first h3
jQuery("#post-104 h3:first").before("<ul></ul>");
//select the ul, the h3's AND the h3's p tags
//and wrap them in a new div
//use the .add() function to make sure everything is selected
jQuery("#post-104 ul").add("#post-104 h3")
.add("#post-104 h3+p").wrapAll("<div id='aboutUs'></div>");
//for EACH h3 item:
jQuery("#post-104 h3").each(function(i){
//add text to the ul list w/ anchor links
var titleTxt = jQuery(this).text();
var htmlTxt = "<li>
<a href='#name-"+i+"'>"+titleTxt+"</a></li>";
jQuery("#post-104 ul").append(htmlTxt);
//wrap each h3 AND p in a div with anchor names
//this time, use .andSelf to make sure everything is selected
jQuery(this).next("p").andSelf()
.wrapAll("<div id='name-"+i+"'></div>");
});
//remove .entry class so list items don't have right quotes
//this is a list style in the default theme
jQuery("#post-104 .entry").removeClass('entry');
//Last, create the tabs widget
jQuery("#post-104 #aboutUs").tabs();

Top WordPress template tags

bloginfo('name');
wp_title('——',true,'');
the_title('<h2>', '</h2>');
the_content('more_link_text', strip_teaser, 'more_file');
the_category(', ');
the_author_meta();
wp_list_pages('title_li=');
wp_nav_menu( array('menu' => 'Main Nav' ));
next_post_link('<strong>%title</strong>');
previous_post_link('<strong>%title</strong>');
comments_number('no responses','one response', '% responses');
comments_popup_link('Add Your Thoughts');
edit_post_link('edit','<p>','</p>');
the_permalink();
the_ID();
wp_get_archives('type=monthly');
get_calendar(false);

Столкнулся на собеседованиях с подобными вопросами, решил вспомнить все ;)

  • Абстрактные классы
  • Интерфейсы
  • Отличия Абстрактные классы и Интерфейсы
  • Трейты

Абстрактные классы Класс, который содержит по крайней мере один абстрактный метод, должен быть определен как абстрактный. Следует помнить, что нельзя создать экземпляр абстрактного класса. Методы, объявленные абстрактными, несут, по существу, лишь описательный смысл и не могут включать реализации (метод должен быть определён в дочернем классе)

<?php
abstract class AbstractClass
{
   /* Данный метод должен быть определён в дочернем классе */
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);
 
   /* Общий метод */
    public function printOut() {
        print $this->getValue() . "\n";
    }
}
 
class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }
 
    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }
}
 
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";

Интерфейсы объектов позволяют создавать код, который указывает, какие методы и свойства должен включать класс, без необходимости описывания их функционала. Тела методов интерфейсов должны быть пустыми. Все методы, определенные в интерфейсы должны быть публичными, что следует из самой природы интерфейса. Могут содержать константы, константы перекрывать нельзя

<?php
interface a
{
    public function foo();
}
 
interface b extends a
{
    public function baz(Baz $baz);
}
 
// Это сработает
class c implements b
{
    public function foo()
    {
    }
 
    public function baz(Baz $baz)
    {
    }
}
 
// Это не сработает и выдаст фатальную ошибку
class d implements b
{
    public function foo()
    {
    }
 
    public function baz(Foo $foo)
    {
    }
}
?>
//коррктный вариант interface c extends a, b

Отличия Абстрактных классов и интерфейсов:

Abstract Class Interface
Абстрактные методы нужно указывать явно с помощью ключевого слова abstract Все методы являются абстрактными
Абстрактные методы можно объявлять с идентификаторами доступа (public, protected, private). При реализации в классе-потомке методы должны иметь такой же модификатор или менее ограниченный Все методы публичные
Может содержать методы с реализацией, поля члены данных, константы. Может содержать константы
В силу отсутствия множественного наследования, класс может наследовать только один абстрактный класс. Класс может наследовать много интерфейсов

Трейты - механизм обеспечения повторного использования кода , предназначены для уменьшения некоторых ограничений единого наследования, позволяя повторно использовать наборы методов свободно, в нескольких независимых классах и реализованных с использованием разных архитектур построения классов. Трейт очень похож на класс, но предназначен для групирования функционала хорошо структурированым и последовательным образом. Невозможно создать самостоятельный экземпляр трейта.

<?php
trait ezcReflectionReturnInfo {
    function getReturnType() { /*1*/ }
    function getReturnDescription() { /*2*/ }
}
 
class ezcReflectionMethod extends ReflectionMethod {
    use ezcReflectionReturnInfo;
    /* ... */
}
 
class ezcReflectionFunction extends ReflectionFunction {
    use ezcReflectionReturnInfo;
    /* ... */
}
?>

Наследуемый член из базового класса переопределяется членом, находящимся в трейте. Порядок приоритета следующий: члены из текущего класса переопределяют методы в трейте, которые в свою очередь переопределяют унаследованные методы.

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}
 
trait World {
    public function sayWorld() {
        echo 'World';
    }
}
 
class MyHelloWorld {
    use Hello, World;
    public function sayExclamationMark() {
        echo '!';
    }
}
 
$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

Just preparing for the test on ANSI SQL, gathered all statements together.

  • SELECT
  • INSERT
  • UPDATE
  • CREATE
  • GRANT
  • ANY, IN, SOME, ALL
  • LIKE
SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...]
    [FROM table_references
    [WHERE where_condition]
    [GROUP BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [HAVING where_condition]
    [ORDER BY {col_name | expr | position}
      [ASC | DESC], ...]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [PROCEDURE procedure_name(argument_list)]
    [INTO OUTFILE 'file_name' export_options
      | INTO DUMPFILE 'file_name'
      | INTO var_name [, var_name]]
    [FOR UPDATE | LOCK IN SHARE MODE]]
 
SELECT t1.name, t2.salary FROM employee AS t1, info AS t2
  WHERE t1.name = t2.name;
 
SELECT t1.name, t2.salary FROM employee t1, info t2
  WHERE t1.name = t2.name;
SELECT college, region, seed FROM tournament
  ORDER BY 2, 3;
SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;

INSERT - 3 ways

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION (partition_name,...)] 
    [(col_name,...)]
    {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]
 
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION (partition_name,...)]
    SET col_name={expr | DEFAULT}, ...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]
 
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION (partition_name,...)] 
    [(col_name,...)]
    SELECT ...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]
 
INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
insert into Citylist (cityname) VALUES ('St. John\'s')
 
INSERT INTO t2 (b, c)
VALUES ((SELECT a FROM t1 WHERE b='Chip'), 'shoulder'),
((SELECT a FROM t1 WHERE b='Chip'), 'old block'),
((SELECT a FROM t1 WHERE b='John'), 'toilet'),
((SELECT a FROM t1 WHERE b='John'), 'long,silver'),
((SELECT a FROM t1 WHERE b='John'), 'li''l');
UPDATE [LOW_PRIORITY] [IGNORE] table_reference
    SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]
 
//examples
UPDATE t1 SET col1 = col1 + 1, col2 = col1;
UPDATE items,month SET items.price=month.price
WHERE items.id=month.id;

CREATE

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    [(create_definition,...)]
    [table_options]
    select_statement
 
create_definition:
    col_name column_definition
  | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...)
        [index_type]
  | {INDEX|KEY} [index_name] [index_type] (index_col_name,...)
        [index_type]
  | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY]
        [index_name] [index_type] (index_col_name,...)
        [index_type]
  | {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...)
        [index_type]
  | [CONSTRAINT [symbol]] FOREIGN KEY
        [index_name] (index_col_name,...) reference_definition
  | CHECK (expr)
 
column_definition:
    data_type [NOT NULL | NULL] [DEFAULT default_value]
      [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY]
      [COMMENT 'string'] [reference_definition]
 
CREATE TABLE IF NOT EXISTS `s chema`.`Employee` (
`idEmployee` V ARCHAR(45) NOT NULL ,
`Name` V ARCHAR(255) NULL ,
`idAddresses` V ARCHAR(45) NULL ,
PRIMARY KEY (`idEmployee`) ,
CONSTRAINT `fkEmployee_Addresses`
FOREIGN KEY `fkEmployee_Addresses` (`idAddresses`)
REFERENCES `s chema`.`Addresses` (`idAddresses`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin
GRANT
    priv_type [(column_list)]
      [, priv_type [(column_list)]] ...
    ON [object_type] priv_level
    TO user_specification [, user_specification] ...
    [REQUIRE {NONE | ssl_option [[AND] ssl_option] ...}]
    [WITH with_option ...]
 
CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';
GRANT ALL ON db1.* TO 'jeffrey'@'localhost';
GRANT SELECT ON db2.invoice TO 'jeffrey'@'localhost';
GRANT USAGE ON *.* TO 'jeffrey'@'localhost' WITH MAX_QUERIES_PER_HOUR 90;
GRANT ALL ON *.* TO 'someuser'@'somehost';
GRANT SELECT, INSERT ON *.* TO 'someuser'@'somehost';
 
GRANT ALL ON mydb.* TO 'someuser'@'somehost';
GRANT SELECT, INSERT ON mydb.* TO 'someuser'@'somehost';
GRANT SELECT (col1), INSERT (col1,col2) ON mydb.mytbl TO 'someuser'@'somehost';
operand comparison_operator ANY (subquery)
operand IN (subquery)
operand comparison_operator SOME (subquery)
 
SELECT s1 FROM t1 WHERE s1 > ANY ( SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 = ANY ( SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN    ( SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 <> ANY  ( SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 <> SOME ( SELECT s1 FROM t2);
 
/*ALL, which must follow a comparison operator, means return TRUE if the comparison is TRUE for ALL of the values in the column that the subquery returns.*/
SELECT s1 FROM t1 WHERE s1 > ALL ( SELECT s1 FROM t2);
SELECT * FROM t1 WHERE 1 > ALL ( SELECT MAX(s1) FROM t2);
 
//same expressions
SELECT s1 FROM t1 WHERE s1 <> ALL ( SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 NOT IN ( SELECT s1 FROM t2);

LIKE - SQL pattern matching enables you to use '_' to match any single character and '%' to match an arbitrary number of characters

SELECT * FROM pet WHERE name LIKE 'b%';
SELECT * FROM pet WHERE name LIKE '_____';//contain 5 chars
SELECT * FROM pet WHERE name REGEXP '^b';//beginning with “b”
CV

Objective

A position as a Web developer that enables me to demonstrate my ability to learn on the job

Technology Summary

  • Languages/Programming: PHP, Yii framework, AJAX, jQuery, Node.js, JavaScript, Bootstrap, CMS WordPress, Python, HTML, CSS, Git, machine learning
  • DB: MySQL, MongoDB

Professional Experience

09/2013 - Ongoing
Freelance Web Programmer PHP, Javascript, MySQL

  • Design & Development applications using Yii framework
  • Web sites & services development (CMS Word Press)
  • Page Makeup (primarily bootstrap)
  • Working with MySQL database
  • Support
  • Copywriting

01/2012- Ongoing
Freelance PM NGOs

  • Coordination teams (up to 30 people)
  • Training Team (up to 20 people)
  • Event Management (courses, seminars, conferences, strategic planning meetings)
  • Facilitation
  • Copywriting
  • SMM
  • Lobby Campaigns (human rights)
  • Team Building
  • Medical Service
  • Journalist (investigative journalism and analytics)

01/2008-10/2012
Programmer accounting software

  • Development and maintenance of software for workflow, reports for Revenue Service etc
  • Support security systems and video surveillance
  • Workflow: design, development from scratch (and support)
  • Made year reports as an accountant

Education

2013-2013 Academy «SMART» Website developer with Yii framework

2005-2006 Kharkiv National University named after V.N. Karazin Programmer, systems analyst, administrator (the diploma with distinction)

1999-2003 National Technical University "Kharkiv Polytechnic Institute" Computer Science (bachelor's degree)

1997-1999 The State Statistics Committee (Kharkov Regional Training Centre) Accountant - economist

CERTIFICATES (recent)

  • MongoDB for Node.js developers
  • Virology I: How viruses work
  • Maps and the Geospatial Revolution
  • Competitive Strategy
  • Algorithmes: Design and Analyses
  • Internet History, Technology and Security
  • Introduction to Data Science
  • Machine Learning
  • Introduction to interactive programming in Python
  • Cryptography
  • The Changing Global Order
  • Risk Management

ADDITIONAL INFORMATION

  • English Upper-Intermediate
  • Love sports - primarily snowboarding and freeskating

Hobbies

  • Machine learning
  • Big data problems, Data Science
  • Games programing (back end)
  • Human Rights movement
  • No-Confl ict Mode in WordPress
  • A Proper Way to Include Scripts
  • Plugin Ajax Read More
  • Plugin Front Delete Comment

No-Confl ict Mode in WordPress use one of these solutions: Write jQuery( ) instead of each $( ) || Use a jQuery wrapper.

//1
jQuery(‘.something).each( function(){
jQuery(this).addClass(stuff);
});
jQuery.data( document.body, ‘foo’, 1337 );
 
// jQuery noConflict wrapper:
(function($) {
// $() will work here
$(‘.something).each( function(){
$(this).addClass(stuff);
});
$.data( document.body, ‘foo’, 1337 );
})(jQuery);

AJAX example: Read More

<?php
/*
Plugin Name: Ajax Read More
Plugin URI: http://example.com/
Description: Ajaxify the "Read more" links
Version: 1.0
*/
 
// Flag to state if the script is needed
global $ssd_arm_needjs;
$ssd_arm_needjs = false;
 
// Plugin version, bump it up if you update the plugin
define( 'ssd_ARM_VERSION', '1.0' );
 
// Enqueue the script, in the footer
add_action( 'template_redirect', 'ssd_arm_add_js' );
function ssd_arm_add_js() {
 
    // Enqueue the script
    wp_enqueue_script( 'ssd_arm',
        plugin_dir_url( __FILE__ ).'js/script.js',
        array('jquery'), ssd_ARM_VERSION, true
    );
 
    // Get current page protocol
    $protocol = isset( $_SERVER["HTTPS"]) ? 'https://' : 'http://';
 
    // Output admin-ajax.php URL with same protocol as current page
    $params = array(
      'ajaxurl' => admin_url( 'admin-ajax.php', $protocol )
    );
    wp_localize_script( 'ssd_arm', 'ssd_arm', $params );
}
 
// Don't add the script if actually not needed
add_action( 'wp_print_footer_scripts', 'ssd_arm_footer_maybe_remove', 1 );
function ssd_arm_footer_maybe_remove() {
    global $ssd_arm_needjs;
    if( !$ssd_arm_needjs ) {
        wp_deregister_script( 'ssd_arm' );
    }
}
 
// Inspect each post to check if there's a "read more" tag
add_action( 'the_post', 'ssd_arm_check_readmore' );
function ssd_arm_check_readmore( $post ) {
    if ( preg_match('/<!--more(.*?)?-->/', $post->post_content )
    && !is_single() ) {
        global $ssd_arm_needjs; 
        $ssd_arm_needjs = true;
    }
}
 
// Ajax handler
add_action('wp_ajax_nopriv_ssd_arm_ajax', 'ssd_arm_ajax');
add_action('wp_ajax_ssd_arm_ajax', 'ssd_arm_ajax');
function ssd_arm_ajax() {
    // Modify the way WP gets post content
    add_filter( 'the_content', 'ssd_arm_get_2nd_half' );
 
    // setup Query
    query_posts( 'p='.absint( $_REQUEST['post_id'] ) );
 
    // "The Loop"
    if ( have_posts() ) : while ( have_posts() ) : the_post();
        the_content();
    endwhile; else:
        echo "post not found :/";
    endif;
 
    // reset Query
    wp_reset_query();
    die();
}
 
// Get second part of a post after the "more" jump
function ssd_arm_get_2nd_half( $content ) {
    $id = absint( $_REQUEST['post_id'] );
    $content = preg_replace( "!^.*<span id=\"more-$id\"></span>!s", '', $content );
    return $content;
}
 
 
//JS code
if( typeof(console) == 'object' ) {
    console.log( 'script loaded' );
}
 
(function($) {
    $('.more-link').click(function(){
        var link = this;
        $(link).html('loading...');
        // href="' . get_permalink() . "#more-{$post->ID}"
        var post_id = $(link).attr('href').replace(/^.*#more-/, '');
        var data = {
            action: 'ssd_arm_ajax',
            post_id: post_id
        };
        $.get(ssd_arm.ajaxurl, data, function(data){
            $(link).after(data).remove();
        });
        return false;
    });
})(jQuery);

A Proper Way to Include Scripts

<?php
/*
Plugin Name: Add JavaScript
Plugin URI: http://example.com/
Description: Demonstrates how to properly insert JS into different pages
*/
 
// URL to the /js directory of the plugin
define( 'ssd_INSERTJS', plugin_dir_url( __FILE__).'js' );
 
// Add new admin pages
add_action('admin_menu', 'ssd_insertjs_add_page');
function ssd_insertjs_add_page() {
    // Add JS to all the admin pages
    wp_enqueue_script( 'ssd_insertjs_1', ssd_INSERTJS.'/script.js.php?where=admin' );
 
    // Add a page under Settings
    $settings = add_options_page( 'Insert JS', 'Insert JS', 'manage_options',
        'ssd_insertjs_settings', 'ssd_insertjs_options_page'
    );
 
    // Add JS to the setting page
    add_action( 'load-'.$settings, 'ssd_insertjs_add_settings_script' );
 
    // Add a page under Users
    $users = add_users_page( 'Insert JS', 'Insert JS', 'manage_options',
        'ssd_insertjs_users', 'ssd_insertjs_users_page'
    );
 
    // Add JS to the users page, with a different hook
    add_action( 'admin_print_scripts-'.$users, 'ssd_insertjs_add_users_script' );
}
 
// Add JS to the plugin's settings page
function ssd_insertjs_add_settings_script() {
    wp_enqueue_script( 'ssd_insertjs_2', ssd_INSERTJS.'/script.js.php?where=settings' );
}
 
// Add JS to the plugin's users page, in the page footer
function ssd_insertjs_add_users_script() {
    wp_enqueue_script( 'ssd_insertjs_3', ssd_INSERTJS.'/script.js.php?where=users',
        '', '', true
    );
}
 
// Add JS to the Comments page
add_action( 'load-edit-comments.php', 'ssd_insertjs_on_comments' );
function ssd_insertjs_on_comments() {
    wp_enqueue_script( 'ssd_insertjs_4', ssd_INSERTJS.'/script.js.php?where=comments' );
}
 
 
// Add JS to pages of the blog
add_action( 'template_redirect', 'ssd_insertjs_add_scripts_blog' );
function ssd_insertjs_add_scripts_blog() {
    // To all pages of the blog
    wp_enqueue_script( 'ssd_insertjs_5', ssd_INSERTJS.'/script.js.php?where=blog' );
 
    // To single post pages
    if( is_single() ) {
        wp_enqueue_script( 'ssd_insertjs_6', ssd_INSERTJS.'/script.js.php?where=single' );
    }
 
    // To the "About" page
    if( is_page('About') ) {
        wp_enqueue_script( 'ssd_insertjs_7', ssd_INSERTJS.'/script.js.php?where=about' );
    }
}
 
 
// Draw options page
function ssd_insertjs_options_page() {
    ?>
    <div class="wrap">
    <?php screen_icon(); ?>
    <h2>Insert JavaScript</h2>
 
    <?php
    var_dump( plugin_basename( dirname(__FILE__) ) );
    var_dump( plugin_dir_url( __FILE__) );
    ?>
 
    <p>This sample plugin selectively adds different JS to the following pages:</p>
    <ol>
        <li>Admin part:
        <ol>
            <li>This very page</li>
            <li>This plugin page under the Users menu</li>
            <li>The Comments page</li>
        </ol></li>
        <li>Blog part:
        <ol>
            <li>All blog pages</li>
            <li>Single post pages</li>
        </ol></li>
    </ol>
    </div>
    <?php
}
 
// Draw users page
function ssd_insertjs_users_page() {
    ?>
    <div class="wrap">
    <?php screen_icon(); ?>
    <h2>Insert JavaScript</h2>
    <p>This is another sample page. Here, the JS is added in the footer (view page source).</p>
    </div>
    <?php
}
 
//code JS
<?php
// Send proper header for the browser
header('Content-type: application/javascript');
 
// Get context to display appropriate notice
$page = isset( $_GET['where'] ) ? $_GET['where'] : '' ;
 
switch( $page ) {
    // admin pages:
    case 'admin':
        $context = "all admin pages";
        break;
 
    case 'settings':
        $context = "plugin settings page";
        break;
 
    case 'users':
        $context = "plugin users page";
        break;
 
    case 'comments':
        $context = "comments page";
        break;
 
    // public pages:
    case 'single':
        $context = "blog single pages";
        break;
 
    case 'about':
        $context = "About page";
        break;
 
    case 'blog':
        $context = "all blog pages";
        break;
}
 
?>
 
// Now javascript part, here a simple alert
alert( 'This script should only load in: <?php echo $context; ?>' );

You now know that using wp_enqueue_script() you can elect to insert your script in the document header or at the end of the document body. In the Head - page elements may not be available to the script because they are not loaded yet, typically include libraries and function defi nitions that can then be used later in the page. Near the Footer - effective if you need to include a third - party script that can potentially slow down or halt the rendering of your page while it loads and executes. In the Page Content - do smth if if the post contains the appropriate shortcode. Inline

Frontend Comment Deletion

<?php
/*
Plugin Name: Instant Delete Comment
Plugin URI: http://example.com/
Description: Add a quick link to instantly delete comments
*/
 
// Add script on single post & pages with comments only, if user has edit rights
add_action( 'template_redirect', 'ssd_idc_addjs_ifcomments' );
function ssd_idc_addjs_ifcomments() {
    if( is_single() && current_user_can( 'moderate_comments' ) ) {
        global $post;
        if( $post->comment_count ) {
            $path = plugin_dir_url( __FILE__ );
 
            wp_enqueue_script( 'ssd_idc', $path.'js/script.js' );
            $protocol = isset( $_SERVER["HTTPS"]) ? 'https://' : 'http://';
            $params = array(
              'ajaxurl' => admin_url( 'admin-ajax.php', $protocol )
            );
            wp_localize_script( 'ssd_idc', 'ssd_idc', $params );
        }
    }
}
 
// Add an admin link to each comment
add_filter( 'comment_text', 'ssd_idc_add_link' );
function ssd_idc_add_link( $text ) {
    // Get current comment ID
    global $comment;
    $comment_id = $comment->comment_ID;
 
    // Get link to admin page to trash comment, and add nonces to it
    $link = admin_url( 'comment.php?action=trash&c='.$comment_id );
    $link = wp_nonce_url( $link, 'ssd_idc-delete-'.$comment_id );
    $link = "<a href='$link' class='ssd_idc_link'>delete comment</a>";
 
    // Append link to comment text
    return $text."<p>[admin: $link]</p>";
}
 
// Ajax handler
add_action( 'wp_ajax_ssd_idc_ajax_delete', 'ssd_idc_ajax_delete' );
function ssd_idc_ajax_delete() {
    $cid = absint( $_POST['cid'] );
 
    $response = new WP_Ajax_Response;
 
    if(
        current_user_can( 'moderate_comments' ) &&
        check_ajax_referer( 'ssd_idc-delete-'.$cid, 'nonce', false ) &&
        wp_delete_comment( $cid  )
    ) {
        // Request successful
        $response->add( array(
            'data' => 'success',
            'supplemental' => array(
                'cid'     => $cid,
                'message' => 'this comment has been deleted'
            ),
        ) );
    } else {
        // Request failed
        $response->add( array(
            'data' => 'error',
            'supplemental' => array(
                'cid'     => $cid,
                'message' => 'an error occured'
            ),
        ) );
    }
 
    $response->send();
 
    exit();
}
 
//code JS - script.js
jQuery(document).ready(function($) {
 
    $('.ssd_idc_link').click(function(){
        var link = this;
        // get comment id and nonce
        var href = $(link).attr( 'href' );
        var id =    href.replace(/^.*c=(\d+).*$/, '$1');
        var nonce = href.replace(/^.*_wpnonce=([a-z0-9]+).*$/, '$1');
 
        var data = {
            action: 'ssd_idc_ajax_delete',
            cid: id,
            nonce: nonce
        }
 
        $.post( ssd_idc.ajaxurl, data, function(data){
            var status  = $(data).find('response_data').text();
            var message = $(data).find('supplemental message').text();
            if( status == 'success' ) {
                $(link).parent().after( '<p><b>'+message+'</b></p>' ).remove();
            } else {
                alert( message );
            }
        });
 
        return false;
 
    });
 
});
  • Custom post types
  • Post metadata
  • Custom taxonomies

Registering the Music Album Post Type

<?php
/*
Plugin Name: Music Collection Post Types
Plugin URI: http://example.com
Description: Creates the music_album post type.
Version: 0.1
*/
 
/* Set up the post types. */
add_action( 'init', 'ssd_music_collection_register_post_types' );
 
/* Registers post types. */
function ssd_music_collection_register_post_types() {
 
    /* Set up the arguments for the 'music_album' post type. */
    $album_args = array(
        'public' => true,
        'query_var' => 'music_album',
        'rewrite' => array(
            'slug' => 'music/albums',
            'with_front' => false,
        ),
        'supports' => array(
            'title',
            'thumbnail'
        ),
        'labels' => array(
            'name' => 'Albums',
            'singular_name' => 'Album',
            'add_new' => 'Add New Album',
            'add_new_item' => 'Add New Album',
            'edit_item' => 'Edit Album',
            'new_item' => 'New Album',
            'view_item' => 'View Album',
            'search_items' => 'Search Albums',
            'not_found' => 'No Albums Found',
            'not_found_in_trash' => 'No Albums Found In Trash'
        ),
    );
 
    /* Register the music album post type. */
    register_post_type( 'music_album', $album_args );
}
 
?>

Registering new taxonomies: Genre and Artist After you add the preceding code, you ’ ll be presented with two new submenu items under the Albums menu item in the admin, labeled Artists and Genres.

<?php
 
/* Set up the taxonomies. */
add_action( 'init', 'ssd_music_collection_register_taxonomies' );
 
/* Registers taxonomies. */
function ssd_music_collection_register_taxonomies() {
 
    /* Set up the artist taxonomy arguments. */
    $artist_args = array(
        'hierarchical' => false,
        'query_var' => 'album_artist', 
        'show_tagcloud' => true,
        'rewrite' => array(
            'slug' => 'music/artists',
            'with_front' => false
        ),
        'labels' => array(
            'name' => 'Artists',
            'singular_name' => 'Artist',
            'edit_item' => 'Edit Artist',
            'update_item' => 'Update Artist',
            'add_new_item' => 'Add New Artist',
            'new_item_name' => 'New Artist Name',
            'all_items' => 'All Artists',
            'search_items' => 'Search Artists',
            'popular_items' => 'Popular Artists',
            'separate_items_with_commas' => 'Separate artists with commas',
            'add_or_remove_items' => 'Add or remove artists',
            'choose_from_most_used' => 'Choose from the most popular artists',
        ),
    );
 
    /* Set up the genre taxonomy arguments. */
    $genre_args = array(
        'hierarchical' => true,
        'query_var' => 'album_genre', 
        'show_tagcloud' => true,
        'rewrite' => array(
            'slug' => 'music/genres',
            'with_front' => false
        ),
        'labels' => array(
            'name' => 'Genres',
            'singular_name' => 'Genre',
            'edit_item' => 'Edit Genre',
            'update_item' => 'Update Genre',
            'add_new_item' => 'Add New Genre',
            'new_item_name' => 'New Genre Name',
            'all_items' => 'All Genres',
            'search_items' => 'Search Genres',
            'parent_item' => 'Parent Genre',
            'parent_item_colon' => 'Parent Genre:',
        ),
    );
 
    /* Register the album artist taxonomy. */
    register_taxonomy( 'album_artist', array( 'music_album' ), $artist_args );
 
    /* Register the album genre taxonomy. */
    register_taxonomy( 'album_genre', array( 'music_album' ), $genre_args );
}
 
?>

Using a Taxonomy with Posts When using taxonomy with posts, you ’ ll generally be listing the taxonomy terms for the given post alongside some or all the content of the post. This would allow viewers to note there is a taxonomy for the post and allow them to fi nd related posts by a given taxonomy term.

<?php
 
add_action( 'init', 'ssd_music_album_register_shortcodes' );
 
function ssd_music_album_register_shortcodes() {
 
    /* Register the [music_albums] shortcode. */
    add_shortcode( 'music_albums', 'ssd_music_albums_shortcode' );
}
 
function ssd_music_albums_shortcode() {
 
    /* Query albums from the database. */
    $loop = new WP_Query(
        array(
            'post_type' => 'music_album',
            'orderby' => 'title',
            'order' => 'ASC',
            'posts_per_page' => -1,
        )
    );
 
    /* Check if any albums were returned. */
    if ( $loop->have_posts() ) {
 
        /* Open an unordered list. */
        $output = '<ul class="music-collection">';
 
        /* Loop through the albums (The Loop). */
        while ( $loop->have_posts() ) {
 
            $loop->the_post();
 
            /* Display the album title. */
            $output .= the_title(
                '<li><a href="' . get_permalink() . '">',
                '</a></li>',
                false
            );
 
        }
 
        /* Close the unordered list. */
        $output .= '</ul>';
    }
 
    /* If no albums were found. */
    else {
        $output = '<p>No albums have been published.';
    }
 
    /* Return the music albums list. */
    return $output;
}
 
?>

A POST TYPE AND TAXONOMY PLUGIN It enables users to create new music albums and organize the albums by genre and artist.

  • The fi rst step you take is creating a new fi le in your plugins directory named ssd-music-collection.php and adding your plugin header at the top of this fi le.
  • The next step is to create the music_album post type, which was outlined in the Registering a Post Type section.
  • The fi nal step of the process is creating the taxonomies for the music_album post type: album_artist and album_genre. How to register a taxonomy was covered in the Registering a Custom Taxonomy section.
  • At this point, you have entire plugin with minimal code that creates and organizes a new type of content within WordPress. All that ’ s left is adding widgets , creating shortcodes, ...

Go to page: