Skip to content

Instantly share code, notes, and snippets.

@Bunkerbewohner
Last active January 17, 2017 12:49
Show Gist options
  • Save Bunkerbewohner/a12ba5c19f3bc1f339a18fa52efeb0cb to your computer and use it in GitHub Desktop.
Save Bunkerbewohner/a12ba5c19f3bc1f339a18fa52efeb0cb to your computer and use it in GitHub Desktop.
<?php
/*
Plugin Name: List Posts with Custom Field
Plugin URI: http://www.christianschenk.org/projects/wordpress-list-posts-custom-field-plugin/
Description: Inserts a list of posts with a certain custom field.
Version: 1.9.4
Author: Christian Schenk
Author URI: http://www.christianschenk.org/
*/
#
# WordPress List Posts with Custom Field Plugin
# Copyright (C) 2007-2014 Christian Schenk
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
#
# Constants
#
define('LPCF_PLACEHOLDER_PERMALINK', '%PERMALINK%');
/**
* Finds posts that have a certain custom field attached and displays their
* title and excerpt in a HTML description list.
*
* Options:
* field: the custom field we're searching for
* orderby: colum of the posts table for "ORDER BY"
* order: ASC or DESC
* titlefield: uses another custom field for the title
* excerptfield: uses another custom field for the excerpt
* titleprefix, titlesuffix: string before or after the title
* excerptprefix, excerptsuffix: string before or after the excerpt
* category: posts have to belong to at least one of the given categories
* having: the posts/pages found need a field with the given value
* having_delim: delimiter for the having clause (delim for key / value)
* having_delim2: delimiter for the having clause (delim for multiple fields)
* having_conj: conjunction for the elements in the having clause (AND or OR)
* limit: lets you limit the number of results shown
*
* Note: field, titlefield and excerptfield may be a comma separated list.
*/
function lpcf_shortcode($atts) {
global $wpdb;
extract(shortcode_atts(array('field' => '',
'orderby' => 'post_date',
'order' => 'DESC',
'titlefield' => '',
'excerptfield' => '',
'titleprefix' => '<a href="'.LPCF_PLACEHOLDER_PERMALINK.'">',
'titlesuffix' => '</a>',
'excerptprefix' => '',
'excerptsuffix' => '',
'display' => '',
'showlinks' => true,
'split' => false,
'category' => null,
'having' => '',
'having_delim' => ',',
'having_delim2' => '|',
'having_conj' => 'OR',
'daterange' => 'all',
'limit' => ''), $atts));
# sanity checks
if (strlen(trim($field)) == 0)
return '<strong>'.__('No custom field found. Add it to the shortcode.', 'lpcf').'</strong>';
if (strpos($field, ',') !== false)
$fields = explode(',', $field);
$order = strtolower($order);
if ($order != 'asc' and $order != 'desc')
return '<strong>'.__('Invalid order. Use "ASC" or "DESC".', 'lpcf').'</strong>';
$titlefields = explode(',', $titlefield);
$excerptfields = explode(',', $excerptfield);
# extract categories
if ( !empty($category) ) {
$category = explode(',', $category);
$tmpCategory = array();
foreach ($category as $cat)
if ( is_numeric($cat) )
$tmpCategory[] = $cat;
$category = $tmpCategory;
}
# make sure that the user did not choose the having delimiters in a way
# that conflicts with the default values
if ($having_delim == $having_delim2)
return '<strong>'.__('Having delimiters must be different.', 'lpcf').'</strong>';
# extract "having" custom fields and values
if (strpos($having, $having_delim) !== false) {
# split multiple key / value pairs
if (strpos($having, $having_delim2) !== false)
$having = explode($having_delim2, $having);
else
$having = array($having); # insert single key / value pair in array
# split all keys from their values
foreach ($having as $key => $value) {
if (strpos($value, $having_delim) === false) continue;
$having[$key] = explode($having_delim, $value);
}
}
# make sure that the having conjunction is either "and" or "or"
$having_conj = strtolower($having_conj);
if ($having_conj != 'and' and $having_conj != 'or')
return '<strong>'.__('Having conjunction must be either "and" or "or".', 'lpcf').'</strong>';
# cater for multiple custom fields
$meta_key_sql = '';
if ( isset($fields) ) {
for ($i = 0, $n = count($fields); $i < $n; $i++) {
$meta_key_sql .= 'm.meta_key = "'.$fields[$i].'"';
if ($i != $n - 1) $meta_key_sql .= ' OR ';
}
} else {
$meta_key_sql = 'm.meta_key = "'.$field.'"';
}
# orderby for SQL
$orderbysql = (strpos($orderby, 'cfvalue') === false) ? $orderby : 'post_date';
# retrieve posts
$sql = 'SELECT DISTINCT p.ID, p.post_title AS title, p.post_excerpt AS excerpt, p.post_date AS date
FROM '.$wpdb->posts.' AS p, '.$wpdb->postmeta.' AS m
WHERE p.ID = m.post_id AND ('.$meta_key_sql.') AND p.post_status = "publish"
ORDER BY p.'.$orderbysql.' '.$order;
$result = $wpdb->get_results($sql);
if (empty($result)) return '<!--'.__('No posts found for these custom fields.', 'lpcf').'-->';
# make sure that the posts belong to at least one of the given categories
if ( !empty($category) ) {
$tmpResult = array();
for ($i = 0, $n = count($result); $i < $n; $i++) {
$post = $result[$i];
foreach ($category as $cat)
if (lpcf_assert_category($post->ID, $cat) === true) {
$tmpResult[] = $post;
break;
}
}
$result = $tmpResult;
}
# split the posts according to their custom fields
if ($split == true and strpos($orderby, 'cfvalue') !== false) {
$tmpResult = array();
lpcf_get_cfvalue($orderby, $result, false);
foreach ($result as $post) {
if (empty($post->cfvalue)) {
$tmpResult[] = $post;
continue;
}
foreach ($post->cfvalue as $curField) {
# PHP 4 compat, since "$tmpPost = clone $post" doesn't work.
$tmpPost =& new lpcf_post();
$tmpPost->ID = $post->ID;
$tmpPost->title = $post->title;
$tmpPost->excerpt = $post->excerpt;
$tmpPost->date = $post->date;
$tmpPost->cfvalue = $curField;
$tmpResult[] = $tmpPost;
}
}
$result = $tmpResult;
}
# set correct title/excerpt
for ($i = 0, $n = count($result); $i < $n; $i++) {
$post = $result[$i];
# set title to cfvalue, the given title fields or the default
if ( $split == true and !empty($post->cfvalue) )
$title = $post->cfvalue;
else
$title = lpcf_get_custom_field($post->ID, $titlefields, $post->title);
# sort multiple custom fields alphabetically in ascending order by default
if (is_array($title))
sort($title);
$result[$i]->title = lpcf_concat_array($title, $titleprefix, $titlesuffix);
if (strpos($result[$i]->title, LPCF_PLACEHOLDER_PERMALINK) !== false)
$result[$i]->title = str_replace(LPCF_PLACEHOLDER_PERMALINK, get_permalink($post->ID), $result[$i]->title);
$excerpt = lpcf_get_custom_field($post->ID, $excerptfields, $post->excerpt);
$result[$i]->excerpt = lpcf_concat_array($excerpt, $excerptprefix, $excerptsuffix);
}
# sort
if ($orderby == 'post_title') {
usort($result, 'lpcf_compare_title');
} else if (strpos($orderby, 'cfvalue') !== false) {
# prepare cfvalue
if ($split == false) lpcf_get_cfvalue($orderby, $result);
foreach ($result as $post)
if ( is_array($post->cfvalue) )
$post->cfvalue = empty($post->cfvalue[0]) == false ? $post->cfvalue[0] : '';
usort($result, 'lpcf_compare_cfvalue');
}
if ($order == 'desc')
$result = array_reverse($result);
#
# OUTPUT
#
$rVal .= "<dl>\n";
for ($i = 0, $output_items = 0, $n = count($result); $i < $n; $i++) {
$post = $result[$i];
# make sure that the post has the following fields set to the given value
if (!empty($having)) {
$having_skip = array();
# compare the values of the keys with each other
foreach ($having as $having_pair) {
$having_pair_key = $having_pair[0];
$having_pair_value = $having_pair[1];
$havingFields = get_post_meta($post->ID, $having_pair_key, false);
# compare the values with each other
foreach ($havingFields as $havingField)
if ($havingField == $having_pair_value)
$having_skip[] = false;
}
# Evaluate the skip condition
if (
# Empty array -> nothing matched
( empty($having_skip) ) OR
# Conjunction AND
# -> there must be as many "false" entries in the skip array as there are custom fields
( $having_conj == 'and' and count($having_skip) != count($having) ) OR
# Conjunction OR
# -> there must be at least one "false" entry in the skip array
( $having_conj == 'or' and !in_array(false, $having_skip) )
)
continue;
}
# only display elements until the limit is reached
if (!empty($limit) and $output_items >= $limit) break;
# make sure the date is correct
# TODO
# get EM_Event instance for this event (see /classes/em-event.php)
$event = em_get_event($post->ID, "post_id");
# get date using placeholder (see http://wp-events-plugin.com/documentation/placeholders/)
$date = $event->output("#_EVENTDATES")
# output
$rVal .= '<dt>'.$post->title."</dt>\n".
"<dd><time>$date</time><span>$post->excerpt</span></dd>\n";
$output_items++;
}
$rVal .= "</dl>\n";
return $rVal;
}
if (function_exists('add_shortcode')) {
add_shortcode('lp', 'lpcf_shortcode');
add_shortcode('list-posts', 'lpcf_shortcode');
}
/**
* PHP 4 compat
*/
class lpcf_post {
var $ID;
var $title;
var $excerpt;
var $date;
var $cfvalue;
}
/**
* Fetches the value for the custom fields that should be used during the
* sorting algorithm.
*/
function lpcf_get_cfvalue($orderby, &$result, $single = true) {
$cfkey = substr($orderby, strpos($orderby, ':') + 1, strlen($orderby));
for ($i = 0, $n = count($result); $i < $n; $i++) {
$post = $result[$i];
$result[$i]->cfvalue = get_post_meta($post->ID, $cfkey, $single);
}
}
/**
* Walks through all the given keys and checks whether the given post has a
* custom field with this particular key. If it does, the value gets returned,
* otherwise the default value will be used.
*
* Note that the order matters since we'll return the value of the first custom
* field that we find.
*/
function lpcf_get_custom_field($postId, $keys, $default) {
if (empty($keys) or !is_array($keys)) return $default;
foreach ($keys as $key) {
if (empty($key)) continue;
$meta = get_post_meta($postId, $key, false);
if (!empty($meta)) return $meta;
}
return $default;
}
/**
* Compares the title field.
*/
function lpcf_compare_title($a, $b) {
return strcmp($a->title, $b->title);
}
/**
* Compares the value of a custom field
*/
function lpcf_compare_cfvalue($a, $b) {
return strcmp($a->cfvalue, $b->cfvalue) * -1;
}
/**
* Concatenates the elements of an array.
*/
function lpcf_concat_array($array, $prefix, $suffix) {
if (!is_array($array))
return $prefix . $array . $suffix;
$concat = '';
foreach ($array as $elem)
$concat .= $prefix . $elem . $suffix;
return $concat;
}
/**
* Returns true if the given post belongs to the given category.
*/
function lpcf_assert_category($postId, $categoryId) {
if ( !is_numeric($postId) or !is_numeric($categoryId) ) return true;
global $wpdb;
$sql = 'SELECT count(object_id) FROM '.$wpdb->term_relationships.' WHERE object_id = '.$postId.' AND term_taxonomy_id = '.$categoryId;
$result = $wpdb->get_var($sql);
if (empty($result))
return false;
return true;
}
## FILE ENDS HERE ###
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment