Lots of minor styling upgrades
[dss-plugins:ryanhellyers-dss-framework.git] / functions.php
1 <?php
2 /**
3  * DSS Framework functions and definitions
4  *
5  * @package WordPress
6  * @subpackage DSS_Framework
7  * @since DSS Framework 1.0
8  */
9
10
11 /**
12  * Set the content width based on the theme's design and stylesheet.
13  */
14 if ( ! isset( $content_width ) )
15         $content_width = 584;
16
17 /**
18  * Definitions
19  */
20 define( 'DSS_READ_MORE_LENGTH', 50 );
21
22 /**
23  * Sets up theme defaults and registers support for various WordPress features.
24  *
25  * Note that this function is hooked into the after_setup_theme hook, which runs
26  * before the init hook. The init hook is too late for some features, such as indicating
27  * support post thumbnails.
28  *
29  * To override dss_setup() in a child theme, add your own dss_setup to your child theme's
30  * functions.php file.
31  *
32  * @uses load_theme_textdomain() For translation/localization support.
33  * @uses add_editor_style() To style the visual editor.
34  * @uses add_theme_support() To add support for post thumbnails, automatic feed links, custom headers
35  *      and backgrounds, and post formats.
36  * @uses register_nav_menus() To add support for navigation menus.
37  * @uses register_default_headers() To register the default custom header images provided with the theme.
38  * @uses set_post_thumbnail_size() To set a custom post thumbnail size.
39  *
40  * Note: This function is modified from the Twenty Eleven theme
41  *
42  * @since DSS Framework 1.0
43  * @author Ryan Hellyer <ryan@metronet.no>
44  */
45 function dss_setup() {
46
47         /* Make DSS Framework available for translation.
48          * Translations can be added to the /languages/ directory.
49          * If you're building a theme based on DSS Framework, use a find and replace
50          * to change 'dss' to the name of your theme in all the template files.
51          */
52         load_theme_textdomain( 'dss', get_template_directory() . '/languages' );
53
54         // This theme styles the visual editor with editor-style.css to match the theme style.
55         add_editor_style();
56
57         // Load up our theme options page and related code.
58         require( get_template_directory() . '/inc/theme-options.php' );
59
60         // Grab DSS Framework's Ephemera widget.
61         require( get_template_directory() . '/inc/widgets.php' );
62
63         // Add default posts and comments RSS feed links to <head>.
64         add_theme_support( 'automatic-feed-links' );
65
66         // This theme uses wp_nav_menu() in one location.
67         register_nav_menu( 'primary', __( 'Primary Menu', 'dss' ) );
68
69         // Add support for a variety of post formats
70         add_theme_support( 'post-formats', array( 'aside', 'link', 'gallery', 'status', 'quote', 'image' ) );
71
72         // This theme uses Featured Images (also known as post thumbnails) for per-post/per-page Custom Header images
73         add_theme_support( 'post-thumbnails' );
74
75         // Add support for custom headers.
76         $custom_header_support = array(
77                 // The default header text color.
78                 'default-text-color' => '000',
79                 // The height and width of our custom header.
80                 'width' => apply_filters( 'dss_header_image_width', 1000 ),
81                 'height' => apply_filters( 'dss_header_image_height', 288 ),
82                 'header-text' => false, 
83                 // Support flexible heights.
84                 'flex-height' => true,
85                 // Random image rotation by default.
86                 'random-default' => false,
87                 // Callback for styling the header preview in the admin.
88                 'admin-head-callback' => 'dss_admin_header_style',
89                 // Callback used to display the header preview in the admin.
90                 'admin-preview-callback' => 'dss_admin_header_image',
91         );
92
93         add_theme_support( 'custom-header', $custom_header_support );
94
95         // We'll be using post thumbnails for custom header images on posts and pages.
96         // We want them to be the size of the header image that we just defined
97         // Larger images will be auto-cropped to fit, smaller ones will be ignored. See header.php.
98         set_post_thumbnail_size( $custom_header_support['width'], $custom_header_support['height'], true );
99
100         // Add DSS Framework's custom image sizes.
101         // Used for large feature (header) images.
102         add_image_size( 'large-feature', $custom_header_support['width'], $custom_header_support['height'], true );
103         // Used for featured posts if a large-feature doesn't exist.
104         add_image_size( 'small-feature', 500, 300 );
105         // Used for post thumbnails
106         add_image_size( 'single-post-thumbnail', 135, 135, true );
107
108         // Default custom headers packaged with the theme. %s is a placeholder for the theme template directory URI.
109         register_default_headers( array(
110                 'chessboard' => array(
111                         'url'           => '%s/images/headers/chessboard.jpg',
112                         'thumbnail_url' => '%s/images/headers/chessboard-thumbnail.jpg',
113                         'description'   => __( 'Chessboard', 'dss' )
114                 ),
115                 'health' => array(
116                         'url'           => '%s/images/headers/health.jpg',
117                         'thumbnail_url' => '%s/images/headers/health-thumbnail.jpg',
118                         'description'   => __( 'Health', 'dss' )
119                 ),
120         ) );
121 }
122 add_action( 'after_setup_theme', 'dss_setup' );
123
124 if ( ! function_exists( 'dss_admin_header_style' ) ) :
125 /**
126  * Styles the header image displayed on the Appearance > Header admin panel.
127  *
128  * Referenced via add_theme_support('custom-header') in dss_setup().
129  *
130  * Note: This function is modified from the Twenty Eleven theme
131  *
132  * @since DSS Framework 1.0
133  * @author Ryan Hellyer <ryan@metronet.no>
134  */
135 function dss_admin_header_style() {
136 ?>
137         <style type="text/css">
138         .appearance_page_custom-header #headimg {
139                 border: none;
140         }
141         #headimg h1,
142         #desc {
143                 font-family: "Helvetica Neue", Arial, Helvetica, "Nimbus Sans L", sans-serif;
144         }
145         #headimg h1 {
146                 margin: 0;
147         }
148         #headimg h1 a {
149                 font-size: 32px;
150                 line-height: 36px;
151                 text-decoration: none;
152         }
153         #desc {
154                 font-size: 14px;
155                 line-height: 23px;
156                 padding: 0 0 3em;
157         }
158         <?php
159                 // If the user has set a custom color for the text use that
160                 if ( get_header_textcolor() != HEADER_TEXTCOLOR ) :
161         ?>
162                 #site-title a,
163                 #site-description {
164                         color: #<?php echo get_header_textcolor(); ?>;
165                 }
166         <?php endif; ?>
167         #headimg img {
168                 max-width: 1000px;
169                 height: auto;
170                 width: 100%;
171         }
172         </style>
173 <?php
174 }
175 endif; // dss_admin_header_style
176
177 if ( ! function_exists( 'dss_admin_header_image' ) ) :
178 /**
179  * Custom header image markup displayed on the Appearance > Header admin panel.
180  *
181  * Referenced via add_theme_support('custom-header') in dss_setup().
182  *
183  * Note: This function is modified from the Twenty Eleven theme
184  *
185  * @since DSS Framework 1.0
186  * @author Ryan Hellyer <ryan@metronet.no>
187  */
188 function dss_admin_header_image() { ?>
189         <div id="headimg">
190                 <?php
191                 $color = get_header_textcolor();
192                 $image = get_header_image();
193                 if ( $color && $color != 'blank' )
194                         $style = ' style="color:#' . $color . '"';
195                 else
196                         $style = ' style="display:none"';
197                 ?>
198                 <h1><a id="name"<?php echo $style; ?> onclick="return false;" href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php bloginfo( 'name' ); ?></a></h1>
199                 <div id="desc"<?php echo $style; ?>><?php bloginfo( 'description' ); ?></div>
200                 <?php if ( $image ) : ?>
201                         <img src="<?php echo esc_url( $image ); ?>" alt="" />
202                 <?php endif; ?>
203         </div>
204 <?php }
205 endif; // dss_admin_header_image
206
207 /**
208  * Limit the number of characters shown in the excerpt
209  * Adds read more link to excerpt
210  *
211  * @since DSS Framework 1.0
212  * @author Ryan Hellyer <ryan@metronet.no>
213  */
214 function dss_limit_excerpt( $excerpt ) {
215         $excerpt = preg_replace( " (\[.*?\])", '', $excerpt );
216         $excerpt = strip_shortcodes( $excerpt );
217         $excerpt = strip_tags( $excerpt );
218         $excerpt = substr( $excerpt, 0, DSS_READ_MORE_LENGTH );
219         $excerpt = substr( $excerpt, 0, strripos( $excerpt, ' ' ) );
220         $excerpt = trim( preg_replace( '/\s+/', ' ', $excerpt ) );
221         $excerpt .= ' &hellip; <a href="'. esc_url( get_permalink() ) . '">' . __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'dss' ) . '</a>';
222
223         return $excerpt;
224 }
225 add_filter( 'wp_trim_excerpt', 'dss_limit_excerpt' );
226
227 /**
228  * Get our wp_nav_menu() fallback, wp_page_menu(), to show a home link.
229  */
230 function dss_page_menu_args( $args ) {
231         $args['show_home'] = true;
232         return $args;
233 }
234 add_filter( 'wp_page_menu_args', 'dss_page_menu_args' );
235
236 /**
237  * Register our sidebars and widgetized areas. Also register the default Epherma widget.
238  *
239  * Note: This function is modified from the Twenty Eleven theme
240  *
241  * @since DSS Framework 1.0
242  * @author Ryan Hellyer <ryan@metronet.no>
243  */
244 function dss_widgets_init() {
245
246         register_widget( 'DSS_Framework_Ephemera_Widget' );
247
248         register_sidebar( array(
249                 'name' => __( 'Main Sidebar', 'dss' ),
250                 'id' => 'sidebar-1',
251                 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
252                 'after_widget' => "</aside>",
253                 'before_title' => '<h3 class="widget-title">',
254                 'after_title' => '</h3>',
255         ) );
256
257         register_sidebar( array(
258                 'name' => __( 'Footer Area One', 'dss' ),
259                 'id' => 'sidebar-3',
260                 'description' => __( 'An optional widget area for your site footer', 'dss' ),
261                 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
262                 'after_widget' => "</aside>",
263                 'before_title' => '<h3 class="widget-title">',
264                 'after_title' => '</h3>',
265         ) );
266
267         register_sidebar( array(
268                 'name' => __( 'Footer Area Two', 'dss' ),
269                 'id' => 'sidebar-4',
270                 'description' => __( 'An optional widget area for your site footer', 'dss' ),
271                 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
272                 'after_widget' => "</aside>",
273                 'before_title' => '<h3 class="widget-title">',
274                 'after_title' => '</h3>',
275         ) );
276
277         register_sidebar( array(
278                 'name' => __( 'Footer Area Three', 'dss' ),
279                 'id' => 'sidebar-5',
280                 'description' => __( 'An optional widget area for your site footer', 'dss' ),
281                 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
282                 'after_widget' => "</aside>",
283                 'before_title' => '<h3 class="widget-title">',
284                 'after_title' => '</h3>',
285         ) );
286 }
287 add_action( 'widgets_init', 'dss_widgets_init' );
288
289 if ( ! function_exists( 'dss_content_nav' ) ) :
290 /**
291  * Display navigation to next/previous pages when applicable
292  * 
293  * Note: This function is modified from the Twenty Eleven theme
294  *
295  * @since DSS Framework 1.0
296  * @author Ryan Hellyer <ryan@metronet.no>
297  */
298 function dss_content_nav( $nav_id ) {
299         global $wp_query;
300
301         if ( $wp_query->max_num_pages > 1 ) : ?>
302                 <nav id="<?php echo $nav_id; ?>">
303                         <h3 class="assistive-text"><?php _e( 'Post navigation', 'dss' ); ?></h3>
304                         <ul id="numeric_pagination"><?php
305                                 // Load numeric pagination
306                                 dss_pagination();
307                         ?>
308                         </ul><!-- #numeric_pagination -->
309                 </nav><!-- #nav-above -->
310         <?php endif;
311 }
312 endif; // dss_content_nav
313
314 /*
315  * Pagination code
316  * @since 1.0
317  * Code developed from the excellent Genesis theme by StudioPress (http://studiopress.com/)
318  * 
319  * @since DSS Framework 1.0
320  * @author Ryan Hellyer <ryan@metronet.no>
321  */
322 function dss_pagination( $pages = '', $range = 2 ) {
323
324         // Beginning of numeric pagination
325         if( !is_singular() ) : // do nothing
326
327         global $wp_query;
328
329         // Stop execution if there\'s only 1 page
330         if( $wp_query->max_num_pages <= 1 ) return;
331
332         $paged = get_query_var( 'paged' ) ? absint( get_query_var( 'paged') ) : 1;
333         $max = intval( $wp_query->max_num_pages );
334
335         //      add current page to the array
336         if ( $paged >= 1 )
337                 $links[] = $paged;
338
339         //      add the pages around the current page to the array
340         if ( $paged >= 3 ) {
341                 $links[] = $paged - 1; $links[] = $paged - 2;
342         }
343         if ( ($paged + 2) <= $max ) { 
344                 $links[] = $paged + 2; $links[] = $paged + 1;
345         }
346
347         //      Previous Post Link
348         if ( get_previous_posts_link() )
349                 printf( '<li>%s</li>' . "\n", get_previous_posts_link( __( '&laquo; Previous', 'lassesuper') ) );
350
351         //      Link to first Page, plus ellipeses, if necessary
352         if ( !in_array( 1, $links ) ) {
353                 if ( $paged == 1 )
354                         $current = ' class="active"';
355                 else
356                         $current = null;
357                 printf(
358                         '<li %s><a href="%s">%s</a></li>' . "\n",
359                         $current,
360                         get_pagenum_link(1),
361                         '1'
362                 );
363
364                 if ( !in_array( 2, $links ) )
365                         echo '<li>&hellip;</li>';
366         }
367
368         //      Link to Current page, plus 2 pages in either direction (if necessary).
369         sort( $links );
370         foreach( (array)$links as $link ) {
371                 $current = ( $paged == $link ) ? 'class="active"' : '';
372                 printf(
373                         '<li %s><a href="%s">%s</a></li>' . "\n",
374                         $current,
375                         get_pagenum_link( $link ),
376                         $link
377                 );
378         }
379
380         //      Link to last Page, plus ellipses, if necessary
381         if ( !in_array( $max, $links ) ) {
382                 if ( !in_array( $max - 1, $links ) )
383                         echo '<li>&hellip;</li>' . "\n";
384                 
385                 $current = ( $paged == $max ) ? 'class="active"' : '';
386                 printf(
387                         '<li %s><a href="%s">%s</a></li>' . "\n",
388                         $current,
389                         get_pagenum_link( $max ),
390                         $max
391                 );
392         }
393
394         //      Next Post Link
395         if ( get_next_posts_link() )
396                 printf(
397                         '<li>%s</li>' . "\n",
398                         get_next_posts_link( __( 'Next &raquo;', 'lassesuper' ) ) );
399         endif;
400
401 }
402
403 /**
404  * Return the URL for the first link found in the post content.
405  *
406  * Note: This function is modified from the Twenty Eleven theme
407  *
408  * @since DSS Framework 1.0
409  * @author Ryan Hellyer <ryan@metronet.no>
410  * @return string|bool URL or false when no link is present.
411  */
412 function dss_url_grabber() {
413         if ( ! preg_match( '/<a\s[^>]*?href=[\'"](.+?)[\'"]/is', get_the_content(), $matches ) )
414                 return false;
415
416         return esc_url_raw( $matches[1] );
417 }
418
419 /**
420  * Count the number of footer sidebars to enable dynamic classes for the footer
421  * 
422  * Note: This function is modified from the Twenty Eleven theme
423  *
424  * @since DSS Framework 1.0
425  * @author Ryan Hellyer <ryan@metronet.no>
426  */
427 function dss_footer_sidebar_class() {
428         $count = 0;
429
430         if ( is_active_sidebar( 'sidebar-3' ) )
431                 $count++;
432
433         if ( is_active_sidebar( 'sidebar-4' ) )
434                 $count++;
435
436         if ( is_active_sidebar( 'sidebar-5' ) )
437                 $count++;
438
439         $class = '';
440
441         switch ( $count ) {
442                 case '1':
443                         $class = 'one';
444                         break;
445                 case '2':
446                         $class = 'two';
447                         break;
448                 case '3':
449                         $class = 'three';
450                         break;
451         }
452
453         if ( $class )
454                 echo 'class="' . $class . '"';
455 }
456
457 if ( ! function_exists( 'dss_comment' ) ) :
458 /**
459  * Template for comments and pingbacks.
460  *
461  * To override this walker in a child theme without modifying the comments template
462  * simply create your own dss_comment(), and that function will be used instead.
463  *
464  * Used as a callback by wp_list_comments() for displaying the comments.
465  *
466  * Note: This function is modified from the Twenty Eleven theme
467  *
468  * @since DSS Framework 1.0
469  * @author Ryan Hellyer <ryan@metronet.no>
470  */
471 function dss_comment( $comment, $args, $depth ) {
472         $GLOBALS['comment'] = $comment;
473         switch ( $comment->comment_type ) :
474                 case 'pingback' :
475                 case 'trackback' :
476         ?>
477         <li class="post pingback">
478                 <p><?php _e( 'Pingback:', 'dss' ); ?> <?php comment_author_link(); ?><?php edit_comment_link( __( 'Edit', 'dss' ), '<span class="edit-link">', '</span>' ); ?></p>
479         <?php
480                         break;
481                 default :
482         ?>
483         <li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
484                 <article id="comment-<?php comment_ID(); ?>" class="comment">
485                         <footer class="comment-meta">
486                                 <div class="comment-author vcard">
487                                         <?php
488                                                 $avatar_size = 68;
489                                                 if ( '0' != $comment->comment_parent )
490                                                         $avatar_size = 39;
491
492                                                 echo get_avatar( $comment, $avatar_size );
493
494                                                 /* translators: 1: comment author, 2: date and time */
495                                                 printf( __( '%1$s on %2$s <span class="says">said:</span>', 'dss' ),
496                                                         sprintf( '<span class="fn">%s</span>', get_comment_author_link() ),
497                                                         sprintf( '<a href="%1$s"><time pubdate datetime="%2$s">%3$s</time></a>',
498                                                                 esc_url( get_comment_link( $comment->comment_ID ) ),
499                                                                 get_comment_time( 'c' ),
500                                                                 /* translators: 1: date, 2: time */
501                                                                 sprintf( __( '%1$s at %2$s', 'dss' ), get_comment_date(), get_comment_time() )
502                                                         )
503                                                 );
504                                         ?>
505
506                                         <?php edit_comment_link( __( 'Edit', 'dss' ), '<span class="edit-link">', '</span>' ); ?>
507                                 </div><!-- .comment-author .vcard -->
508
509                                 <?php if ( $comment->comment_approved == '0' ) : ?>
510                                         <em class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.', 'dss' ); ?></em>
511                                         <br />
512                                 <?php endif; ?>
513
514                         </footer>
515
516                         <div class="comment-content"><?php comment_text(); ?></div>
517
518                         <div class="reply">
519                                 <?php comment_reply_link( array_merge( $args, array( 'reply_text' => __( 'Reply <span>&darr;</span>', 'dss' ), 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
520                         </div><!-- .reply -->
521                 </article><!-- #comment-## -->
522
523         <?php
524                         break;
525         endswitch;
526 }
527 endif; // ends check for dss_comment()
528
529 if ( ! function_exists( 'dss_posted_on' ) ) :
530 /**
531  * Prints HTML with meta information for the current post-date/time and author.
532  * Create your own dss_posted_on to override in a child theme
533  *
534  * Note: This function is modified from the Twenty Eleven theme
535  *
536  * @since DSS Framework 1.0
537  * @author Ryan Hellyer <ryan@metronet.no>
538  */
539 function dss_posted_on() {
540         printf( __( '<span class="sep">Posted</span><span class="by-author"><span class="sep"> by </span><span class="author vcard"><a class="url fn n" href="%5$s" title="%6$s" rel="author">%7$s</a></span></span> &nbsp; <a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s" pubdate>%4$s</time></a>', 'dss' ),
541                 esc_url( get_permalink() ),
542                 esc_attr( get_the_time() ),
543                 esc_attr( get_the_date( 'c' ) ),
544                 esc_html( get_the_date() ),
545                 esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
546                 esc_attr( sprintf( __( 'View all posts by %s', 'dss' ), get_the_author() ) ),
547                 get_the_author()
548         );
549 }
550 endif;
551
552 /**
553  * Adds two classes to the array of body classes.
554  * The first is if the site has only had one author with published posts.
555  * The second is if a singular post being displayed
556  *
557  * Note: This function is modified from the Twenty Eleven theme
558  *
559  * @since DSS Framework 1.0
560  * @author Ryan Hellyer <ryan@metronet.no>
561  */
562 function dss_body_classes( $classes ) {
563
564         if ( function_exists( 'is_multi_author' ) && ! is_multi_author() )
565                 $classes[] = 'single-author';
566
567         if ( is_singular() && ! is_home() && ! is_page_template( 'showcase.php' ) && ! is_page_template( 'sidebar-page.php' ) )
568                 $classes[] = 'singular';
569
570         return $classes;
571 }
572 add_filter( 'body_class', 'dss_body_classes' );
573
574 /**
575  * Categories to ignore in templates
576  * If one of these categories is singly present, then the category list is not displayed
577  * Useful for ensuring that categories aren't listed when someone doesn't bother to set a category for the post
578  *
579  * @since DSS Framework 1.0
580  * @author Ryan Hellyer <ryan@metronet.no>
581  */
582 function dss_categories_to_ignore() {
583         $cats = array(
584                 'Uncategorised',
585                 'Uncategorized',
586                 'Ukategorisert',
587         );
588         return $cats;
589 }
590
591 /**
592  * Adds order class to widgets
593  * Useful for targetting individual widgets
594  * 
595  * Works by modifying the global array containing the sidebar class names
596  * Code adapted from http://konstruktors.com/blog/wordpress/3615-add-widget-order-css-class-sidebar/
597  * 
598  * @since 1.0
599  * @global array $wp_registered_sidebars
600  * @global array $wp_registered_widgets
601  * @author Ryan Hellyer <ryan@pixopoint.com> and Kaspars Dambis <kaspars@metronet.no>
602  */
603 function dss_widget_order_class() {
604         global $wp_registered_sidebars, $wp_registered_widgets;
605
606         // Grab the widgets
607         $sidebars = wp_get_sidebars_widgets();
608
609         if ( empty( $sidebars ) )
610                 return;
611
612         // Loop through each widget and change the class names
613         foreach ( $sidebars as $sidebar_id => $widgets ) {
614                 if ( empty( $widgets ) )
615                         continue;
616                 $number_of_widgets = count( $widgets );
617                 foreach ( $widgets as $i => $widget_id ) {
618                         $wp_registered_widgets[$widget_id]['classname'] .= ' widget-order-' . $i;
619
620                         // Add first widget class
621                         if ( 0 == $i ) {
622                                 $wp_registered_widgets[$widget_id]['classname'] .= ' first-widget'; 
623                         }
624
625                         // Add last widget class
626                         if ( $number_of_widgets == ( $i + 1 ) ) {
627                                 $wp_registered_widgets[$widget_id]['classname'] .= ' last-widget'; 
628                         }
629                 }
630         }
631 }
632 add_action( 'init', 'dss_widget_order_class' );