I really need a comprehensive solution to this, so I’m offering up almost a quarter of my rep in bounty 🙂
I would like to have a plugin that creates a custom category listing on my home page. To do this, I’d like the “Category Edit” screen to be augmented with some additional functions as described below…
- Adds “Upload/Delete Image” handler to the Category Edit Screen for a Given Category (this allows the end user to upload an image that will be used to represent the category. Ideally, it should automatically be resized to 125 pixels wide by the plugin when uploaded.
- Adds “Category Title” input field to the Category Edit Screen for a Given Category. This is in addition to the existing default “Name” field.
- Adds a checkbox titled “Show on homepage listing” to allow selective display of each category on the home page listing.
- When the home page is viewed, the plugin appends the_content with the custom category listing, including each category’s custom thumbnail and title.
The resulting markup should be an unordered list with no nesting, like so…
<ul class="custom-categories">
<li>
<span><a href="https://wordpress.stackexchange.com/questions/5955/link-to-category-1"><img src="the-category-1-image" /></a></span>
<a href="https://wordpress.stackexchange.com/questions/5955/link-to-category-1">Category 1 Title</a> The category description text goes here
</li>
<li>
<span><a href="link-to-category-2"><img src="the-category-2-image" /></a></span>
<a href="link-to-category-2">Category 2 Title</a> The category description text goes here
</li>
etc...
</ul>
Here’s a stub file I’ve started…
add_filter( 'the_content', 'cb_category_listing' );
function cb_category_listing( $content )
{
if ( is_home() ) {
$cat_args['title_li'] = '';
$cat_args['exclude_tree'] = 1;
$cat_args['exclude'] = 1;
$myContent = wp_list_categories(apply_filters('widget_categories_args', $cat_args));
$content .= $myContent;
}
return $content;
}
Note: This is for older versions of WP < 3.9 prior to the new media upload being introduced
Here’s how to add fields and save the values on the category edit screen as well as a method of adding an image upload field.
Adding fields to category edit screen
To start we need to get some code showing up on the category edit screen.
add_action( 'edit_category_form_fields', 'my_category_custom_fields' );
add_action( 'edit_category', 'save_my_category_custom_fields' );
function my_category_custom_fields( $tag ) {
// your custom field HTML will go here
// the $tag variable is a taxonomy term object with properties like $tag->name, $tag->term_id etc...
// we need to know the values of our existing entries if any
$category_meta = get_option( 'category_meta' );
?>
<tr class="form-field">
<th scope="row" valign="top"><label for="category-title"><?php _e("Title"); ?></label></th>
<td>
<input id="category-title" name="category_meta[<?php echo $tag->term_id ?>]Category listing with thumbnail and description on home page" value="<?php if ( isset( $category_meta[ $tag->term_id ] ) ) esc_attr_e( $category_meta[ $tag->term_id ]['title'] ); ?>" />
<span class="description"><?php _e('Enter an alternative title for this category.'); ?></span>
</td>
</tr>
<!-- rinse & repeat for other fields you need -->
<?php
}
The simplest way to store our custom values is in the options table (there should be a taxonomy-meta table really but never mind). This way we only need to make one query to get the meta data for all of our categories. If anyone has a better idea for storage then speak up!
function save_my_category_custom_fields() {
if ( isset( $_POST['category_meta'] ) && !update_option('category_meta', $_POST['category_meta']) )
add_option('category_meta', $_POST['category_meta']);
}
For a checkbox you’re simply storing true or false so you’d use category_extras[$tag->term_id][show_on_home]
for the name attribute and use the value stored in $category_meta
to determine if it’s checked or not.
You may want to add some extra processing or sanitisation to the save function – mine is just a quick n dirty example.
The image field
This is a fair bit of code and quite complicated so I won’t explain it all here but the comments describe the purpose of each function. We can discuss in the comments if you want to.
The following functions add a link to the category edit screen which brings up the wordpress media library/image upload popup. You can then upload a picture and click to use it. You’ll then have the image ID and thumbnail url available to you with the other meta above.
// add the image size you need
add_image_size( 'category_thumb', 125, 125, true );
// setup our image field and handling methods
function setup_category_image_handling() {
// add the image field to the rest
add_action( 'edit_category_form_fields', 'category_image' );
global $pagenow;
if ( is_admin() ) {
add_action( 'admin_init', 'fix_async_upload_image' );
if ( 'edit-tags.php' == $pagenow ) {
add_thickbox();
add_action('admin_print_footer_scripts', 'category_image_send_script', 1000);
} elseif ( 'media-upload.php' == $pagenow || 'async-upload.php' == $pagenow ) {
add_filter( 'media_send_to_editor', 'category_image_send_to_editor', 1, 8 );
add_filter( 'gettext', 'category_image_replace_text_in_thickbox', 1, 3 );
}
}
}
add_action( 'admin_init', 'setup_category_image_handling' );
// the taxonomy edit screen image field
function category_image( $tag ) {
// get our category meta data
$category_meta = get_option('category_meta');
?>
<tr class="form-field hide-if-no-js">
<th scope="row" valign="top"><label for="taxonomy-image"><?php _e("Image"); ?></label></th>
<td>
<div id="taxonomy-image-holder">
<?php if( !empty($category_meta[$tag->term_id]['image']) ) { ?>
<img style="max-width:100%;display:block;" src="https://wordpress.stackexchange.com/questions/5955/<?php echo esc_attr( $category_meta[ $tag->term_id ]["image']['thumb'] ); ?>" alt="" />
<a id="taxonomy-image-select" class="thickbox" href="media-upload.php?is_term=true&type=image&TB_iframe=1"><?php _e('Change image'); ?></a>
<a class="deletion" id="taxonomy-image-remove" href="#remove-image">Remove image</a>
<?php } else { ?>
<a id="taxonomy-image-select" class="thickbox" href="media-upload.php?is_term=true&type=image&TB_iframe=1"><?php _e('Choose an image'); ?></a>
<?php } ?>
</div>
<input type="hidden" name="category_meta[<?php echo $tag->term_id ?>][image][id]" value="<?php if( isset($category_meta[ $tag->term_id ]['image']['id']) ) echo esc_attr($category_meta[ $tag->term_id ]['image']['id']); ?>" class="tax-image-id" />
<input type="hidden" name="category_meta[<?php echo $tag->term_id ?>][image][thumb]" value="<?php if( isset($category_meta[ $tag->term_id ]['image']['thumb']) ) echo esc_attr($category_meta[ $tag->term_id ]['image']['thumb']); ?>" class="tax-image-thumb" />
<span class="description"><?php _e('A category image.'); ?></span></td>
</tr>
<?php
}
// required for uploading images on non post/page screens
function fix_async_upload_image() {
if(isset($_REQUEST['attachment_id'])) {
$GLOBALS['post'] = get_post($_REQUEST['attachment_id']);
}
}
// are we dealing with the taxonomy edit screen?
function is_category_context() {
if ( isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'],'is_term') !== false ) {
return true;
} elseif ( isset($_REQUEST['_wp_http_referer']) && strpos($_REQUEST['_wp_http_referer'],'is_term') !== false ) {
return true;
} elseif ( isset($_REQUEST['is_term']) && $_REQUEST['is_term'] !== false ) {
return true;
}
return false;
}
// replace Insert Into Post text with something more appropriate
function category_image_replace_text_in_thickbox($translated_text, $source_text, $domain) {
if ( is_category_context() ) {
if ('Insert into Post' == $source_text) {
return __('Use this image', MB_DOM );
}
}
return $translated_text;
}
// output a script that sets variables on the window object so that they can be accessed elsewhere
function category_image_send_to_editor( $html, $id, $attachment ) {
// context check might not be necessary, and, might not work in all cases
if ( is_category_context() ) {
$item = get_post($id);
$src = wp_get_attachment_image_src($id,'thumbnail',true); // 0 = url, 1 = width, 2 = height, 3 = icon(bool)
?>
<script type="text/javascript">
// send image variables back to opener
var win = window.dialogArguments || opener || parent || top;
win.TI.id = <?php echo $id ?>;
win.TI.thumb = '<?php echo $src[0]; ?>';
</script>
<?php
}
return $html;
}
// write out the javascript that handles what happens when a user clicks to use an image
function category_image_send_script() { ?>
<script>
self.TI = {};
var tb_position;
function send_to_editor(h) {
// ignore content returned from media uploader and use variables passed to window instead
jQuery('.tax-image-id').val( self.TI.id );
jQuery('.tax-image-thumb').val( self.TI.thumb );
// display image
jQuery('#taxonomy-image-holder img, #taxonomy-image-remove').remove();
jQuery('#taxonomy-image-holder')
.prepend('<img style="max-width:100%;display:block;" src="'+ self.TI.thumb +'" alt="" />')
.append('<a class="deletion" id="taxonomy-image-remove" href="#remove-image">Remove image</a>');
jQuery('#taxonomy-image-select').html('Change image');
// close thickbox
tb_remove();
}
(function($){
$(document).ready(function() {
tb_position = function() {
var tbWindow = $('#TB_window'), width = $(window).width(), H = $(window).height(), W = ( 720 < width ) ? 720 : width;
if ( tbWindow.size() ) {
tbWindow.width( W - 50 ).height( H - 45 );
$('#TB_iframeContent').width( W - 50 ).height( H - 75 );
tbWindow.css({'margin-left': '-' + parseInt((( W - 50 ) / 2),10) + 'px'});
if ( typeof document.body.style.maxWidth != 'undefined' )
tbWindow.css({'top':'20px','margin-top':'0'});
};
return $('a.thickbox').each( function() {
var href = $(this).attr('href');
if ( ! href ) return;
href = href.replace(/&width=[0-9]+/g, '');
href = href.replace(/&height=[0-9]+/g, '');
$(this).attr( 'href', href + '&width=" + ( W - 80 ) + "&height=" + ( H - 85 ) );
});
};
$(window).resize(function(){ tb_position(); });
$("#taxonomy-image-select').click(function(event){
tb_show("Choose an image:", $(this).attr("href"), false);
return false;
});
$('#taxonomy-image-remove').live('click',function(event){
$('#taxonomy-image-select').html('Choose an image');
$('#taxonomy-image-holder img').remove();
$('input[class^="tax-image"]').val("");
$(this).remove();
return false;
});
});
})(jQuery);
</script>
<?php
}
Accessing the information
In your my_function
bit taken from your own answer you would then access the metadata like so:
function my_function(){
$args=array(
'orderby' => 'name',
'order' => 'ASC'
);
$categories=get_categories($args);
// get our category meta data and exit out if there isn't any
$category_meta = get_option('category_meta');
if ( !$category_meta )
return;
echo '<ul style="list-style-type:none;margin:0;padding:0">';
foreach($categories as $category) {
// skip unticked categories & categories with no meta data
if ( !isset( $category_meta[ $category->term_id ] ) || ( isset( $category_meta[ $category->term_id ] ) && !$category_meta[ $category->term_id ]['show_on_home'] ) )
continue;
echo '<li><a style="display:block;margin-top:20px;" href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $category->name ) . '" ' . '>' . $category_meta[ $category->term_id ]['title'].'</a>';
if ( "" != $category_meta[ $category->term_id ]['image']['id'] )
echo wp_get_attachment_image( $category_meta[ $category->term_id ]['image']['id'], 'category_thumbnail', false, array( 'alt' => $category->name, 'class' => '' ) );
echo $category->description . '</li>';
}
echo '</ul>';
}