├── assets ├── css │ ├── admin.css │ ├── admin.less │ ├── layout.css │ └── layout.less └── images │ ├── features-icon.png │ └── features-icon@x2.png ├── classes ├── class-woothemes-features-taxonomy.php ├── class-woothemes-features.php └── class-woothemes-widget-features.php ├── lang ├── woothemes-features-en_GB.po └── woothemes-features-xx_XX.pot ├── readme.txt ├── woothemes-features-template.php └── woothemes-features.php /assets/css/admin.css: -------------------------------------------------------------------------------- 1 | #adminmenu .menu-icon-feature div.wp-menu-image:before { 2 | content: '\f155'; 3 | } -------------------------------------------------------------------------------- /assets/css/admin.less: -------------------------------------------------------------------------------- 1 | // Features icon 2 | #adminmenu .menu-icon-feature div.wp-menu-image:before { 3 | content: '\f155'; 4 | } -------------------------------------------------------------------------------- /assets/css/layout.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Front-end layout styles. 3 | */ 4 | .clearfix { 5 | zoom: 1; 6 | } 7 | .clearfix:before, 8 | .clearfix:after { 9 | content: ""; 10 | display: table; 11 | } 12 | .clearfix:after { 13 | clear: both; 14 | } 15 | .widget_woothemes_features { 16 | margin: 0; 17 | zoom: 1; 18 | } 19 | .widget_woothemes_features:before, 20 | .widget_woothemes_features:after { 21 | content: ""; 22 | display: table; 23 | } 24 | .widget_woothemes_features:after { 25 | clear: both; 26 | } 27 | .widget_woothemes_features > h3 { 28 | margin: 0 0 .8em; 29 | } 30 | .widget_woothemes_features .feature { 31 | display: block; 32 | text-align: center; 33 | margin-bottom: 2em; 34 | } 35 | .widget_woothemes_features .feature h3 a { 36 | color: inherit; 37 | } 38 | .widget_woothemes_features .feature img { 39 | float: none; 40 | margin: 0 auto 1em auto; 41 | border: none; 42 | } 43 | .widget_woothemes_features .feature .feature-title { 44 | margin: 0 0 .8em; 45 | padding: 0; 46 | font-size: 1.2em; 47 | border: none; 48 | } 49 | @media only screen and (min-width: 980px) { 50 | #main .widget_woothemes_features .columns-1 .feature { 51 | width: 100%; 52 | text-align: left; 53 | } 54 | #main .widget_woothemes_features .columns-1 .feature img { 55 | float: left; 56 | margin: 0 2em 0 1em; 57 | } 58 | #main .widget_woothemes_features .columns-2 .feature { 59 | width: 47%; 60 | text-align: left; 61 | } 62 | #main .widget_woothemes_features .columns-2 .feature img { 63 | float: left; 64 | margin: 0 2em 0 1em; 65 | } 66 | #main .widget_woothemes_features .columns-3 .feature { 67 | width: 30%; 68 | text-align: center; 69 | } 70 | #main .widget_woothemes_features .columns-3 .feature img { 71 | float: none; 72 | } 73 | #main .widget_woothemes_features .columns-4 .feature { 74 | width: 21%; 75 | text-align: center; 76 | } 77 | #main .widget_woothemes_features .columns-4 .feature img { 78 | float: none; 79 | } 80 | #main .widget_woothemes_features .columns-5 .feature { 81 | width: 16%; 82 | text-align: center; 83 | } 84 | #main .widget_woothemes_features .columns-5 .feature img { 85 | float: none; 86 | } 87 | #main .widget_woothemes_features .columns-6 .feature { 88 | width: 12.4%; 89 | text-align: center; 90 | } 91 | #main .widget_woothemes_features .columns-6 .feature img { 92 | float: none; 93 | } 94 | #main .widget_woothemes_features .feature { 95 | float: left; 96 | margin-right: 5%; 97 | } 98 | #main .widget_woothemes_features .feature.last { 99 | margin-right: 0; 100 | } 101 | #main .widget_woothemes_features .feature .feature-content { 102 | overflow: hidden; 103 | } 104 | #sidebar .widget_woothemes_features .columns-2 .feature, 105 | #sidebar .widget_woothemes_features .columns-3 .feature, 106 | #sidebar .widget_woothemes_features .columns-4 .feature, 107 | #sidebar .widget_woothemes_features .columns-5 .feature, 108 | #sidebar .widget_woothemes_features .columns-6 .feature { 109 | width: 100%; 110 | float: none; 111 | margin-right: 0; 112 | clear: both; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /assets/css/layout.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Front-end layout styles. 3 | */ 4 | 5 | .clearfix { 6 | zoom: 1; // For IE 6/7 (trigger hasLayout) 7 | 8 | &:before, &:after { 9 | content: ""; 10 | display: table; 11 | } 12 | 13 | &:after { 14 | clear:both; 15 | } 16 | } 17 | 18 | .widget_woothemes_features { 19 | margin: 0; 20 | .clearfix; 21 | 22 | > h3 { 23 | margin: 0 0 .8em; 24 | } 25 | 26 | .feature { 27 | display:block; 28 | text-align: center; 29 | margin-bottom: 2em; 30 | 31 | h3 a { 32 | color: inherit; 33 | } 34 | 35 | img { 36 | float: none; 37 | margin: 0 auto 1em auto; 38 | border: none; 39 | } 40 | 41 | .feature-title { 42 | margin: 0 0 .8em; 43 | padding: 0; 44 | font-size: 1.2em; 45 | border: none; 46 | } 47 | } 48 | } 49 | 50 | // Layout 51 | @media only screen and ( min-width: 980px ) { 52 | 53 | #main { 54 | .widget_woothemes_features { 55 | .columns-1 { 56 | .feature { 57 | width: 100%; 58 | text-align: left; 59 | 60 | img { 61 | float: left; 62 | margin: 0 2em 0 1em; 63 | } 64 | } 65 | } 66 | 67 | .columns-2 { 68 | .feature { 69 | width: 47%; 70 | text-align:left; 71 | 72 | img { 73 | float:left; 74 | margin: 0 2em 0 1em; 75 | } 76 | } 77 | } 78 | 79 | .columns-3 { 80 | .feature { 81 | width: 30%; 82 | text-align:center; 83 | 84 | img { 85 | float:none; 86 | } 87 | } 88 | } 89 | .columns-4 { 90 | .feature { 91 | width: 21%; 92 | text-align:center; 93 | 94 | img { 95 | float:none; 96 | } 97 | } 98 | } 99 | .columns-5 { 100 | .feature { 101 | width: 16%; 102 | text-align:center; 103 | img { 104 | float:none; 105 | } 106 | } 107 | } 108 | 109 | .columns-6 { 110 | .feature { 111 | width: 12.4%; 112 | text-align:center; 113 | 114 | img { 115 | float:none; 116 | } 117 | } 118 | } 119 | 120 | .feature { 121 | float: left; 122 | margin-right: 5%; 123 | 124 | &.last { 125 | margin-right: 0; 126 | } 127 | 128 | .feature-content{ 129 | overflow: hidden; 130 | } 131 | } 132 | } 133 | } 134 | 135 | #sidebar { 136 | .widget_woothemes_features { 137 | .columns-2, 138 | .columns-3, 139 | .columns-4, 140 | .columns-5, 141 | .columns-6 { 142 | .feature { 143 | width: 100%; 144 | float: none; 145 | margin-right: 0; 146 | clear: both; 147 | } 148 | } 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /assets/images/features-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woocommerce/features/1f3c59cc608b3b19254b98411d21f38a4cf82522/assets/images/features-icon.png -------------------------------------------------------------------------------- /assets/images/features-icon@x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woocommerce/features/1f3c59cc608b3b19254b98411d21f38a4cf82522/assets/images/features-icon@x2.png -------------------------------------------------------------------------------- /classes/class-woothemes-features-taxonomy.php: -------------------------------------------------------------------------------- 1 | post_type = 'feature'; 67 | $this->token = esc_attr( $token ); 68 | $this->singular = esc_html( $singular ); 69 | $this->plural = esc_html( $plural ); 70 | 71 | if ( '' == $this->singular ) $this->singular = __( 'Category', 'woothemes-features' ); 72 | if ( '' == $this->plural ) $this->plural = __( 'Categories', 'woothemes-features' ); 73 | 74 | $this->args = wp_parse_args( $args, $this->_get_default_args() ); 75 | } // End __construct() 76 | 77 | /** 78 | * Return an array of default arguments. 79 | * @access private 80 | * @since 1.3.0 81 | * @return array Default arguments. 82 | */ 83 | private function _get_default_args () { 84 | return array( 'labels' => $this->_get_default_labels(), 'public' => true, 'hierarchical' => true, 'show_ui' => true, 'show_admin_column' => true, 'query_var' => true, 'show_in_nav_menus' => false, 'show_tagcloud' => false ); 85 | } // End _get_default_args() 86 | 87 | /** 88 | * Return an array of default labels. 89 | * @access private 90 | * @since 1.3.0 91 | * @return array Default labels. 92 | */ 93 | private function _get_default_labels () { 94 | return array( 95 | 'name' => sprintf( _x( '%s', 'taxonomy general name', 'woothemes-features' ), $this->plural ), 96 | 'singular_name' => sprintf( _x( '%s', 'taxonomy singular name', 'woothemes-features' ), $this->singular ), 97 | 'search_items' => sprintf( __( 'Search %s', 'woothemes-features' ), $this->plural ), 98 | 'all_items' => sprintf( __( 'All %s', 'woothemes-features' ), $this->plural ), 99 | 'parent_item' => sprintf( __( 'Parent %s', 'woothemes-features' ), $this->singular ), 100 | 'parent_item_colon' => sprintf( __( 'Parent %s:', 'woothemes-features' ), $this->singular ), 101 | 'edit_item' => sprintf( __( 'Edit %s', 'woothemes-features' ), $this->singular ), 102 | 'update_item' => sprintf( __( 'Update %s', 'woothemes-features' ), $this->singular ), 103 | 'add_new_item' => sprintf( __( 'Add New %s', 'woothemes-features' ), $this->singular ), 104 | 'new_item_name' => sprintf( __( 'New %s Name', 'woothemes-features' ), $this->singular ), 105 | 'menu_name' => sprintf( __( '%s', 'woothemes-features' ), $this->plural ) 106 | ); 107 | } // End _get_default_labels() 108 | 109 | /** 110 | * Register the taxonomy. 111 | * @access public 112 | * @since 1.3.0 113 | * @return void 114 | */ 115 | public function register () { 116 | register_taxonomy( esc_attr( $this->token ), esc_attr( $this->post_type ), (array)$this->args ); 117 | } // End register() 118 | } // End Class 119 | ?> -------------------------------------------------------------------------------- /classes/class-woothemes-features.php: -------------------------------------------------------------------------------- 1 | dir = dirname( $file ); 33 | $this->file = $file; 34 | $this->assets_dir = trailingslashit( $this->dir ) . 'assets'; 35 | $this->assets_url = esc_url( trailingslashit( plugins_url( '/assets/', $file ) ) ); 36 | $this->token = 'feature'; 37 | 38 | $this->load_plugin_textdomain(); 39 | add_action( 'init', array( $this, 'load_localisation' ), 0 ); 40 | 41 | // Run this on activation. 42 | register_activation_hook( $this->file, array( $this, 'activation' ) ); 43 | 44 | add_action( 'init', array( $this, 'register_post_type' ) ); 45 | add_action( 'init', array( $this, 'register_taxonomy' ) ); 46 | 47 | if ( is_admin() ) { 48 | global $pagenow; 49 | 50 | add_action( 'admin_menu', array( $this, 'meta_box_setup' ), 20 ); 51 | add_action( 'save_post', array( $this, 'meta_box_save' ) ); 52 | add_filter( 'enter_title_here', array( $this, 'enter_title_here' ) ); 53 | add_action( 'admin_print_styles', array( $this, 'enqueue_admin_styles' ), 10 ); 54 | add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) ); 55 | 56 | if ( $pagenow == 'edit.php' && isset( $_GET['post_type'] ) && esc_attr( $_GET['post_type'] ) == $this->token ) { 57 | add_filter( 'manage_edit-' . $this->token . '_columns', array( $this, 'register_custom_column_headings' ), 10, 1 ); 58 | add_action( 'manage_posts_custom_column', array( $this, 'register_custom_columns' ), 10, 2 ); 59 | } 60 | } 61 | 62 | add_action( 'after_setup_theme', array( $this, 'ensure_post_thumbnails_support' ) ); 63 | add_action( 'after_setup_theme', array( $this, 'load_frontend_layout_css' ), 20 ); 64 | add_action( 'after_setup_theme', array( $this, 'register_image_sizes' ) ); 65 | } // End __construct() 66 | 67 | /** 68 | * Register the post type. 69 | * 70 | * @access public 71 | * @param string $token 72 | * @param string 'Features' 73 | * @param string 'Features' 74 | * @param array $supports 75 | * @return void 76 | */ 77 | public function register_post_type () { 78 | $labels = array( 79 | 'name' => _x( 'Features', 'post type general name', 'woothemes-features' ), 80 | 'singular_name' => _x( 'Feature', 'post type singular name', 'woothemes-features' ), 81 | 'add_new' => _x( 'Add New', 'feature', 'woothemes-features' ), 82 | 'add_new_item' => sprintf( __( 'Add New %s', 'woothemes-features' ), __( 'Feature', 'woothemes-features' ) ), 83 | 'edit_item' => sprintf( __( 'Edit %s', 'woothemes-features' ), __( 'Feature', 'woothemes-features' ) ), 84 | 'new_item' => sprintf( __( 'New %s', 'woothemes-features' ), __( 'Feature', 'woothemes-features' ) ), 85 | 'all_items' => sprintf( __( 'All %s', 'woothemes-features' ), __( 'Features', 'woothemes-features' ) ), 86 | 'view_item' => sprintf( __( 'View %s', 'woothemes-features' ), __( 'Feature', 'woothemes-features' ) ), 87 | 'search_items' => sprintf( __( 'Search %a', 'woothemes-features' ), __( 'Features', 'woothemes-features' ) ), 88 | 'not_found' => sprintf( __( 'No %s Found', 'woothemes-features' ), __( 'Features', 'woothemes-features' ) ), 89 | 'not_found_in_trash' => sprintf( __( 'No %s Found In Trash', 'woothemes-features' ), __( 'Features', 'woothemes-features' ) ), 90 | 'parent_item_colon' => '', 91 | 'menu_name' => __( 'Features', 'woothemes-features' ) 92 | 93 | ); 94 | 95 | $single_slug = apply_filters( 'woothemes_features_single_slug', _x( 'feature', 'single post url slug', 'woothemes-features' ) ); 96 | $archive_slug = apply_filters( 'woothemes_features_archive_slug', _x( 'features', 'post archive url slug', 'woothemes-features' ) ); 97 | 98 | $args = array( 99 | 'labels' => $labels, 100 | 'public' => true, 101 | 'publicly_queryable' => true, 102 | 'show_ui' => true, 103 | 'show_in_menu' => true, 104 | 'query_var' => true, 105 | 'rewrite' => array( 'slug' => $single_slug ), 106 | 'capability_type' => 'post', 107 | 'has_archive' => $archive_slug, 108 | 'hierarchical' => false, 109 | 'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'page-attributes' ), 110 | 'menu_position' => 5, 111 | 'menu_icon' => '' 112 | ); 113 | register_post_type( $this->token, apply_filters( 'woothemes_features_post_type_args', $args ) ); 114 | } // End register_post_type() 115 | 116 | /** 117 | * Register the "feature-category" taxonomy. 118 | * @access public 119 | * @since 1.3.0 120 | * @return void 121 | */ 122 | public function register_taxonomy () { 123 | $this->taxonomy_category = new Woothemes_Features_Taxonomy(); // Leave arguments empty, to use the default arguments. 124 | $this->taxonomy_category->register(); 125 | } // End register_taxonomy() 126 | 127 | /** 128 | * Add custom columns for the "manage" screen of this post type. 129 | * 130 | * @access public 131 | * @param string $column_name 132 | * @param int $id 133 | * @since 1.0.0 134 | * @return void 135 | */ 136 | public function register_custom_columns ( $column_name, $id ) { 137 | global $wpdb, $post; 138 | 139 | $meta = get_post_custom( $id ); 140 | 141 | switch ( $column_name ) { 142 | 143 | case 'image': 144 | $value = ''; 145 | 146 | $value = $this->get_image( $id, 40 ); 147 | 148 | echo $value; 149 | break; 150 | 151 | default: 152 | break; 153 | 154 | } 155 | } // End register_custom_columns() 156 | 157 | /** 158 | * Add custom column headings for the "manage" screen of this post type. 159 | * 160 | * @access public 161 | * @param array $defaults 162 | * @since 1.0.0 163 | * @return void 164 | */ 165 | public function register_custom_column_headings ( $defaults ) { 166 | $new_columns = array( 'image' => __( 'Image', 'woothemes-features' ) ); 167 | 168 | $last_item = ''; 169 | 170 | if ( isset( $defaults['date'] ) ) { unset( $defaults['date'] ); } 171 | 172 | if ( count( $defaults ) > 2 ) { 173 | $last_item = array_slice( $defaults, -1 ); 174 | 175 | array_pop( $defaults ); 176 | } 177 | $defaults = array_merge( $defaults, $new_columns ); 178 | 179 | if ( $last_item != '' ) { 180 | foreach ( $last_item as $k => $v ) { 181 | $defaults[$k] = $v; 182 | break; 183 | } 184 | } 185 | 186 | return $defaults; 187 | } // End register_custom_column_headings() 188 | 189 | /** 190 | * Update messages for the post type admin. 191 | * @since 1.0.0 192 | * @param array $messages Array of messages for all post types. 193 | * @return array Modified array. 194 | */ 195 | public function updated_messages ( $messages ) { 196 | global $post, $post_ID; 197 | 198 | $messages[$this->token] = array( 199 | 0 => '', // Unused. Messages start at index 1. 200 | 1 => sprintf( __( 'Feature updated. %sView feature%s', 'woothemes-features' ), '', '' ), 201 | 2 => __( 'Custom field updated.', 'woothemes-features' ), 202 | 3 => __( 'Custom field deleted.', 'woothemes-features' ), 203 | 4 => __( 'Feature updated.', 'woothemes-features' ), 204 | /* translators: %s: date and time of the revision */ 205 | 5 => isset($_GET['revision']) ? sprintf( __( 'Feature restored to revision from %s', 'woothemes-features' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, 206 | 6 => sprintf( __( 'Feature published. %sView feature%s', 'woothemes-features' ), '', '' ), 207 | 7 => __('Feature saved.'), 208 | 8 => sprintf( __( 'Feature submitted. %sPreview feature%s', 'woothemes-features' ), '', '' ), 209 | 9 => sprintf( __( 'Feature scheduled for: %1$s. %2$sPreview feature%3$s', 'woothemes-features' ), 210 | // translators: Publish box date format, see http://php.net/date 211 | '' . date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ) . '', '', '' ), 212 | 10 => sprintf( __( 'Feature draft updated. %sPreview feature%s', 'woothemes-features' ), '', '' ), 213 | ); 214 | 215 | return $messages; 216 | } // End updated_messages() 217 | 218 | /** 219 | * Setup the meta box. 220 | * 221 | * @access public 222 | * @since 1.1.0 223 | * @return void 224 | */ 225 | public function meta_box_setup () { 226 | add_meta_box( 'feature-data', __( 'Feature Details', 'woothemes-features' ), array( $this, 'meta_box_content' ), $this->token, 'normal', 'high' ); 227 | } // End meta_box_setup() 228 | 229 | /** 230 | * The contents of our meta box. 231 | * 232 | * @access public 233 | * @since 1.1.0 234 | * @return void 235 | */ 236 | public function meta_box_content () { 237 | global $post_id; 238 | $fields = get_post_custom( $post_id ); 239 | $field_data = $this->get_custom_fields_settings(); 240 | 241 | $html = ''; 242 | 243 | $html .= ''; 244 | 245 | if ( 0 < count( $field_data ) ) { 246 | $html .= '' . "\n"; 247 | $html .= '' . "\n"; 248 | 249 | foreach ( $field_data as $k => $v ) { 250 | $data = $v['default']; 251 | if ( isset( $fields['_' . $k] ) && isset( $fields['_' . $k][0] ) ) { 252 | $data = $fields['_' . $k][0]; 253 | } 254 | 255 | $html .= '' . "\n"; 258 | } 259 | 260 | $html .= '' . "\n"; 261 | $html .= '
' . "\n"; 256 | $html .= '

' . $v['description'] . '

' . "\n"; 257 | $html .= '
' . "\n"; 262 | } 263 | 264 | echo $html; 265 | } // End meta_box_content() 266 | 267 | /** 268 | * Save meta box fields. 269 | * 270 | * @access public 271 | * @since 1.1.0 272 | * @param int $post_id 273 | * @return void 274 | */ 275 | public function meta_box_save ( $post_id ) { 276 | global $post, $messages; 277 | 278 | // Verify 279 | if ( ( get_post_type() != $this->token ) || ! wp_verify_nonce( $_POST['woo_' . $this->token . '_noonce'], plugin_basename( $this->dir ) ) ) { 280 | return $post_id; 281 | } 282 | 283 | if ( 'page' == $_POST['post_type'] ) { 284 | if ( ! current_user_can( 'edit_page', $post_id ) ) { 285 | return $post_id; 286 | } 287 | } else { 288 | if ( ! current_user_can( 'edit_post', $post_id ) ) { 289 | return $post_id; 290 | } 291 | } 292 | 293 | $field_data = $this->get_custom_fields_settings(); 294 | $fields = array_keys( $field_data ); 295 | 296 | foreach ( $fields as $f ) { 297 | 298 | ${$f} = strip_tags(trim($_POST[$f])); 299 | 300 | // Escape the URLs. 301 | if ( 'url' == $field_data[$f]['type'] ) { 302 | ${$f} = esc_url( ${$f} ); 303 | } 304 | 305 | if ( get_post_meta( $post_id, '_' . $f ) == '' ) { 306 | add_post_meta( $post_id, '_' . $f, ${$f}, true ); 307 | } elseif( ${$f} != get_post_meta( $post_id, '_' . $f, true ) ) { 308 | update_post_meta( $post_id, '_' . $f, ${$f} ); 309 | } elseif ( ${$f} == '' ) { 310 | delete_post_meta( $post_id, '_' . $f, get_post_meta( $post_id, '_' . $f, true ) ); 311 | } 312 | } 313 | } // End meta_box_save() 314 | 315 | /** 316 | * Customise the "Enter title here" text. 317 | * 318 | * @access public 319 | * @since 1.0.0 320 | * @param string $title 321 | * @return void 322 | */ 323 | public function enter_title_here ( $title ) { 324 | if ( get_post_type() == $this->token ) { 325 | $title = __( 'Enter the feature title here', 'woothemes-features' ); 326 | } 327 | return $title; 328 | } // End enter_title_here() 329 | 330 | /** 331 | * Enqueue post type admin CSS. 332 | * 333 | * @access public 334 | * @since 1.0.0 335 | * @return void 336 | */ 337 | public function enqueue_admin_styles () { 338 | wp_register_style( 'woothemes-features-admin', esc_url( $this->assets_url . 'css/admin.css' ), array(), '1.0.2' ); 339 | wp_enqueue_style( 'woothemes-features-admin' ); 340 | } // End enqueue_admin_styles() 341 | 342 | /** 343 | * Enqueue post type layout CSS. 344 | * 345 | * @access public 346 | * @since 1.5.0 347 | * @return void 348 | */ 349 | public function enqueue_layout_styles () { 350 | wp_register_style( 'woothemes-features-layout', esc_url( $this->assets_url . 'css/layout.css' ), array(), '1.0.0' ); 351 | wp_enqueue_style( 'woothemes-features-layout' ); 352 | } // End enqueue_layout_styles() 353 | 354 | /** 355 | * Get the settings for the custom fields. 356 | * @since 1.1.0 357 | * @return array 358 | */ 359 | public function get_custom_fields_settings () { 360 | $fields = array(); 361 | 362 | $fields['url'] = array( 363 | 'name' => __( 'URL', 'woothemes-features' ), 364 | 'description' => __( 'Enter a URL that applies to this feature (for example: http://woothemes.com/).', 'woothemes-features' ), 365 | 'type' => 'url', 366 | 'default' => '', 367 | 'section' => 'info' 368 | ); 369 | 370 | return apply_filters( 'woothemes_features_custom_fields_settings', $fields ); 371 | } // End get_custom_fields_settings() 372 | 373 | /** 374 | * Get the image for the given ID. 375 | * @param int $id Post ID. 376 | * @param string/array/int $size Image dimension. (default: "feature-thumbnail") 377 | * @since 1.0.0 378 | * @return string tag. 379 | */ 380 | protected function get_image ( $id, $size = 'feature-thumbnail' ) { 381 | $response = ''; 382 | 383 | if ( has_post_thumbnail( $id ) ) { 384 | // If not a string or an array, and not an integer, default to 150x9999. 385 | if ( ( is_int( $size ) || ( 0 < intval( $size ) ) ) && ! is_array( $size ) ) { 386 | $size = array( intval( $size ), intval( $size ) ); 387 | } elseif ( ! is_string( $size ) && ! is_array( $size ) ) { 388 | $size = array( 150, 9999 ); 389 | } 390 | $response = get_the_post_thumbnail( intval( $id ), $size ); 391 | } 392 | 393 | return $response; 394 | } // End get_image() 395 | 396 | /** 397 | * Register image sizes. 398 | * @since 1.0.0 399 | * @return void 400 | */ 401 | public function register_image_sizes () { 402 | if ( function_exists( 'add_image_size' ) ) { 403 | add_image_size( 'feature-thumbnail', 150, 9999 ); // 150 pixels wide (and unlimited height) 404 | } 405 | } // End register_image_sizes() 406 | 407 | /** 408 | * Get features. 409 | * @param string/array $args Arguments to be passed to the query. 410 | * @since 1.0.0 411 | * @return array/boolean Array if true, boolean if false. 412 | */ 413 | public function get_features ( $args = '' ) { 414 | $defaults = array( 415 | 'limit' => 5, 416 | 'orderby' => 'menu_order', 417 | 'order' => 'DESC', 418 | 'id' => 0, 419 | 'category' => 0, 420 | 'custom_links_only' => false 421 | ); 422 | 423 | $args = wp_parse_args( $args, $defaults ); 424 | 425 | // Allow child themes/plugins to filter here. 426 | $args = apply_filters( 'woothemes_get_features_args', $args ); 427 | 428 | // The Query Arguments. 429 | $query_args = array(); 430 | $query_args['post_type'] = 'feature'; 431 | $query_args['numberposts'] = $args['limit']; 432 | $query_args['orderby'] = $args['orderby']; 433 | $query_args['order'] = $args['order']; 434 | $query_args['suppress_filters'] = false; 435 | 436 | if ( is_numeric( $args['id'] ) && ( intval( $args['id'] ) > 0 ) ) { 437 | $query_args['p'] = intval( $args['id'] ); 438 | } 439 | 440 | // Whitelist checks. 441 | if ( ! in_array( $query_args['orderby'], array( 'none', 'ID', 'author', 'title', 'date', 'modified', 'parent', 'rand', 'comment_count', 'menu_order', 'meta_value', 'meta_value_num' ) ) ) { 442 | $query_args['orderby'] = 'date'; 443 | } 444 | 445 | if ( ! in_array( $query_args['order'], array( 'ASC', 'DESC' ) ) ) { 446 | $query_args['order'] = 'DESC'; 447 | } 448 | 449 | if ( ! in_array( $query_args['post_type'], get_post_types() ) ) { 450 | $query_args['post_type'] = 'feature'; 451 | } 452 | 453 | $tax_field_type = ''; 454 | 455 | // If the category ID is specified. 456 | if ( is_numeric( $args['category'] ) && 0 < intval( $args['category'] ) ) { 457 | $tax_field_type = 'id'; 458 | } 459 | 460 | // If the category slug is specified. 461 | if ( ! is_numeric( $args['category'] ) && is_string( $args['category'] ) ) { 462 | $tax_field_type = 'slug'; 463 | } 464 | 465 | // Setup the taxonomy query. 466 | if ( '' != $tax_field_type ) { 467 | $term = $args['category']; 468 | if ( is_string( $term ) ) { $term = esc_html( $term ); } else { $term = intval( $term ); } 469 | $query_args['tax_query'] = array( array( 'taxonomy' => 'feature-category', 'field' => $tax_field_type, 'terms' => array( $term ) ) ); 470 | } 471 | 472 | // The Query. 473 | $query = get_posts( $query_args ); 474 | 475 | // The Display. 476 | if ( ! is_wp_error( $query ) && is_array( $query ) && count( $query ) > 0 ) { 477 | foreach ( $query as $k => $v ) { 478 | $meta = get_post_custom( $v->ID ); 479 | 480 | // Get the image. 481 | $query[$k]->image = $this->get_image( $v->ID, $args['size'] ); 482 | 483 | // Get the URL. 484 | if ( isset( $meta['_url'][0] ) && '' != $meta['_url'][0] ) { 485 | $query[$k]->url = esc_url( $meta['_url'][0] ); 486 | } else { 487 | if ( true == $args['custom_links_only'] ) { 488 | $query[$k]->url = ''; 489 | } else { 490 | $query[$k]->url = get_permalink( $v->ID ); 491 | } 492 | } 493 | } 494 | } else { 495 | $query = false; 496 | } 497 | 498 | return $query; 499 | } // End get_features() 500 | 501 | /** 502 | * Load the plugin's localisation file. 503 | * @access public 504 | * @since 1.0.0 505 | * @return void 506 | */ 507 | public function load_localisation () { 508 | load_plugin_textdomain( 'woothemes-features', false, dirname( plugin_basename( $this->file ) ) . '/lang/' ); 509 | } // End load_localisation() 510 | 511 | /** 512 | * Load the plugin textdomain from the main WordPress "languages" folder. 513 | * @since 1.0.0 514 | * @return void 515 | */ 516 | public function load_plugin_textdomain () { 517 | $domain = 'woothemes-features'; 518 | // The "plugin_locale" filter is also used in load_plugin_textdomain() 519 | $locale = apply_filters( 'plugin_locale', get_locale(), $domain ); 520 | 521 | load_textdomain( $domain, WP_LANG_DIR . '/' . $domain . '/' . $domain . '-' . $locale . '.mo' ); 522 | load_plugin_textdomain( $domain, FALSE, dirname( plugin_basename( $this->file ) ) . '/lang/' ); 523 | } // End load_plugin_textdomain() 524 | 525 | /** 526 | * Run on activation. 527 | * @access public 528 | * @since 1.0.0 529 | * @return void 530 | */ 531 | public function activation () { 532 | $this->register_plugin_version(); 533 | $this->flush_rewrite_rules(); 534 | } // End activation() 535 | 536 | /** 537 | * Register the plugin's version. 538 | * @access public 539 | * @since 1.0.0 540 | * @return void 541 | */ 542 | private function register_plugin_version () { 543 | if ( $this->version != '' ) { 544 | update_option( 'woothemes-features' . '-version', $this->version ); 545 | } 546 | } // End register_plugin_version() 547 | 548 | /** 549 | * Flush the rewrite rules 550 | * @access public 551 | * @since 1.3.1 552 | * @return void 553 | */ 554 | private function flush_rewrite_rules () { 555 | $this->register_post_type(); 556 | flush_rewrite_rules(); 557 | } // End flush_rewrite_rules() 558 | 559 | /** 560 | * Ensure that "post-thumbnails" support is available for those themes that don't register it. 561 | * @since 1.0.1 562 | * @return void 563 | */ 564 | public function ensure_post_thumbnails_support () { 565 | if ( ! current_theme_supports( 'post-thumbnails' ) ) { add_theme_support( 'post-thumbnails' ); } 566 | } // End ensure_post_thumbnails_support() 567 | 568 | /** 569 | * Load the front-end layout styles for themes that don't include a built-in support for Features. 570 | * @since 1.5.0 571 | * @return void 572 | */ 573 | public function load_frontend_layout_css () { 574 | if ( ! current_theme_supports( 'features-by-woothemes' ) || apply_filters( 'woothemes_features_layout_css', false ) ) { 575 | add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_layout_styles' ), 10 ); 576 | } 577 | } // End load_frontend_layout_css() 578 | 579 | } // End Class -------------------------------------------------------------------------------- /classes/class-woothemes-widget-features.php: -------------------------------------------------------------------------------- 1 | woothemes_widget_cssclass = 'widget_woothemes_features'; 42 | $this->woothemes_widget_description = __( 'Recent features listed on your site.', 'woothemes-features' ); 43 | $this->woothemes_widget_idbase = 'woothemes_features'; 44 | $this->woothemes_widget_title = __( 'Features', 'woothemes-features' ); 45 | 46 | /* Widget settings. */ 47 | $widget_ops = array( 48 | 'classname' => $this->woothemes_widget_cssclass, 49 | 'description' => $this->woothemes_widget_description 50 | ); 51 | 52 | /* Widget control settings. */ 53 | $control_ops = array( 54 | 'width' => 250, 55 | 'height' => 350, 56 | 'id_base' => $this->woothemes_widget_idbase 57 | ); 58 | 59 | /* Create the widget. */ 60 | parent::__construct( $this->woothemes_widget_idbase, $this->woothemes_widget_title, $widget_ops, $control_ops ); 61 | 62 | } // End __construct() 63 | 64 | /** 65 | * Display the widget on the frontend. 66 | * @since 1.0.0 67 | * @param array $args Widget arguments. 68 | * @param array $instance Widget settings for this instance. 69 | * @return void 70 | */ 71 | public function widget( $args, $instance ) { 72 | extract( $args, EXTR_SKIP ); 73 | 74 | /* Our variables from the widget settings. */ 75 | $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ); 76 | 77 | /* Before widget (defined by themes). */ 78 | $args = array(); 79 | 80 | $args['before'] = $before_widget; 81 | 82 | /* After widget (defined by themes). */ 83 | $args['after'] = $after_widget; 84 | 85 | /* Display the widget title if one was input (before and after defined by themes). */ 86 | if ( $title ) { 87 | $args['title'] = $title; 88 | $args['before_title'] = $before_title; 89 | $args['after_title'] = $after_title; 90 | } 91 | 92 | /* Widget content. */ 93 | // Add actions for plugins/themes to hook onto. 94 | do_action( $this->woothemes_widget_cssclass . '_top' ); 95 | 96 | // Integer values. 97 | if ( isset( $instance['limit'] ) && ( 0 < count( $instance['limit'] ) ) ) { 98 | $args['limit'] = intval( $instance['limit'] ); 99 | } 100 | 101 | if ( isset( $instance['specific_id'] ) && ( 0 < count( $instance['specific_id'] ) ) ) { 102 | $args['id'] = intval( $instance['specific_id'] ); 103 | } 104 | 105 | if ( isset( $instance['size'] ) ){ 106 | if( is_numeric( $instance['size'] ) && ( 0 < count( $instance['size'] ) ) ) { 107 | $args['size'] = intval( $instance['size'] ); 108 | } else { 109 | $args['size'] = $instance['size']; 110 | } 111 | } 112 | 113 | if ( isset( $instance['per_row'] ) && ( 0 < count( $instance['per_row'] ) ) ) { 114 | $args['per_row'] = intval( $instance['per_row'] ); 115 | } 116 | 117 | if ( isset( $instance['category'] ) && is_numeric( $instance['category'] ) ) { 118 | $args['category'] = intval( $instance['category'] ); 119 | } 120 | 121 | // Boolean values. 122 | if ( isset( $instance['link_title'] ) && $instance['link_title'] == true && $instance['custom_links_only'] == false ) { 123 | $args['link_title'] = true; 124 | $args['custom_links_only'] = false; 125 | } elseif ( isset( $instance['link_title'] ) && $instance['link_title'] == true && isset( $instance['custom_links_only'] ) && $instance['custom_links_only'] == true ) { 126 | $args['link_title'] = true; 127 | $args['custom_links_only'] = true; 128 | } elseif ( isset( $instance['link_title'] ) && $instance['link_title'] == false && isset( $instance['custom_links_only'] ) && $instance['custom_links_only'] == false ) { 129 | $args['link_title'] = false; 130 | $args['custom_links_only'] = false; 131 | } 132 | 133 | // Select boxes. 134 | if ( isset( $instance['orderby'] ) && in_array( $instance['orderby'], array_keys( $this->get_orderby_options() ) ) ) { 135 | $args['orderby'] = $instance['orderby']; 136 | } 137 | 138 | if ( isset( $instance['order'] ) && in_array( $instance['order'], array_keys( $this->get_order_options() ) ) ) { 139 | $args['order'] = $instance['order']; 140 | } 141 | 142 | // Display the features. 143 | woothemes_features( $args ); 144 | 145 | // Add actions for plugins/themes to hook onto. 146 | do_action( $this->woothemes_widget_cssclass . '_bottom' ); 147 | } // End widget() 148 | 149 | /** 150 | * Method to update the settings from the form() method. 151 | * @since 1.0.0 152 | * @param array $new_instance New settings. 153 | * @param array $old_instance Previous settings. 154 | * @return array Updated settings. 155 | */ 156 | public function update ( $new_instance, $old_instance ) { 157 | $instance = $old_instance; 158 | 159 | /* Strip tags for title and name to remove HTML (important for text inputs). */ 160 | $instance['title'] = strip_tags( $new_instance['title'] ); 161 | 162 | /* Make sure the integer values are definitely integers. */ 163 | $instance['limit'] = intval( $new_instance['limit'] ); 164 | $instance['specific_id'] = intval( $new_instance['specific_id'] ); 165 | 166 | if( is_numeric( $new_instance['size'] ) ){ 167 | $instance['size'] = intval( $new_instance['size'] ); 168 | } else { 169 | $size = sanitize_title_with_dashes( $new_instance['size'] ); 170 | $instance['size'] = in_array( $size, get_intermediate_image_sizes() ) ? $size : 'thumbnail'; 171 | } 172 | 173 | $instance['per_row'] = intval( $new_instance['per_row'] ); 174 | $instance['category'] = intval( $new_instance['category'] ); 175 | 176 | /* The checkbox is returning a Boolean (true/false), so we check for that. */ 177 | $instance['link_title'] = (bool) esc_attr( $new_instance['link_title'] ); 178 | $instance['custom_links_only'] = (bool) esc_attr( $new_instance['custom_links_only'] ); 179 | 180 | /* The select box is returning a text value, so we escape it. */ 181 | $instance['orderby'] = esc_attr( $new_instance['orderby'] ); 182 | $instance['order'] = esc_attr( $new_instance['order'] ); 183 | 184 | return $instance; 185 | } // End update() 186 | 187 | /** 188 | * The form on the widget control in the widget administration area. 189 | * Make use of the get_field_id() and get_field_name() function when creating your form elements. This handles the confusing stuff. 190 | * @since 1.0.0 191 | * @param array $instance The settings for this instance. 192 | * @return void 193 | */ 194 | public function form( $instance ) { 195 | 196 | /* Set up some default widget settings. */ 197 | /* Make sure all keys are added here, even with empty string values. */ 198 | $defaults = array( 199 | 'title' => '', 200 | 'limit' => 5, 201 | 'orderby' => 'menu_order', 202 | 'order' => 'DESC', 203 | 'specific_id' => '', 204 | 'size' => 50, 205 | 'per_row' => 3, 206 | 'category' => 0, 207 | 'link_title' => true, 208 | 'custom_links_only' => false 209 | ); 210 | 211 | $instance = wp_parse_args( (array) $instance, $defaults ); 212 | ?> 213 | 214 |

215 | 216 | 217 |

218 | 219 |

220 | 221 | 222 |

223 | 224 |

225 | 226 | 227 |

228 | 229 |

230 | 231 | 232 |

233 | 234 |

235 | 236 | 241 |

242 | 243 |

244 | 245 | 250 |

251 | 252 |

253 | 254 | 'feature-category', 'class' => 'widefat', 'show_option_all' => __( 'All', 'woothemes-features' ), 'id' => $this->get_field_id( 'category' ), 'name' => $this->get_field_name( 'category' ), 'selected' => $instance['category'] ); 256 | wp_dropdown_categories( $dropdown_args ); 257 | ?> 258 |

259 | 260 |

261 | /> 262 | 263 |

264 | 265 |

266 | /> 267 | 268 |

269 | 270 |

271 | 272 | 273 |

274 |

275 | __( 'No Order', 'woothemes-features' ), 286 | 'ID' => __( 'Entry ID', 'woothemes-features' ), 287 | 'title' => __( 'Title', 'woothemes-features' ), 288 | 'date' => __( 'Date Added', 'woothemes-features' ), 289 | 'menu_order' => __( 'Specified Order Setting', 'woothemes-features' ), 290 | 'rand' => __( 'Random Order', 'woothemes-features' ) 291 | ); 292 | } // End get_orderby_options() 293 | 294 | /** 295 | * Get an array of the available order options. 296 | * @since 1.0.0 297 | * @return array 298 | */ 299 | protected function get_order_options () { 300 | return array( 301 | 'ASC' => __( 'Ascending', 'woothemes-features' ), 302 | 'DESC' => __( 'Descending', 'woothemes-features' ) 303 | ); 304 | } // End get_order_options() 305 | } // End Class 306 | 307 | /* Register the widget. */ 308 | add_action( 'widgets_init', create_function( '', 'return register_widget("WooThemes_Widget_Features");' ), 1 ); -------------------------------------------------------------------------------- /lang/woothemes-features-en_GB.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: Features v1.3.1\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: \n" 6 | "PO-Revision-Date: 2013-07-31 12:39:51+0000\n" 7 | "Last-Translator: Matt \n" 8 | "Language-Team: \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Plural-Forms: nplurals=2; plural=n != 1;\n" 13 | "X-Generator: CSL v1.x\n" 14 | "X-Poedit-Language: English\n" 15 | "X-Poedit-Country: UNITED KINGDOM\n" 16 | "X-Poedit-SourceCharset: utf-8\n" 17 | "X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;\n" 18 | "X-Poedit-Basepath: ../\n" 19 | "X-Poedit-Bookmarks: \n" 20 | "X-Poedit-SearchPath-0: .\n" 21 | "X-Textdomain-Support: yes" 22 | 23 | #: classes/class-woothemes-features.php:78 24 | #@ woothemes-features 25 | msgctxt "post type general name" 26 | msgid "Features" 27 | msgstr "" 28 | 29 | #: classes/class-woothemes-features.php:79 30 | #@ woothemes-features 31 | msgctxt "post type singular name" 32 | msgid "Feature" 33 | msgstr "" 34 | 35 | #: classes/class-woothemes-features.php:80 36 | #@ woothemes-features 37 | msgctxt "feature" 38 | msgid "Add New" 39 | msgstr "" 40 | 41 | #: classes/class-woothemes-features-taxonomy.php:103 42 | #: classes/class-woothemes-features.php:81 43 | #, php-format 44 | #@ woothemes-features 45 | msgid "Add New %s" 46 | msgstr "" 47 | 48 | #: classes/class-woothemes-features.php:81 49 | #: classes/class-woothemes-features.php:82 50 | #: classes/class-woothemes-features.php:83 51 | #: classes/class-woothemes-features.php:85 52 | #@ woothemes-features 53 | msgid "Feature" 54 | msgstr "" 55 | 56 | #: classes/class-woothemes-features-taxonomy.php:101 57 | #: classes/class-woothemes-features.php:82 58 | #, php-format 59 | #@ woothemes-features 60 | msgid "Edit %s" 61 | msgstr "" 62 | 63 | #: classes/class-woothemes-features.php:83 64 | #, php-format 65 | #@ woothemes-features 66 | msgid "New %s" 67 | msgstr "" 68 | 69 | #: classes/class-woothemes-features-taxonomy.php:98 70 | #: classes/class-woothemes-features.php:84 71 | #, php-format 72 | #@ woothemes-features 73 | msgid "All %s" 74 | msgstr "" 75 | 76 | #: classes/class-woothemes-features.php:84 77 | #: classes/class-woothemes-features.php:86 78 | #: classes/class-woothemes-features.php:87 79 | #: classes/class-woothemes-features.php:88 80 | #: classes/class-woothemes-features.php:90 81 | #: classes/class-woothemes-widget-features.php:44 82 | #@ woothemes-features 83 | msgid "Features" 84 | msgstr "" 85 | 86 | #: classes/class-woothemes-features.php:85 87 | #, php-format 88 | #@ woothemes-features 89 | msgid "View %s" 90 | msgstr "" 91 | 92 | #: classes/class-woothemes-features.php:86 93 | #, php-format 94 | #@ woothemes-features 95 | msgid "Search %a" 96 | msgstr "" 97 | 98 | #: classes/class-woothemes-features.php:87 99 | #, php-format 100 | #@ woothemes-features 101 | msgid "No %s Found" 102 | msgstr "" 103 | 104 | #: classes/class-woothemes-features.php:88 105 | #, php-format 106 | #@ woothemes-features 107 | msgid "No %s Found In Trash" 108 | msgstr "" 109 | 110 | #: classes/class-woothemes-features.php:165 111 | #@ woothemes-features 112 | msgid "Image" 113 | msgstr "" 114 | 115 | #: classes/class-woothemes-features.php:199 116 | #, php-format 117 | #@ woothemes-features 118 | msgid "Feature updated. %sView feature%s" 119 | msgstr "" 120 | 121 | #: classes/class-woothemes-features.php:200 122 | #@ woothemes-features 123 | msgid "Custom field updated." 124 | msgstr "" 125 | 126 | #: classes/class-woothemes-features.php:201 127 | #@ woothemes-features 128 | msgid "Custom field deleted." 129 | msgstr "" 130 | 131 | #: classes/class-woothemes-features.php:202 132 | #@ woothemes-features 133 | msgid "Feature updated." 134 | msgstr "" 135 | 136 | #. translators: %s: date and time of the revision 137 | #: classes/class-woothemes-features.php:204 138 | #, php-format 139 | #@ woothemes-features 140 | msgid "Feature restored to revision from %s" 141 | msgstr "" 142 | 143 | #: classes/class-woothemes-features.php:205 144 | #, php-format 145 | #@ woothemes-features 146 | msgid "Feature published. %sView feature%s" 147 | msgstr "" 148 | 149 | #: classes/class-woothemes-features.php:206 150 | #@ default 151 | msgid "Feature saved." 152 | msgstr "" 153 | 154 | #: classes/class-woothemes-features.php:207 155 | #, php-format 156 | #@ woothemes-features 157 | msgid "Feature submitted. %sPreview feature%s" 158 | msgstr "" 159 | 160 | #: classes/class-woothemes-features.php:208 161 | #, php-format 162 | #@ woothemes-features 163 | msgid "Feature scheduled for: %1$s. %2$sPreview feature%3$s" 164 | msgstr "" 165 | 166 | #: classes/class-woothemes-features.php:210 167 | #@ default 168 | msgid "M j, Y @ G:i" 169 | msgstr "" 170 | 171 | #: classes/class-woothemes-features.php:211 172 | #, php-format 173 | #@ woothemes-features 174 | msgid "Feature draft updated. %sPreview feature%s" 175 | msgstr "" 176 | 177 | #: classes/class-woothemes-features.php:324 178 | #@ woothemes-features 179 | msgid "Enter the feature title here" 180 | msgstr "" 181 | 182 | #: classes/class-woothemes-widget-features.php:42 183 | #@ woothemes-features 184 | msgid "Recent features listed on your site." 185 | msgstr "" 186 | 187 | #: classes/class-woothemes-widget-features.php:159 188 | #@ woothemes-features 189 | msgid "Title (optional):" 190 | msgstr "" 191 | 192 | #: classes/class-woothemes-widget-features.php:164 193 | #@ woothemes-features 194 | msgid "Limit:" 195 | msgstr "" 196 | 197 | #: classes/class-woothemes-widget-features.php:169 198 | #@ woothemes-features 199 | msgid "Image Size (in pixels):" 200 | msgstr "" 201 | 202 | #: classes/class-woothemes-widget-features.php:179 203 | #@ woothemes-features 204 | msgid "Order By:" 205 | msgstr "" 206 | 207 | #: classes/class-woothemes-widget-features.php:188 208 | #@ woothemes-features 209 | msgid "Order Direction:" 210 | msgstr "" 211 | 212 | #: classes/class-woothemes-widget-features.php:205 213 | #@ woothemes-features 214 | msgid "Specific ID (optional):" 215 | msgstr "" 216 | 217 | #: classes/class-woothemes-widget-features.php:219 218 | #@ woothemes-features 219 | msgid "No Order" 220 | msgstr "" 221 | 222 | #: classes/class-woothemes-widget-features.php:220 223 | #@ woothemes-features 224 | msgid "Entry ID" 225 | msgstr "" 226 | 227 | #: classes/class-woothemes-widget-features.php:221 228 | #@ woothemes-features 229 | msgid "Title" 230 | msgstr "" 231 | 232 | #: classes/class-woothemes-widget-features.php:222 233 | #@ woothemes-features 234 | msgid "Date Added" 235 | msgstr "" 236 | 237 | #: classes/class-woothemes-widget-features.php:223 238 | #@ woothemes-features 239 | msgid "Specified Order Setting" 240 | msgstr "" 241 | 242 | #: classes/class-woothemes-widget-features.php:235 243 | #@ woothemes-features 244 | msgid "Ascending" 245 | msgstr "" 246 | 247 | #: classes/class-woothemes-widget-features.php:236 248 | #@ woothemes-features 249 | msgid "Descending" 250 | msgstr "" 251 | 252 | #: classes/class-woothemes-features.php:225 253 | #@ woothemes-features 254 | msgid "Feature Details" 255 | msgstr "" 256 | 257 | #: classes/class-woothemes-features.php:350 258 | #@ woothemes-features 259 | msgid "URL" 260 | msgstr "" 261 | 262 | #: classes/class-woothemes-features.php:351 263 | #@ woothemes-features 264 | msgid "Enter a URL that applies to this feature (for example: http://woothemes.com/)." 265 | msgstr "" 266 | 267 | #: classes/class-woothemes-widget-features.php:174 268 | #@ woothemes-features 269 | msgid "Items Per Row:" 270 | msgstr "" 271 | 272 | #: classes/class-woothemes-widget-features.php:208 273 | #@ woothemes-features 274 | msgid "Display a specific feature, rather than a list." 275 | msgstr "" 276 | 277 | #: classes/class-woothemes-widget-features.php:224 278 | #@ woothemes-features 279 | msgid "Random Order" 280 | msgstr "" 281 | 282 | #: classes/class-woothemes-features-taxonomy.php:71 283 | #@ woothemes-features 284 | msgid "Category" 285 | msgstr "" 286 | 287 | #: classes/class-woothemes-features-taxonomy.php:72 288 | #@ woothemes-features 289 | msgid "Categories" 290 | msgstr "" 291 | 292 | #: classes/class-woothemes-features-taxonomy.php:95 293 | #, php-format 294 | #@ woothemes-features 295 | msgctxt "taxonomy general name" 296 | msgid "%s" 297 | msgstr "" 298 | 299 | #: classes/class-woothemes-features-taxonomy.php:96 300 | #, php-format 301 | #@ woothemes-features 302 | msgctxt "taxonomy singular name" 303 | msgid "%s" 304 | msgstr "" 305 | 306 | #: classes/class-woothemes-features-taxonomy.php:97 307 | #, php-format 308 | #@ woothemes-features 309 | msgid "Search %s" 310 | msgstr "" 311 | 312 | #: classes/class-woothemes-features-taxonomy.php:99 313 | #, php-format 314 | #@ woothemes-features 315 | msgid "Parent %s" 316 | msgstr "" 317 | 318 | #: classes/class-woothemes-features-taxonomy.php:100 319 | #, php-format 320 | #@ woothemes-features 321 | msgid "Parent %s:" 322 | msgstr "" 323 | 324 | #: classes/class-woothemes-features-taxonomy.php:102 325 | #, php-format 326 | #@ woothemes-features 327 | msgid "Update %s" 328 | msgstr "" 329 | 330 | #: classes/class-woothemes-features-taxonomy.php:104 331 | #, php-format 332 | #@ woothemes-features 333 | msgid "New %s Name" 334 | msgstr "" 335 | 336 | #: classes/class-woothemes-features-taxonomy.php:105 337 | #, php-format 338 | #@ woothemes-features 339 | msgid "%s" 340 | msgstr "" 341 | 342 | #: classes/class-woothemes-widget-features.php:197 343 | #@ woothemes-features 344 | msgid "Category:" 345 | msgstr "" 346 | 347 | #: classes/class-woothemes-widget-features.php:199 348 | #@ woothemes-features 349 | msgid "All" 350 | msgstr "" 351 | 352 | #: classes/class-woothemes-features.php:94 353 | #@ woothemes-features 354 | msgctxt "single post url slug" 355 | msgid "feature" 356 | msgstr "" 357 | 358 | #: classes/class-woothemes-features.php:95 359 | #@ woothemes-features 360 | msgctxt "post archive url slug" 361 | msgid "features" 362 | msgstr "" 363 | 364 | -------------------------------------------------------------------------------- /lang/woothemes-features-xx_XX.pot: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: PlaceHolder\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: \n" 6 | "PO-Revision-Date: 2012-10-17 12:43:24+0000\n" 7 | "Last-Translator: none\n" 8 | "Language-Team: \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Plural-Forms: nplurals=2; plural=n != 1;\n" 13 | "X-Poedit-Language: English\n" 14 | "X-Poedit-Country: UNITED STATES\n" 15 | "X-Poedit-SourceCharset: utf-8\n" 16 | "X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;\n" 17 | "X-Poedit-Basepath: ../\n" 18 | "X-Poedit-Bookmarks: \n" 19 | "X-Poedit-SearchPath-0: .\n" 20 | "X-Textdomain-Support: yes" 21 | 22 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === Features by WooThemes === 2 | Contributors: woothemes, mattyza, jameskoster, hlashbrooke, jeffikus, danieldudzic 3 | Donate link: http://woothemes.com/ 4 | Tags: features, widget, shortcode, template-tag, services 5 | Requires at least: 3.4.2 6 | Tested up to: 4.3.1 7 | Stable tag: 1.5.0 8 | License: GPLv2 or later 9 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 10 | 11 | Show off what features your company, product or service offers, using our shortcode, widget or template tag. 12 | 13 | == Description == 14 | 15 | "Features by WooThemes" is a clean and easy-to-use features showcase management system for WordPress. Load in the features your product, company or services offers, and display them via a shortcode, widget or template tag on your website. 16 | 17 | Looking for a helping hand? [View plugin documentation](http://wordpress.org/extend/plugins/features-by-woothemes/other_notes/). 18 | 19 | Looking to contribute code to this plugin? [Fork the repository over at GitHub](http://github.com/woothemes/features/). 20 | (submit pull requests to the "develop" branch) 21 | 22 | == Usage == 23 | 24 | To display your features via a theme or a custom plugin, please use the following code: 25 | 26 | `` 27 | 28 | To add arguments to this, please use any of the following arguments, using the syntax provided below: 29 | 30 | * 'limit' => 5 (the maximum number of items to display) 31 | * 'orderby' => 'menu_order' (how to order the items - accepts all default WordPress ordering options) 32 | * 'order' => 'DESC' (the order direction) 33 | * 'id' => 0 (display a specific item) 34 | * 'echo' => true (whether to display or return the data - useful with the template tag) 35 | * 'size' => 50 (the pixel dimensions of the image) 36 | * 'per_row' => 3 (when creating rows, how many items display in a single row?) 37 | * 'link_title' => true (link the feature's title to it's permalink) 38 | * 'custom_links_only' => true (link the feature's title only if a custom URL is set) 39 | * 'title' => '' (an optional title) 40 | * 'before' => '<div class="widget widget_woothemes_features">' (the starting HTML, wrapping the features) 41 | * 'after' => '</div>' (the ending HTML, wrapping the features) 42 | * 'before_title' => '<h2>' (the starting HTML, wrapping the title) 43 | * 'after_title' => '</h2>' (the ending HTML, wrapping the title) 44 | * 'category' => 0 (the ID/slug of the category to filter by) 45 | 46 | The various options for the "orderby" parameter are: 47 | 48 | * 'none' 49 | * 'ID' 50 | * 'author' 51 | * 'title' 52 | * 'date' 53 | * 'modified' 54 | * 'parent' 55 | * 'rand' 56 | * 'comment_count' 57 | * 'menu_order' 58 | * 'meta_value' 59 | * 'meta_value_num' 60 | 61 | ` 10, 'link_title' => false ) ); ?>` 62 | 63 | The same arguments apply to the shortcode which is `[woothemes_features]` and the template tag, which is ``. 64 | 65 | == Usage Examples == 66 | 67 | Adjusting the limit and image dimension, using the arguments in the three possible methods: 68 | 69 | do_action() call: 70 | 71 | ` 10, 'size' => 100 ) ); ?>` 72 | 73 | woothemes_features() template tag: 74 | 75 | ` 10, 'size' => 100 ) ); ?>` 76 | 77 | [woothemes_features] shortcode: 78 | 79 | `[woothemes_features limit="10" size="100"]` 80 | 81 | == Installation == 82 | 83 | Installing "Features by WooThemes" can be done either by searching for "Features by WooThemes" via the "Plugins > Add New" screen in your WordPress dashboard, or by using the following steps: 84 | 85 | 1. Download the plugin via WordPress.org. 86 | 1. Upload the ZIP file through the "Plugins > Add New > Upload" screen in your WordPress dashboard. 87 | 1. Activate the plugin through the 'Plugins' menu in WordPress 88 | 1. Place `` in your templates, or use the provided widget or shortcode. 89 | 90 | == Frequently Asked Questions == 91 | 92 | = The plugin looks unstyled when I activate it. Why is this? = 93 | 94 | "Features by WooThemes" is a lean plugin that aims to keep it's purpose as clean and clear as possible. Thus, we don't load any preset CSS styling, to allow full control over the styling within your theme or child theme. 95 | 96 | = How do I contribute? = 97 | 98 | We encourage everyone to contribute their ideas, thoughts and code snippets. This can be done by forking the [repository over at GitHub](http://github.com/woothemes/features/). 99 | 100 | = Can I make feature links open in a new window / tab? = 101 | 102 | You sure can, just use the following snippet: 103 | 104 | `add_filter( 'woothemes_features_disable_external_links', '__return_false' );` 105 | 106 | == Screenshots == 107 | 108 | 1. The features management screen within the WordPress admin. 109 | 110 | == Upgrade Notice == 111 | 112 | = 1.5.0 = 113 | * Add argument to features widget to accept image pixel size or thumbnail name. 114 | * Adds basic front-end layout styling. 115 | 116 | = 1.4.4 = 117 | * Removes deprecated constructor call for WP_Widget, action hook fix. 118 | 119 | = 1.4.0 = 120 | * WordPress 3.8 support (3.8 is now the minimum required version). 121 | * Adds the ability to link only features with a custom URL set. 122 | 123 | = 1.3.1 = 124 | * Adds filters for the single features and features archives URL slugs 125 | * Adds a flush_rewrite_rules() call on plugin activation 126 | 127 | = 1.3.0 = 128 | * Adds "woothemes_features_content" filter and shortcode support. Adds "feature-category" taxonomy. 129 | 130 | = 1.2.2 = 131 | * Minor bugfixes to the "order" directions options and additions to the "woothemes_features_html" filter. 132 | 133 | = 1.2.1 = 134 | * Minor bugfix to the output of the "Features" widget. 135 | 136 | = 1.2.0 = 137 | * Adds basic WPML support. 138 | * Enhancements to the widget output. 139 | * Adds new arguments for controlling the HTML wrapping the features, as well as wrapping the title. 140 | * Ads support for the excerpt. 141 | 142 | = 1.1.0 = 143 | * Adds "URL" custom field. 144 | * Adds "link_title" option to the shortcode. 145 | * Routine plugin maintenance. 146 | 147 | = 1.0.0 = 148 | * Initial release. Woo! 149 | 150 | == Changelog == 151 | 152 | = 1.5.0 = 153 | * 2015.11.20 154 | * Update - add argument to features widget for pixel size or image thumbnail name. 155 | * New - Adds basic front-end layout styling. 156 | 157 | = 1.4.4 = 158 | * 2015.07.06 159 | * Fix - Action hook typo (props helgatheviking). 160 | * Removes deprecated constructor call for WP_Widget 161 | 162 | = 1.4.3 = 163 | * 2014.08.18 164 | * Tweak - Made post type args filterable (props lkraav). 165 | 166 | = 1.4.2 = 167 | * 2014-02-03 168 | * Fix - Link title options in the widget. 169 | 170 | = 1.4.1 = 171 | * 2014-01-30 172 | * New - Filter to set feature links to open in a new window. 173 | * Fix - Widget image size option. 174 | * Tweak - Better WPML integration. 175 | 176 | = 1.4.0 = 177 | * 2014-01-17 178 | * UI tweaks for WordPress 3.8. 179 | * Default args are now filterable via woothemes_features_default_args. 180 | * Adds the ability to link only features with a custom URL set. 181 | * Adds a new %%PERMALINK%% tag to the templating engine. 182 | * Adjusts the 'id' parameter to cater for multipe ID values. 183 | 184 | = 1.3.1 = 185 | * 2013-08-01. 186 | * Adds "woothemes_features_single_slug" as a filter for the single feature URL slug 187 | * Adds "woothemes_features_archive_slug" as a filter for the features archive URL slug 188 | * Adds a flush_rewrite_rules() call on plugin activation 189 | 190 | = 1.3.0 = 191 | * 2013-04-30. 192 | * Adds "woothemes_features_content" filter for modifying the content of features when outputting the features list. 193 | * Adds default filters to the "woothemes_features_content" hook, enabling shortcodes in the content or excerpt fields. 194 | * Adds "feature-category" taxonomy and necessary logic for displaying features from a specified category. 195 | * Adds "columns-X" class to the ".features" DIV tag, for easier styling, using the "per_row" attribute. 196 | 197 | = 1.2.2 = 198 | * 2013-01-03 199 | * Fix the "order" direction options to be in capitals. 200 | * Enhance the "woothemes_features_html" filter. 201 | * Make sure to use the_content() if there is no custom excerpt. 202 | * Add support for ordering by "rand" to the widget. 203 | * Allow the "size" parameter to receive an array of dimensions. 204 | 205 | = 1.2.1 = 206 | * 2012-11-29 207 | * Makes sure the ending wrapping markup for the widget is declared in the appropriate location, before calling the woothemes_features() function. 208 | 209 | = 1.2.0 = 210 | * 2012-11-27 211 | * Adds basic WPML support to the get_features() method. 212 | * Moves the "title" outside of the ".features" DIV tag. 213 | * Adds "before" and "after" arguments for filtering the HTML for the container. Integrate the $before_widget and $after widget variables to use these parameters with the widget. 214 | * If the "link title" option is enabled, link the image as well. 215 | * Adds "before_title" and "after_title" arguments, for filtering the title's wrapping HTML. Integrate the $before_title and $after_title widget variables to use these parameters with the widget. 216 | * Adds support for the excerpt. 217 | 218 | = 1.1.0 = 219 | * 2012-11-08 220 | * Adds "link_title" option to the shortcode. 221 | * Adds "URL" custom field, to use in place of linking to the permalink, if it is specified. 222 | 223 | = 1.0.1 = 224 | * 2012-11-06 225 | * Tweak - first / last classes applied regardless 226 | 227 | = 1.0.0 = 228 | * 2012-10-23 229 | * Initial release. Woo! -------------------------------------------------------------------------------- /woothemes-features-template.php: -------------------------------------------------------------------------------- 1 | get_features( $args ); 14 | } // End woothemes_get_features() 15 | } 16 | 17 | /** 18 | * Enable the usage of do_action( 'woothemes_features' ) to display features within a theme/plugin. 19 | * 20 | * @since 1.0.0 21 | */ 22 | add_action( 'woothemes_features', 'woothemes_features' ); 23 | 24 | if ( ! function_exists( 'woothemes_features' ) ) { 25 | /** 26 | * Display or return HTML-formatted testimonials. 27 | * @param string/array $args Arguments. 28 | * @since 1.0.0 29 | * @return string 30 | */ 31 | function woothemes_features ( $args = '' ) { 32 | global $post; 33 | 34 | $defaults = apply_filters( 'woothemes_features_default_args', array( 35 | 'limit' => 5, 36 | 'orderby' => 'menu_order', 37 | 'order' => 'DESC', 38 | 'id' => 0, 39 | 'echo' => true, 40 | 'size' => 150, 41 | 'per_row' => 3, 42 | 'link_title' => true, 43 | 'custom_links_only' => true, 44 | 'title' => '', 45 | 'before' => '
', 46 | 'after' => '
', 47 | 'before_title' => '

', 48 | 'after_title' => '

', 49 | 'category' => 0 50 | ) ); 51 | 52 | $args = wp_parse_args( $args, $defaults ); 53 | 54 | // Allow child themes/plugins to filter here. 55 | $args = apply_filters( 'woothemes_features_args', $args ); 56 | $html = ''; 57 | 58 | do_action( 'woothemes_features_before', $args ); 59 | 60 | // The Query. 61 | $query = woothemes_get_features( $args ); 62 | 63 | // The Display. 64 | if ( ! is_wp_error( $query ) && is_array( $query ) && count( $query ) > 0 ) { 65 | $html .= $args['before'] . "\n"; 66 | 67 | if ( '' != $args['title'] ) { 68 | $html .= $args['before_title'] . esc_html( $args['title'] ) . $args['after_title'] . "\n"; 69 | } 70 | 71 | $html .= '
' . "\n"; 72 | 73 | // Begin templating logic. 74 | $tpl = '
%%IMAGE%%

%%TITLE%%

%%CONTENT%%
'; 75 | $tpl = apply_filters( 'woothemes_features_item_template', $tpl, $args ); 76 | 77 | $i = 0; 78 | foreach ( $query as $post ) { 79 | $template = $tpl; 80 | $i++; 81 | 82 | setup_postdata( $post ); 83 | 84 | $class = 'feature'; 85 | 86 | if( ( 0 == $i % $args['per_row'] ) ) { 87 | $class .= ' last'; 88 | } elseif ( 0 == ( $i - 1 ) % ( $args['per_row'] ) ) { 89 | $class .= ' first'; 90 | } 91 | 92 | if( is_numeric( $args['size'] ) ){ 93 | $image_size = array( $args['size'], $args['size'] ); 94 | } else { 95 | $image_size = $args['size']; 96 | } 97 | 98 | $image_size = apply_filters( 'woothemes_features_image_size', $image_size, $post ); 99 | 100 | $image = get_the_post_thumbnail( $post->ID, $image_size ); 101 | 102 | $title = get_the_title(); 103 | 104 | if ( apply_filters( 'woothemes_features_disable_external_links', true ) ) { 105 | $external = ''; 106 | } else { 107 | $external = 'target="_blank"'; 108 | } 109 | 110 | if ( true == $args['link_title'] && '' != $post->url ) { 111 | $image = '' . $image . ''; 112 | $title = '' . $title . ''; 113 | } 114 | 115 | // Optionally display the image, if it is available. 116 | if ( has_post_thumbnail() ) { 117 | $template = str_replace( '%%IMAGE%%', $image, $template ); 118 | } else { 119 | $template = str_replace( '%%IMAGE%%', '', $template ); 120 | } 121 | 122 | $template = str_replace( '%%CLASS%%', $class, $template ); 123 | $template = str_replace( '%%TITLE%%', $title, $template ); 124 | 125 | $template = str_replace( '%%PERMALINK%%', esc_url( get_permalink( get_the_ID() ) ), $template ); 126 | 127 | if ( '' != $post->post_excerpt ) { 128 | $content = get_the_excerpt(); 129 | } else { 130 | $content = get_the_content(); 131 | } 132 | $content = apply_filters( 'woothemes_features_content', $content, $post ); 133 | $template = str_replace( '%%CONTENT%%', $content, $template ); 134 | 135 | $template = apply_filters( 'woothemes_features_template', $template, $post ); 136 | 137 | $html .= $template; 138 | 139 | if( ( 0 == $i % $args['per_row'] ) ) { 140 | $html .= '
' . "\n"; 141 | } 142 | } 143 | 144 | $html .= '
' . "\n"; 145 | $html .= $args['after'] . "\n"; 146 | 147 | wp_reset_postdata(); 148 | } 149 | 150 | // Allow child themes/plugins to filter here. 151 | $html = apply_filters( 'woothemes_features_html', $html, $query, $args ); 152 | 153 | if ( $args['echo'] != true ) { return $html; } 154 | 155 | // Should only run is "echo" is set to true. 156 | echo $html; 157 | 158 | do_action( 'woothemes_features_after', $args ); // Only if "echo" is set to true. 159 | } // End woothemes_features() 160 | } 161 | 162 | if ( ! function_exists( 'woothemes_features_shortcode' ) ) { 163 | /** 164 | * The shortcode function. 165 | * @since 1.0.0 166 | * @param array $atts Shortcode attributes. 167 | * @param string $content If the shortcode is a wrapper, this is the content being wrapped. 168 | * @return string Output using the template tag. 169 | */ 170 | function woothemes_features_shortcode ( $atts, $content = null ) { 171 | $args = (array)$atts; 172 | 173 | $defaults = array( 174 | 'limit' => 5, 175 | 'orderby' => 'menu_order', 176 | 'order' => 'DESC', 177 | 'id' => 0, 178 | 'echo' => true, 179 | 'size' => 150, 180 | 'per_row' => 3, 181 | 'link_title' => true, 182 | 'custom_links_only' => false, 183 | 'category' => 0 184 | ); 185 | 186 | $args = shortcode_atts( $defaults, $atts ); 187 | 188 | // Make sure we return and don't echo. 189 | $args['echo'] = false; 190 | 191 | // Fix integers. 192 | if ( isset( $args['limit'] ) ) $args['limit'] = intval( $args['limit'] ); 193 | if ( isset( $args['id'] ) ) $args['id'] = intval( $args['id'] ); 194 | 195 | if ( isset( $args['size'] ) ){ 196 | if( is_numeric( $args['size'] ) ){ 197 | $args['size'] = intval( $args['size'] ); 198 | } else { 199 | $size = sanitize_title_with_dashes( $args['size'] ); 200 | $args['size'] = in_array( $size, get_intermediate_image_sizes() ) ? $size : 'thumbnail'; 201 | } 202 | } 203 | 204 | if ( isset( $args['per_row'] ) && ( 0 < intval( $args['per_row'] ) ) ) $args['per_row'] = intval( $args['per_row'] ); 205 | if ( isset( $args['category'] ) && is_numeric( $args['category'] ) ) $args['category'] = intval( $args['category'] ); 206 | 207 | // Fix booleans. 208 | foreach ( array( 'link_title', 'custom_links_only' ) as $k => $v ) { 209 | if ( isset( $args[$v] ) && ( 'true' == $args[$v] ) ) { 210 | $args[$v] = true; 211 | } else { 212 | $args[$v] = false; 213 | } 214 | } 215 | 216 | return woothemes_features( $args ); 217 | } // End woothemes_features_shortcode() 218 | } 219 | 220 | add_shortcode( 'woothemes_features', 'woothemes_features_shortcode' ); 221 | 222 | if ( ! function_exists( 'woothemes_features_content_default_filters' ) ) { 223 | /** 224 | * Adds default filters to the "woothemes_features_content" filter point. 225 | * @since 1.3.0 226 | * @return void 227 | */ 228 | function woothemes_features_content_default_filters () { 229 | add_filter( 'woothemes_features_content', 'do_shortcode' ); 230 | } // End woothemes_features_content_default_filters() 231 | 232 | add_action( 'woothemes_features_before', 'woothemes_features_content_default_filters' ); 233 | } 234 | ?> -------------------------------------------------------------------------------- /woothemes-features.php: -------------------------------------------------------------------------------- 1 | version = '1.5.0'; --------------------------------------------------------------------------------