Skip to content

Instantly share code, notes, and snippets.

@felipelavinz
Created March 17, 2011 19:04
Show Gist options
  • Save felipelavinz/874920 to your computer and use it in GitHub Desktop.
Save felipelavinz/874920 to your computer and use it in GitHub Desktop.
Abstract class for dealing with common tasks over WordPress post objects
<?php
/**
* Basically, a posts objects iterator
* @author Felipe Lavín Z. <felipe@yukei.net>
**/
abstract class av_post_objects{
public $id;
public $meta;
public $type;
public $i = 0;
public $params;
public $query;
function __construct($args=null){
$s = wp_parse_args($args, array(
'loop_wrap' => 'div',
'loop_class' => '',
'loop_id' => '',
'loop_elements' => 'div',
'elements_class' => '',
'is_hatom' => false, // if set to true, add hatom classes
'postmeta' => false, // name of a post_meta key that would be used in each post
'echo' => true
));
$s = array_merge($s, $this->defaults);
$this->params = (object)$s;
$this->id = get_class($this);
}
/**
* Register post type
**/
abstract function register_type();
/**
* Get post objects
* @param array $args Array or query string of arguments
* @return object WP_Query object
**/
function get($args=null){
$s = wp_parse_args( (array)$args, (array)$this->params );
// set this to a class variable, so we can have access to the WP_Query properties
$this->query = new WP_Query( $s );
return $this->query;
}
/**
* The "view" method should be implemented by each extending class
* Format item output for each of the query results
* @param $post A $post object
* @args $args
* @return string Item output
**/
abstract function view($post=null, $args=null);
/**
* Loop should handle all objects retrieving and looping
* and let the view method handle the display of each item
* Class constructors can define the wrapping and other presentational
* attributes that should be applied on the loop
**/
function loop($objects=null, $view=null){
global $post;
$the_post = $post;
if ( !$objects ) $objects = $this->get();
$out = '';
if ( $objects->have_posts() ) {
apply_filters('pre_'. $this->id .'_loop', &$out, $objects);
$out .= '<'. $this->params->loop_wrap . $this->get_wrap_classes($this->params->loop_class) . (( $this->params->loop_id ) ?' id="'. esc_attr($this->params->loop_id) .'"' : '' ) .'>';
// here there should be a variable-name action, passing $objects as argument
// do_action ...
apply_filters('start_'. $this->id .'_loop', &$out, $objects);
while ( $objects->have_posts() ) {
$objects->the_post(); $this->meta = null;
$this->meta = $this->get_meta($post);
// here there should be a variable-name action, passing the post as argument
// do_action...
// perhaps this should be captured in an output buffer, just to make sure
// that the view action it's not echoing, instead of returning
$out .= '<'. $this->params->loop_elements . $this->get_item_classes($this->params->item_class) .' id="'. esc_attr($post->post_name) .'">';
$out .= !is_null($view) && is_callable($view) ? call_user_func($view) : $this->view();
$out .= '</'. $this->params->loop_elements .'>';
$this->i++;
}
apply_filters('end_'. $this->id .'_loop', &$out, $objects);
$out .= '</'. $this->params->loop_wrap .'>';
apply_filters('post_'. $this->id .'_loop', &$out, $objects);
wp_reset_query();
$post = $the_post;
// here there shoud be a variable-name action, so we can do stuff such as removing query filters
} else {
$out .= '<p>'. __('No posts have been found') .'</p>';
}
if ( $this->params->echo ) echo $out;
else return $out;
}
public function get_meta($post=null){
if ( is_null($post) ) global $post;
if ( $this->params->postmeta ) {
if ( is_string($this->params->postmeta) ) {
$meta = get_post_meta($post->ID, $this->params->postmeta, true);
$this->meta = $post->meta = $meta ? $meta : null;
} elseif ( is_array($this->params->postmeta) ) {
$this->meta = $post->meta = $this->get_meta_arr();
}
}
}
/**
* Fetch various meta fields and set them to $this->meta so we can access
* them in the posts loop
* @param array $metas List of meta keys to fetch
* @return array Associative array with meta keys as keys and values as values
**/
public function get_meta_arr( $metas = null ){
global $wpdb, $post; $out = new stdClass;
if ( is_null($metas) ) $metas = $this->params->postmeta;
// If metas is an associative array, we'll use our custom names as keys
if ( $this->is_associative($metas) ) {
$assoc = true;
$names2keys = array_flip($metas);
}
// Prepare meta keys for query
array_walk($metas, array($this, 'prepare_meta_keys'));
(array)$meta_values = $wpdb->get_results("SELECT meta_key, meta_value FROM $wpdb->postmeta WHERE post_id = $post->ID AND meta_key IN(". implode(',', (array)$metas) .")");
if ( $assoc ) {
$out = $this->map_meta_keys($meta_values, $names2keys);
} else {
foreach ( $meta_values as $m ) {
$out->{$m->meta_key} = maybe_unserialize($m->meta_value);
}
}
return $out;
}
/**
* Map meta_keys and meta_values to our custom meta names
* @param array $values DDBB Query results
* @param array $names2keys Associative array with meta keys as keys and our custom names as values
* @return array Associative array with custom keys
**/
private function map_meta_keys($values, $names2keys){
$out = new stdClass;
foreach ( $values as $v ) {
$out->$names2keys[$v->meta_key] = maybe_unserialize($v->meta_value);
}
return $out;
}
/**
* Add slashes to array keys so they won't be mistaken for columns
* @param arr $key The array that's checked
* @return void Return by reference
* */
private function prepare_meta_keys(&$key){
$key = "'$key'";
}
/**
* Check if it's an associative array
* @param array $arr The array that will be tested
* @return boolean True if assocative, false if numeric
* */
private function is_associative($arr){
return !ctype_digit( implode('', array_keys($arr)) );
}
public function get_item_classes($custom=null){
$out = ' class="'. $this->params->post_type .'-entry';
$out .= ( $this->i%2 ) ? ' odd' : ' even';
if ( $this->i === 0 ) $out .= ' first';
if ( $this->i === ( $this->query->found_posts - 1 ) ) $out .= ' last';
if ( $custom ) $out .= ' '. esc_attr($custom);
if ( $this->params->hatom ) $out .= ' hentry';
$out .= '"';
return $out;
}
public function get_wrap_classes($custom=null){
$out = ' class="'. $this->params->post_type .'-loop';
if ( $custom ) $out .= ' '. esc_attr($custom);
if ( $this->params->hatom ) $out .= ' hfeed';
$out .= '"';
return $out;
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment