PluginProbe
Same Category Posts / 1.1.5
Same Category Posts v1.1.5
1.2.0 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 1.1.20 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 trunk 1.0 1.0.1 1.0.10 1.0.11 1.0.12 All 36 releases
same-category-posts / same-category-posts.php

same-category-posts.php in Same Category Posts 1.1.5, at same-category-posts.php

1,052 lines 42.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Same Category Posts
4 Plugin URI: https://wordpress.org/plugins/same-category-posts/
5 Description: Adds a widget that shows the most recent posts from a single category.
6 Author: Daniel Floeter
7 Version: 1.1.5
8 Author URI: https://profiles.wordpress.org/kometschuh/
9 */
10
11 namespace sameCategoryPosts;
12
13 // Don't call the file directly
14 if ( !defined( 'ABSPATH' ) ) exit;
15
16 define( 'SAME_CATEGORY_POSTS_VERSION', "1.1.1");
17
18 /**
19 * Register our styles
20 *
21 * @return void
22 */
23 function same_category_posts_styles() {
24 wp_register_style( 'same-category-posts', plugins_url( 'same-category-posts/same-category-posts.css' ) );
25 wp_enqueue_style( 'same-category-posts' );
26 }
27 add_action( 'wp_enqueue_scripts', __NAMESPACE__.'\same_category_posts_styles' );
28
29 /**
30 * Register our admin scripts
31 *
32 * @return void
33 */
34 function same_category_posts_admin_scripts($hook) {
35 wp_register_script( 'same_category-posts-admin-js', plugins_url( 'same-category-posts/js/admin/same-category-posts.js' ), array('jquery') , SAME_CATEGORY_POSTS_VERSION , true );
36 wp_enqueue_script( 'same_category-posts-admin-js' );
37 }
38 add_action('admin_enqueue_scripts', __NAMESPACE__.'\same_category_posts_admin_scripts');
39
40 /**
41 * Add styles for widget sections
42 *
43 */
44 function admin_styles() {
45 ?>
46 <style>
47 .same-category-widget-cont h4 {
48 padding: 12px 15px;
49 cursor: pointer;
50 margin: 5px 0;
51 border: 1px solid #E5E5E5;
52 }
53 .same-category-widget-cont h4:first-child {
54 margin-top: 10px;
55 }
56 .same-category-widget-cont h4:last-of-type {
57 margin-bottom: 10px;
58 }
59 .same-category-widget-cont h4:after {
60 float:right;
61 font-family: "dashicons";
62 content: '\f140';
63 -ms-transform: translate(-1px,1px);
64 -webkit-transform: translate(-1px,1px);
65 -moz-transform: translate(-1px,1px);
66 transform: translate(-1px,1px);
67 -ms-transition: all 600ms;
68 -webkit-transition: all 600ms;
69 -moz-transition: all 600ms;
70 transition: all 600ms;
71 }
72 .same-category-widget-cont h4.open:after {
73 -ms-transition: all 600ms;
74 -webkit-transition: all 600ms;
75 -moz-transition: all 600ms;
76 transition: all 600ms;
77 -ms-transform: rotate(180deg);
78 -webkit-transform: rotate(180deg);
79 -moz-transform: rotate(180deg);
80 transform: rotate(180deg);
81 }
82 .same-category-widget-cont > div {
83 display:none;
84 overflow: hidden;
85 }
86 .same-category-widget-cont > div.open {
87 display:block;
88 }
89 <?php //disable taxterms?>
90 select[disabled] {
91 background: #ececec !important;
92 }
93
94 select[disabled] option {
95 color: #c3c3c3;
96 }
97 </style>
98 <?php
99 }
100
101 add_action( 'admin_print_styles-widgets.php', __NAMESPACE__.'\admin_styles' );
102
103 /**
104 * Get image size
105 *
106 * $thumb_w, $thumb_h - the width and height of the thumbnail in the widget settings
107 * $image_w,$image_h - the width and height of the actual image being displayed
108 *
109 * return: an array with the width and height of the element containing the image
110 */
111 function same_category_posts_get_image_size( $thumb_w,$thumb_h,$image_w,$image_h) {
112
113 $image_size = array('image_h' => $thumb_h, 'image_w' => $thumb_w, 'marginAttr' => '', 'marginVal' => '');
114 $relation_thumbnail = $thumb_w / $thumb_h;
115 $relation_cropped = $image_w / $image_h;
116
117 if ($relation_thumbnail < $relation_cropped) {
118 // crop left and right site
119 // thumbnail width/height ration is smaller, need to inflate the height of the image to thumb height
120 // and adjust width to keep aspect ration of image
121 $image_size['image_h'] = $thumb_h;
122 $image_size['image_w'] = $thumb_h / $image_h * $image_w;
123 $image_size['marginAttr'] = 'margin-left';
124 $image_size['marginVal'] = ($image_size['image_w'] - $thumb_w) / 2;
125 } else {
126 // crop top and bottom
127 // thumbnail width/height ration is bigger, need to inflate the width of the image to thumb width
128 // and adjust height to keep aspect ration of image
129 $image_size['image_w'] = $thumb_w;
130 $image_size['image_h'] = $thumb_w / $image_w * $image_h;
131 $image_size['marginAttr'] = 'margin-top';
132 $image_size['marginVal'] = ($image_size['image_h'] - $thumb_h) / 2;
133 }
134
135 return $image_size;
136 }
137
138 /**
139 * Related Posts Widget Class
140 *
141 * Shows posts from same category with some configurable options
142 */
143 class Widget extends \WP_Widget {
144
145 function __construct() {
146 $widget_ops = array('classname' => 'same-category-posts', 'description' => __('List posts from same category in sidebar based on shown post\'s category'));
147 parent::__construct('same-category-posts', __('Same Category Posts'), $widget_ops);
148 }
149
150 /*
151 override the thumbnail htmo to insert cropping when needed
152 */
153 function post_thumbnail_html( $size ){
154 global $post;
155
156 $post_thumbnail_id = get_post_thumbnail_id( $post->ID );
157 if ( ! $post_thumbnail_id && $this->instance['default_thunmbnail'] ) {
158 $post_thumbnail_id = $this->instance['default_thunmbnail'];
159 }
160
161 // Don't use the thumbnail, if it is cropped
162 $thumbSize = array();
163 foreach ( get_intermediate_image_sizes() as $thumb ) {
164 if ( in_array( $thumb, array('thumbnail') ) ) {
165 $thumbSize['width'] = get_option( "{$thumb}_size_w" );
166 $thumbSize['height'] = get_option( "{$thumb}_size_h" );
167 $thumbSize['crop'] = (bool) get_option( "{$thumb}_crop" );
168 }
169 }
170 if ( $thumbSize['crop'] ) {
171 $thumbSize[0] = $size[0] <= $thumbSize['width'] ? ( $thumbSize['width'] + 1 ) : $size[0];
172 $thumbSize[1] = $size[1] <= $thumbSize['height'] ? ( $thumbSize['height'] + 1 ) : $size[1];
173 }
174
175 // HTML generated by the core APIs.
176 $html = wp_get_attachment_image( $post_thumbnail_id, $thumbSize, false );
177
178 if ( empty( $this->instance['thumb_w'] ) || empty( $this->instance['thumb_h'] ) ){
179 return $html; // bail out if no full dimensions defined
180 }
181
182 $meta = image_get_intermediate_size($post_thumbnail_id,$size);
183
184 $post_img = wp_get_attachment_metadata($post_thumbnail_id, $size);
185 $meta['file'] = basename( $post_img['file'] );
186
187 $origfile = get_attached_file( $post_thumbnail_id, true); // the location of the full file
188 $file = dirname($origfile) .'/'.$meta['file']; // the location of the file displayed as thumb
189 list( $width, $height ) = getimagesize($file); // get actual size of the thumb file
190
191 if ($width / $height == $this->instance['thumb_w'] / $this->instance['thumb_h']) {
192 // image is same ratio as asked for, nothing to do here as the browser will handle it correctly
193 ;
194 } else if (isset($this->instance['use_css_cropping'])) {
195 $image = same_category_posts_get_image_size( $this->instance['thumb_w'], $this->instance['thumb_h'], $width, $height );
196
197 // replace srcset
198 $array = array();
199 preg_match( '/width="([^"]*)"/i', $html, $array ) ;
200 $pattern = "/".$array[1]."w/";
201 $html = preg_replace($pattern, $image['image_w']."w", $html);
202 // replace size
203 $pattern = "/".$array[1]."px/";
204 $html = preg_replace($pattern, $image['image_w']."px", $html);
205 // replace width
206 $pattern = "/width=\"[0-9]*\"/";
207 $html = preg_replace($pattern, "width='".$image['image_w']."'", $html);
208 // replace height
209 $pattern = "/height=\"[0-9]*\"/";
210 $html = preg_replace($pattern, "height='".$image['image_h']."'", $html);
211 // set margin
212 $html = str_replace('<img ','<img style="'.$image['marginAttr'].':-'.$image['marginVal'].'px;height:'.$image['image_h']
213 .'px;clip:rect(auto,'.($this->instance['thumb_w']+$image['marginVal']).'px,auto,'.$image['marginVal']
214 .'px);width:auto;max-width:initial;" ',$html);
215 // wrap span
216 $html = '<span style="width:'.$this->instance['thumb_w'].'px;height:'.$this->instance['thumb_h'].'px;">'
217 .$html.'</span>';
218 } else {
219 // if use_css_cropping not used
220 // no interface changes: leave without change
221 }
222 return $html;
223 }
224
225 /*
226 wrapper to execute the the_post_thumbnail with filters
227 */
228 function the_post_thumbnail($size= 'post-thumbnail',$attr='') {
229 if (empty($size)) // if junk value, make it a normal thumb
230 $size= 'post-thumbnail';
231 else if (is_array($size) && (count($size)==2)) { // good format at least
232 // normalize to ints first
233 $size[0] = (int) $size[0];
234 $size[1] = (int) $size[1];
235 if (($size[0] == 0) && ($size[1] == 0)) //both values zero then revert to thumbnail
236 $size= 'post-thumbnail';
237 // if one value is zero make a square using the other value
238 else if (($size[0] == 0) && ($size[1] != 0))
239 $size[0] = $size[1];
240 else if (($size[0] != 0) && ($size[1] == 0))
241 $size[1] = $size[0];
242 } else {
243 $size= 'post-thumbnail'; // yet another form of junk
244 }
245
246 // don't use the thumbnail, if it is cropped
247 $thumbSize = array();
248 foreach ( get_intermediate_image_sizes() as $thumb ) {
249 if ( in_array( $thumb, array('thumbnail') ) ) {
250 $thumbSize['width'] = get_option( "{$thumb}_size_w" );
251 $thumbSize['height'] = get_option( "{$thumb}_size_h" );
252 $thumbSize['crop'] = (bool) get_option( "{$thumb}_crop" );
253 }
254 }
255 if ( $sizes['crop'] ) {
256 $size[0] = $size[0] <= $thumbSize['width'] ? ( $thumbSize['width'] + 1 ) : $size[0];
257 $size[1] = $size[1] <= $thumbSize['height'] ? ( $thumbSize['height'] + 1 ) : $size[1];
258 }
259
260 $ret = $this->post_thumbnail_html( $size );
261 return $ret;
262 }
263
264 /**
265 * Calculate the HTML for showing the thumb of a post item.
266 * Expected to be called from a loop with globals properly set
267 *
268 * @param array $instance Array which contains the various settings
269 * @return string The HTML for the thumb related to the post
270 *
271 * @since 1.0.8
272 */
273 function show_thumb($instance) {
274 $ret = '';
275
276 if ( function_exists('the_post_thumbnail') &&
277 current_theme_supports("post-thumbnails") &&
278 isset ( $this->instance["thumb"] ) &&
279 has_post_thumbnail() ) {
280 $ret .= '<a ';
281 $use_css_cropping = isset($this->instance['use_css_cropping']) ? "same-category-post-css-cropping" : "";
282 $ret .= 'class="same-category-post-thumbnail ' . $use_css_cropping . '"';
283 $ret .= 'href="' . get_the_permalink() . '" title="' . get_the_title() . '">';
284 $ret .= $this->the_post_thumbnail( array($this->instance['thumb_w'],$this->instance['thumb_h']));
285 $ret .= '</a>';
286 }
287 return $ret;
288 }
289
290 /**
291 * Excerpt more link filter
292 */
293 function excerpt_more_filter($more) {
294 return ' <a class="cat-post-excerpt-more" href="'. get_permalink() . '">' . esc_html($this->instance["excerpt_more_text"]) . '</a>';
295 }
296
297 /**
298 * Calculate the HTML for a post item based on the widget settings and post.
299 * Expected to be called in an active loop with all the globals set
300 *
301 * @param array $instance Array which contains the various settings
302 * $param null|integer $current_post_id If on singular page specifies the id of
303 * the post, otherwise null
304 * @return string The HTML for item related to the post
305 *
306 * @since 1.0.8
307 */
308 function itemHTML($instance,$current_post_id) {
309 global $post;
310
311 $ret = '<li class="same-category-post-item ' . ($post->ID == $current_post_id ? 'same-category-post-current' : '') . '">';
312
313 if( isset( $instance["thumbTop"] ) ) :
314 $ret .= $this->show_thumb($instance);
315 endif;
316
317 $ret .= '<a class="post-title" href="' . get_the_permalink() . '" rel="bookmark" title="Permanent Link to ' . get_the_title() . '">' . get_the_title() . '</a>';
318
319 if ( isset( $instance['date'] ) ) {
320 if (isset($instance['date_format']) && strlen(trim($instance['date_format'])) > 0)
321 $date_format = $instance['date_format'];
322 else if (isset($instance['use_wp_date_format']) && strlen(trim($instance['use_wp_date_format'])) > 0)
323 $date_format = "";
324 else
325 $date_format = "j M Y";
326
327 $ret .= '<p class="post-date">';
328
329 if (isset($instance["date_link"]) && $instance["date_link"])
330 $ret .= '<a href="'.get_the_permalink().'">';
331
332 $ret .= get_the_date($date_format);
333
334 if (isset($instance["date_link"]) && $instance["date_link"])
335 $ret .= '</a>';
336
337 $ret .= '</p>';
338 }
339
340 if( !isset( $instance["thumbTop"] ) ) :
341 $ret .= $this->show_thumb($instance);
342 endif;
343
344 if ( isset ( $instance['excerpt'] ) ) {
345 $ret .= apply_filters('the_excerpt', get_the_excerpt());;
346 }
347
348 if ( isset ( $instance['comment_num'] ) ) {
349 $ret .= '<p class="same-category-post-comment-num">(' . get_comments_number() . ')</p>';
350 }
351
352 if ( isset( $instance['author'] ) ) {
353 $ret .= '<p class="post-author cat-post-author">';
354 $ret .= get_the_author_posts_link();
355 $ret .= '</p>';
356 }
357
358 $ret .= '</li>';
359 return $ret;
360 }
361 /**
362
363 * Set for each object_taxonomy the hierarchical post_type as default, if no tax is selected
364 *
365 * @param array &$instance
366 * @return by ref
367 */
368 function initPostTypesAndTaxes(&$instance) {
369 $post_types = get_post_types( array( 'publicly_queryable' => true ) );
370 foreach ($post_types as $post_type) {
371 $object_taxes = get_object_taxonomies( $post_type, 'objects' );
372
373 $set_default = true;
374 foreach ( $object_taxes as $tax ) {
375 if (isset($instance['include_tax'][$post_type]) && $instance['include_tax'][$post_type]) {
376 if ($tax->name == $instance['include_tax'][$post_type])
377 $set_default = false;
378 }
379 // put all taxes and the associated post_type
380 if ($tax->hierarchical) {
381 $instance['post_types'][$tax->name] = array( 'post_type'=>$post_type, 'hierarchical'=>true );
382 } else {
383 $instance['post_types'][$tax->name] = array( 'post_type'=>$post_type, 'hierarchical'=>false );
384 }
385 }
386 // put and set only 'default' taxes
387 if ($set_default) {
388 foreach ( $object_taxes as $tax ) {
389 if ($tax->hierarchical) {
390 $instance['include_tax'][$post_type] = $tax->name; // set as 'default'
391 }
392 }
393 }
394 }
395 }
396
397 // Displays a list of posts from same category on single post pages.
398 function widget($args, $instance) {
399 // Only show widget if on a post page.
400 if ( !is_single() ) return;
401
402 global $wp_query;
403 $post_old = $post; // Save the post object.
404 $post = $wp_query->post;
405 $current_post_id = $post->ID;
406
407 extract( $args );
408 $this->instance = $instance;
409
410 $this->initPostTypesAndTaxes($instance);
411
412 $taxonomies = null;
413 $all_taxonomies = null;
414 $taxes = get_object_taxonomies( $post );
415
416 // Get all taxonomies
417 $all_terms = array();
418 foreach ($taxes as $tax) {
419 $terms = get_terms($tax,array('public'=>true), 'objects');
420 foreach ($terms as $id => $name) {
421 $all_terms[$tax][] = $name->term_id;
422 }
423 }
424
425 // Get post taxonomies
426 $categories = null;
427 foreach ($taxes as $tax) {
428 $post_type = $instance['post_types'][$tax]['post_type'];
429 if ($tax == $instance['include_tax'][$post_type]) {
430 $terms = get_the_terms($post->ID, $tax);
431 if ($terms) {
432 foreach ($terms as $term) {
433 $taxonomies[$tax][] = $term->term_id;
434 }
435 }
436 $categories = get_the_terms($post->ID,$tax);
437 }
438 }
439
440 // Excerpt length filter
441 if ( isset($instance["excerpt_length"]) && $instance["excerpt_length"] > 0 ) {
442 $new_excerpt_length = create_function('$length', "return " . $instance["excerpt_length"] . ";");
443 add_filter('excerpt_length', $new_excerpt_length);
444 }
445
446 $valid_sort_orders = array('date', 'title', 'comment_count', 'rand');
447 if ( isset($instance['sort_by']) && in_array($instance['sort_by'], $valid_sort_orders) ) {
448 $sort_by = $instance['sort_by'];
449 $sort_order = (bool) isset( $instance['asc_sort_order'] ) ? 'ASC' : 'DESC';
450 } else {
451 // by default, display latest first
452 $sort_by = 'date';
453 $sort_order = 'DESC';
454 }
455
456 // Excerpt more_text
457 if( isset($instance["excerpt_more_text"]) && ltrim($instance["excerpt_more_text"]) != '' )
458 {
459 add_filter('excerpt_more', array($this,'excerpt_more_filter'));
460 }
461
462 // deprecate >= 1.0.12: 'exclude_categories' get 'exclude_terms'
463 // Exclude categories
464 if (!isset($instance['exclude_terms']['category']) && isset($instance['exclude_categories']) && $instance['exclude_categories'])
465 $instance['exclude_terms'] = array( 'category' => $instance['exclude_categories']);
466
467 // Query args
468 $args = array(
469 'orderby' => $sort_by,
470 'order' => $sort_order
471 );
472
473 $args['post_type'] = array( get_post_type( $post ) );
474
475 if ($taxonomies) {
476 $term_query_in = array('relation' => 'OR');
477 $term_query_not_in = null;
478 foreach ( $taxonomies as $tax=>$terms) {
479 if ( isset($instance['exclude_terms']) && $instance['exclude_terms'] && array_key_exists($tax, $instance['exclude_terms']) ) {
480 $terms = array_diff($terms, $instance['exclude_terms'][$tax]);
481 }
482
483 if ($terms) {
484 $term_query_in[] = array(
485 'taxonomy' => $tax,
486 'field' => 'term_id',
487 'terms' => $terms,
488 'include_children' => isset($instance['exclude_children']) && $instance['exclude_children'] ? false : true,
489 'operator' => 'IN',
490 );
491 }
492
493 $not_terms = array_diff( $all_terms[$tax], $terms );
494 if ( $not_terms ) {
495 $term_query_not_in[] = array(
496 'taxonomy' => $tax,
497 'field' => 'term_id',
498 'terms' => $not_terms,
499 'include_children' => isset( $instance['exclude_no_children'] ) && $instance['exclude_no_children'] ? false : true,
500 'operator' => 'NOT IN',
501 );
502 }
503 }
504 }
505
506 $term_query[] = array('relation' => 'AND');
507 $term_query[] = $term_query_in;
508 $term_query[] = $term_query_not_in;
509
510 if (is_array($term_query))
511 $args['tax_query'] = $term_query;
512
513 $args['post__not_in'] = array();
514 if (isset( $instance['exclude_current_post'] ) && $instance['exclude_current_post']) {
515 $args['post__not_in'] = array( $current_post_id );
516 }
517
518 if(isset( $instance['exclude_sticky_posts'] ) && $instance['exclude_sticky_posts']) {
519 foreach (get_option( 'sticky_posts' ) as $value) {
520 $args['post__not_in'][] = $value;
521 }
522 }
523
524 $args['posts_per_page'] = (isset($instance['num']) && $instance['num']) ? $instance['num'] : -1;
525
526 $my_query = new \WP_Query($args);
527
528 if( $my_query->have_posts() )
529 {
530 echo $before_widget;
531
532 // Widget title
533 if( !isset ( $instance["hide_title"] ) ) {
534 if( isset( $instance["separate_categories"] ) && $instance["separate_categories"] ) {
535 // Separate categories: title to array
536 foreach($categories as $cat) {
537 $widgetHTML[$cat->name]['ID'] = $cat->term_id;
538 if( isset ( $instance["title_link"] ) ) {
539 $title = '<a href="' . get_category_link( $cat ) . '">'. $cat->name . '</a>';
540 if(isset($instance['title']) && strpos($instance['title'], '%cat-all%') !== false)
541 $title = str_replace( "%cat-all%", $title, $instance['title']);
542 else if(isset($instance['title']) && strpos($instance['title'], '%cat%') !== false)
543 $title = str_replace( "%cat%", $title, $instance['title']);
544 $widgetHTML[$cat->name]['title'] = $title;
545 } else {
546 $title = $cat->name;
547 if(isset($instance['title']) && strpos($instance['title'], '%cat-all%') !== false)
548 $title = str_replace( "%cat-all%", $title, $instance['title']);
549 else if(isset($instance['title']) && strpos($instance['title'], '%cat%') !== false)
550 $title = str_replace( "%cat%", $title, $instance['title']);
551 $widgetHTML[$cat->name]['title'] = $title;
552 }
553 }
554 } else {
555 // ! Separate categories: echo
556 echo $before_title;
557 if( isset ( $instance["title_link"] ) ) {
558 $linkList = "";
559 foreach($categories as $cat) {
560 if(isset($instance['exclude_terms']) && $instance['exclude_terms'] && in_array($cat->term_id,$instance['exclude_terms']))
561 continue;
562 $linkList .= '<a href="' . get_category_link( $cat ) . '">'. $cat->name . '</a>, ';
563 }
564 $linkList = trim($linkList, ", ");
565 if( isset($instance['title']) && $instance['title'] ) { // use placeholders if title is not empty
566 if(strpos($instance['title'], '%cat-all%') !== false ||
567 strpos($instance['title'], '%cat%') !== false) { // all-category placeholder is used
568 if(strpos($instance['title'], '%cat-all%') !== false)
569 $linkList = str_replace( "%cat-all%", $linkList, $instance['title']);
570 else if(strpos($instance['title'], '%cat%') !== false)
571 $linkList = str_replace( "%cat%", '<a href="' . get_category_link( $categories[0] ) . '">'. $categories[0]->name . '</a>', $instance['title']);
572 } else // no category placeholder is used
573 $linkList = '<a href="' . get_category_link( $categories[0] ) . '">'. $instance['title'] . '</a>';
574 }
575 echo htmlspecialchars_decode(apply_filters('widget_title',$linkList));
576 } else {
577 $categoryNames = "";
578 if ($categories) {
579 foreach ($categories as $key => $val) {
580 if(isset($instance['exclude_terms']) && $instance['exclude_terms'] && in_array($val->term_id,$instance['exclude_terms'][$val->taxonomy]))
581 continue;
582 $categoryNames .= $val->name . ", ";
583 }
584 $categoryNames = trim($categoryNames, ", ");
585 }
586
587 if( isset($instance['title']) && $instance['title'] ) { // use placeholders if title is not empty
588 if(strpos($instance['title'], '%cat-all%') !== false) // all-category placeholder is used
589 $categoryNames = str_replace( "%cat-all%", $categoryNames, $instance['title']);
590 else if(strpos($instance['title'], '%cat%') !== false) // one-category placeholder is used
591 $categoryNames = str_replace( "%cat%", $categories[0]->name, $instance['title']);
592 else
593 $categoryNames = $instance['title'];
594 }
595 echo htmlspecialchars_decode(apply_filters('widget_title',$categoryNames));
596 }
597 echo $after_title;
598 }
599 }
600 // /Widget title
601
602 // Post list
603 echo "<ul>\n";
604 while ($my_query->have_posts())
605 {
606 $my_query->the_post();
607
608 if( isset( $instance["separate_categories"] ) && $instance["separate_categories"] ) {
609 // Separate categories: get itemHTML to array
610 $object_taxes = get_object_taxonomies( $post, 'objects' );
611 $post_categories = null;
612 foreach ( $object_taxes as $tax ) {
613 $post_type = $instance['post_types'][$tax->name]['post_type'];
614 if ($tax->name == $instance['include_tax'][$post_type]) {
615 $post_categories = get_the_terms($post->ID,$tax->name);
616 break;
617 }
618 }
619 foreach ($post_categories as $val) {
620 $widgetHTML[$val->name][$post->ID]['itemHTML'] = $this->itemHTML($instance,$current_post_id);
621 $widgetHTML[$val->name][$post->ID]['ID'] = $post->ID;
622 }
623 } else {
624 // ! Separate categories: get itemHTML and echo
625 echo $this->itemHTML($instance,$current_post_id);
626 }
627 } // end while
628
629 if (isset( $instance["separate_categories"] ) && $instance["separate_categories"]) {
630 // Separate categories: echo
631 $isOnPage = array();
632 foreach($widgetHTML as $val) {
633 // widget title
634 $haveItemHTML = false;
635 $ret = $before_title . htmlspecialchars_decode(apply_filters('widget_title',isset($val['title'])?$val['title']:"")) . $after_title;
636 $count = 1;
637 $num_per_cat = (isset($instance['num_per_cate'])&&$instance['num_per_cate']!=0?($instance['num_per_cate']):99999);
638 foreach($val as $key) {
639 if(is_array($key) && array_key_exists('itemHTML', $key)) {
640 if( !in_array($key['ID'], $isOnPage) ) {
641 if($count <= $num_per_cat) {
642 $ret .= $key['itemHTML'];
643 $haveItemHTML = true;
644 $isOnPage[] = $key['ID'];
645 } else
646 break;
647 $count++;
648 }
649 }
650 }
651 if ($haveItemHTML)
652 echo $ret;
653 }
654 }
655
656 echo "</ul>\n";
657 // end Post list
658
659 echo $after_widget;
660 }
661
662 if(isset($new_excerpt_length))
663 remove_filter('excerpt_length', $new_excerpt_length);
664 remove_filter('excerpt_more', array($this,'excerpt_more_filter'));
665
666 $post = $post_old; // Restore the post object.
667 }
668
669 /**
670 * Update the options
671 *
672 * @param array $new_instance
673 * @param array $old_instance
674 * @return array
675 */
676 function update($new_instance, $old_instance) {
677
678 return $new_instance;
679 }
680
681 /**
682 * The widget configuration form back end.
683 *
684 * @param array $instance
685 * @return void
686 */
687 function form($instance) {
688
689 // ToDo seperate_cat get seperate_tax (if update, settings)
690
691 $this->initPostTypesAndTaxes($instance);
692
693 $instance = wp_parse_args( ( array ) $instance, array(
694 'title' => '',
695 'hide_title' => '',
696 'separate_categories' => '',
697 'num_per_cate' => '',
698 'num' => '',
699 'exclude_no_children' => '',
700 'exclude_children' => '',
701 'sort_by' => '',
702 'asc_sort_order' => '',
703 'title_link' => '',
704 'exclude_categories' => '',
705 'exclude_terms' => array(),
706 'include_tax' => array(),
707 'post_types' => array(),
708 'exclude_current_post' => '',
709 'exclude_sticky_posts' => '',
710 'author' => '',
711 'date_format' => '',
712 'use_wp_date_format' => '',
713 'date_link' => '',
714 'excerpt' => '',
715 'excerpt_length' => '',
716 'excerpt_more_text' => '',
717 'comment_num' => '',
718 'date' => '',
719 'thumb' => '',
720 'thumbTop' => '',
721 'thumb_w' => '',
722 'thumb_h' => '',
723 'use_css_cropping' => ''
724 ) );
725
726 $title = $instance['title'];
727 $hide_title = $instance['hide_title'];
728 $separate_categories = $instance['separate_categories'];
729 $num_per_cate = $instance['num_per_cate'];
730 $num = $instance['num'];
731 $exclude_no_children = $instance['exclude_no_children'];
732 $exclude_children = $instance['exclude_children'];
733 $sort_by = $instance['sort_by'];
734 $asc_sort_order = $instance['asc_sort_order'];
735 $title_link = $instance['title_link'];
736 $exclude_categories = $instance['exclude_categories'];
737 $exclude_terms = $instance['exclude_terms'];
738 $include_tax = $instance['include_tax'];
739 $post_types = $instance['post_types'];
740 $exclude_current_post = $instance['exclude_current_post'];
741 $exclude_sticky_posts = $instance['exclude_sticky_posts'];
742 $author = $instance['author'];
743 $date_format = $instance['date_format'];
744 $use_wp_date_format = $instance['use_wp_date_format'];
745 $date_link = $instance['date_link'];
746 $excerpt = $instance['excerpt'];
747 $excerpt_length = $instance['excerpt_length'];
748 $excerpt_more_text = $instance['excerpt_more_text'];
749 $comment_num = $instance['comment_num'];
750 $date = $instance['date'];
751 $thumb = $instance['thumb'];
752 $thumbTop = $instance['thumbTop'];
753 $thumb_w = $instance['thumb_w'];
754 $thumb_h = $instance['thumb_h'];
755 $use_css_cropping = $instance['use_css_cropping'];
756
757 ?>
758 <div class="same-category-widget-cont">
759 <h4 data-panel="title"><?php _e('Title')?></h4>
760 <div>
761 <p>
762 <label for="<?php echo $this->get_field_id("title_link"); ?>">
763 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("title_link"); ?>" name="<?php echo $this->get_field_name("title_link"); ?>"<?php checked( (bool) $instance["title_link"], true ); ?> />
764 <?php _e( 'Make widget title link' ); ?>
765 </label>
766 </p>
767
768 <p>
769 <label for="<?php echo $this->get_field_id("hide_title"); ?>">
770 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("hide_title"); ?>" name="<?php echo $this->get_field_name("hide_title"); ?>"<?php checked( (bool) $instance["hide_title"], true ); ?> />
771 <?php _e( 'Hide title' ); ?>
772 </label>
773 </p>
774
775 <p>
776 <label for="<?php echo $this->get_field_id("title"); ?>">
777 <?php _e( 'Title *' ); ?>:
778 <input style="width:80%;" class="widefat" id="<?php echo $this->get_field_id("title"); ?>" name="<?php echo $this->get_field_name("title"); ?>" type="text" value="<?php echo esc_attr($instance['title']); ?>" />
779 <div style="border-left:5px solid #F1F1F1;padding-left:10px;">* Placeholder: </br>'%cat%' - One category (the first if more assigned)</br>'%cat-all%' - All assigned categories for the shown post</div>
780 </label>
781 </p>
782 </div>
783 <h4 data-panel="filter"><?php _e('Filter')?></h4>
784 <div>
785 <?php
786 // get taxonomies except for the built-in
787 $args = array(
788 'public' => true
789 );
790 $taxs = get_taxonomies( $args, 'objects' );
791
792 // now get all tags
793 $args = array(
794 'hide_empty' => false, // we want to show not yet populated terms as well
795 'fields' => 'id=>name' // return array of names matched to ids
796 );
797 $collect_post_types = "";
798 foreach ($taxs as $key=>$tax) {
799 $taxname = $tax->name;
800 $terms = get_terms($taxname,$args);
801 $post_type = $post_types[$taxname]['post_type'];
802
803 if ($terms) {
804 if ($collect_post_types != $post_type) {
805 echo ($collect_post_types == "")?'':'</div>';
806 echo 'Show <b>'.$post_type.'</b> with:<br>';
807 echo '<div style="border-left:5px solid #F1F1F1;padding-left:10px;">';
808 $collect_post_types = $post_type;
809 }
810 ?>
811 <p>
812 <label>
813 <input name="<?php echo $this->get_field_name('include_tax['.$post_type.']'); ?>" data-taxname-and-post-type="<?php echo $taxname.'-'.$post_type ?>" onchange="javascript:scpwp_namespace.toggleSelectTaxPanel(this)" type="radio" class="checkbox" id="<?php echo $this->get_field_id('include_tax['.$post_type.']'); ?>" value="<?php echo $taxname ?>"<?php checked( (bool) ($instance['include_tax'][$post_type] == $taxname), true ); ?> />
814 <?php printf( __( 'Same "%s" and exclude:' ), esc_html($tax->labels->name)); ?>
815 </label>
816 </p>
817 <?php
818
819 $selected = array();
820 if (isset($instance['exclude_terms'][$taxname]))
821 $selected = $instance['exclude_terms'][$taxname];
822 else if (isset($instance["exclude_categories"]) && $instance["exclude_categories"] && $taxname == 'category') // deprecate >= 1.0.12: 'exclude_categories' get 'exclude_terms'
823 $selected = $instance["exclude_categories"];
824
825 $style_display_attr = ($instance['include_tax'][$post_type] == $taxname)?'block':'none';
826
827 echo '<div data-post-type='.$post_type.' class=\'scpwp-exclude-taxterms-'.$taxname.'-panel\' style="display:'.$style_display_attr.'">';
828 echo '<select multiple="multiple" name="'.$this->get_field_name('exclude_terms').'['.$taxname.'][]" id="'.$this->get_field_id('exclude_terms['.$taxname.']').'">';
829 foreach ($terms as $id => $name) {
830 $sel = '';
831 if (in_array($id,$selected))
832 $sel = ' selected="selected"';
833 echo '<option value="'.$id.'"'.$sel.'>'.esc_html($name).'</option>';
834 }
835 echo '</select>';
836 echo '<p>(CTRL+Click: Multiselection and clear)</p>';
837 echo '</div>';
838 }
839 }
840 ?>
841
842 <p>
843 <label for="<?php echo $this->get_field_id("exclude_no_children"); ?>">
844 <input type="checkbox" class="checkbox"
845 id="<?php echo $this->get_field_id("exclude_no_children"); ?>"
846 name="<?php echo $this->get_field_name("exclude_no_children"); ?>"
847 <?php checked( (bool) $instance["exclude_no_children"], true ); ?> />
848 <?php _e( 'Perform the exclusion without children' ); ?>
849 </label>
850 </p>
851
852 </div>
853
854 <p>
855 <label for="<?php echo $this->get_field_id("sort_by"); ?>">
856 <?php _e('Sort by'); ?>:
857 <select id="<?php echo $this->get_field_id("sort_by"); ?>" name="<?php echo $this->get_field_name("sort_by"); ?>">
858 <option value="date"<?php selected( $instance["sort_by"], "date" ); ?>>Date</option>
859 <option value="title"<?php selected( $instance["sort_by"], "title" ); ?>>Title</option>
860 <option value="comment_count"<?php selected( $instance["sort_by"], "comment_count" ); ?>>Number of comments</option>
861 <option value="rand"<?php selected( $instance["sort_by"], "rand" ); ?>>Random</option>
862 </select>
863 </label>
864 </p>
865
866 <p>
867 <label for="<?php echo $this->get_field_id("asc_sort_order"); ?>">
868 <input type="checkbox" class="checkbox"
869 id="<?php echo $this->get_field_id("asc_sort_order"); ?>"
870 name="<?php echo $this->get_field_name("asc_sort_order"); ?>"
871 <?php checked( (bool) $instance["asc_sort_order"], true ); ?> />
872 <?php _e( 'Reverse sort order (ascending)' ); ?>
873 </label>
874 </p>
875
876 <p>
877 <label for="<?php echo $this->get_field_id("separate_categories"); ?>">
878 <input onchange="javascript:scpwp_namespace.toggleSeparateCategoriesPanel(this)" type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("separate_categories"); ?>" name="<?php echo $this->get_field_name("separate_categories"); ?>"<?php checked( (bool) $instance["separate_categories"], true ); ?> />
879 <?php _e( 'Separate terms (If more than one assigned)' ); ?>
880 </label>
881 </p>
882
883 <p class="scpwp-separate-categories-panel" style="border-left:5px solid #F1F1F1;padding-left:10px;display:<?php echo (isset($separate_categories) && $separate_categories) ? 'block' : 'none'?>">
884 <label for="<?php echo $this->get_field_id("num_per_cate"); ?>">
885 <?php _e('Max. number of posts per separated categories'); ?>:
886 <input style="width: 15%; text-align: center;" id="<?php echo $this->get_field_id("num_per_cate"); ?>" name="<?php echo $this->get_field_name("num_per_cate"); ?>" type="number" min="0" value="<?php echo absint($instance["num_per_cate"]); ?>" size='3' />
887 </label>
888 </p>
889
890 <p>
891 <label for="<?php echo $this->get_field_id("num"); ?>">
892 <?php _e('Number of posts to show (overall)'); ?>:
893 <input style="width:30%;" style="text-align: center;" id="<?php echo $this->get_field_id("num"); ?>" name="<?php echo $this->get_field_name("num"); ?>" type="number" min="0" value="<?php echo absint($instance["num"]); ?>" size='3' />
894 </label>
895 </p>
896
897 <p>
898 <label for="<?php echo $this->get_field_id("exclude_current_post"); ?>">
899 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("exclude_current_post"); ?>" name="<?php echo $this->get_field_name("exclude_current_post"); ?>"<?php checked( (bool) $instance["exclude_current_post"], true ); ?> />
900 <?php _e( 'Exclude current post' ); ?>
901 </label>
902 </p>
903
904 <p>
905 <label for="<?php echo $this->get_field_id("exclude_sticky_posts"); ?>">
906 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("exclude_sticky_posts"); ?>" name="<?php echo $this->get_field_name("exclude_sticky_posts"); ?>"<?php checked( (bool) $instance["exclude_sticky_posts"], true ); ?> />
907 <?php _e( 'Exclude sticky posts' ); ?>
908 </label>
909 </p>
910
911 <p>
912 <label for="<?php echo $this->get_field_id("exclude_children"); ?>">
913 <input type="checkbox" class="checkbox"
914 id="<?php echo $this->get_field_id("exclude_children"); ?>"
915 name="<?php echo $this->get_field_name("exclude_children"); ?>"
916 <?php checked( (bool) $instance["exclude_children"], true ); ?> />
917 <?php _e( 'Exclude children' ); ?>
918 </label>
919 </p>
920
921 </div>
922 <h4 data-panel="thumbnails"><?php _e('Thumbnails')?></h4>
923 <div>
924 <?php
925 if ( function_exists('the_post_thumbnail') && current_theme_supports("post-thumbnails") ) :
926 ?>
927 <p>
928 <label for="<?php echo $this->get_field_id("thumb"); ?>">
929 <input onchange="javascript:scpwp_namespace.toggleShowPostThumbnailPanel(this)" type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("thumb"); ?>" name="<?php echo $this->get_field_name("thumb"); ?>"<?php checked( (bool) $instance["thumb"], true ); ?> />
930 <?php _e( 'Show post thumbnail' ); ?>
931 </label>
932 </p>
933
934 <div class="scpwp-show-post-thumbnail-panel" style="border-left:5px solid #F1F1F1;padding-left:10px;display:<?php echo (isset($thumb) && $thumb) ? 'block' : 'none'?>">
935 <p>
936 <label for="<?php echo $this->get_field_id("thumbTop"); ?>">
937 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("thumbTop"); ?>" name="<?php echo $this->get_field_name("thumbTop"); ?>"<?php checked( (bool) $instance["thumbTop"], true ); ?> />
938 <?php _e( 'Thumbnail to top' ); ?>
939 </label>
940 </p>
941
942 <p>
943 <label>
944 <?php _e('Thumbnail dimensions (in pixels)'); ?>:<br />
945 <label for="<?php echo $this->get_field_id("thumb_w"); ?>">
946 Width: <input class="widefat" style="width:30%;" type="number" min="1" id="<?php echo $this->get_field_id("thumb_w"); ?>" name="<?php echo $this->get_field_name("thumb_w"); ?>" value="<?php echo $instance["thumb_w"]; ?>" />
947 </label>
948
949 <label for="<?php echo $this->get_field_id("thumb_h"); ?>">
950 Height: <input class="widefat" style="width:30%;" type="number" min="1" id="<?php echo $this->get_field_id("thumb_h"); ?>" name="<?php echo $this->get_field_name("thumb_h"); ?>" value="<?php echo $instance["thumb_h"]; ?>" />
951 </label>
952 </label>
953 </p>
954
955 <p>
956 <label for="<?php echo $this->get_field_id("use_css_cropping"); ?>">
957 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("use_css_cropping"); ?>" name="<?php echo $this->get_field_name("use_css_cropping"); ?>"<?php checked( (bool) $instance["use_css_cropping"], true ); ?> />
958 <?php _e( 'CSS crop to requested size' ); ?>
959 </label>
960 </p>
961 </div>
962 <?php
963 endif;
964 ?>
965 </div>
966 <h4 data-panel="details"><?php _e('Post details')?></h4>
967 <div>
968 <p>
969 <label for="<?php echo $this->get_field_id("excerpt"); ?>">
970 <input onchange="javascript:scpwp_namespace.toggleShowPostExcerptPanel(this)" type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("excerpt"); ?>" name="<?php echo $this->get_field_name("excerpt"); ?>"<?php checked( (bool) $instance["excerpt"], true ); ?> />
971 <?php _e( 'Show post excerpt' ); ?>
972 </label>
973 </p>
974
975 <div class="scpwp-show-post-excerpt-panel" style="border-left:5px solid #F1F1F1;padding-left:10px;display:<?php echo (isset($excerpt) && $excerpt) ? 'block' : 'none'?>">
976 <p>
977 <label for="<?php echo $this->get_field_id("excerpt_length"); ?>">
978 <?php _e( 'Excerpt length (in words):' ); ?>
979 </label>
980 <input style="width:30%; text-align: center;" placeholder="<?php _e('55')?>" type="number" min="0" id="<?php echo $this->get_field_id("excerpt_length"); ?>" name="<?php echo $this->get_field_name("excerpt_length"); ?>" value="<?php echo $instance["excerpt_length"]; ?>" size="3" />
981 </p>
982
983 <p>
984 <label for="<?php echo $this->get_field_id("excerpt_more_text"); ?>">
985 <?php _e( 'Excerpt \'more\' text:' ); ?>
986 </label>
987 <input class="widefat" style="width:50%;" placeholder="<?php _e('... more')?>" id="<?php echo $this->get_field_id("excerpt_more_text"); ?>" name="<?php echo $this->get_field_name("excerpt_more_text"); ?>" type="text" value="<?php echo esc_attr($instance["excerpt_more_text"]); ?>" />
988 </p>
989 </div>
990
991 <p>
992 <label for="<?php echo $this->get_field_id("comment_num"); ?>">
993 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("comment_num"); ?>" name="<?php echo $this->get_field_name("comment_num"); ?>"<?php checked( (bool) $instance["comment_num"], true ); ?> />
994 <?php _e( 'Show number of comments' ); ?>
995 </label>
996 </p>
997
998 <p>
999 <label for="<?php echo $this->get_field_id("date"); ?>" onchange="javascript:scpwp_namespace.toggleDatePanel(this)">
1000 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("date"); ?>" name="<?php echo $this->get_field_name("date"); ?>"<?php checked( (bool) $instance["date"], true ); ?> />
1001 <?php _e( 'Show post date' ); ?>
1002 </label>
1003 </p>
1004 <div class="cpwp_ident scpwp-data-panel-date" style="display:<?php echo ((bool) $date) ? 'block' : 'none'?>">
1005 <p>
1006 <label for="<?php echo $this->get_field_id("use_wp_date_format"); ?>" onchange="javascript:scpwp_namespace.toggleUseWPDateFormatPanel(this)">
1007 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("use_wp_date_format"); ?>" name="<?php echo $this->get_field_name("use_wp_date_format"); ?>"<?php checked( (bool) $instance["use_wp_date_format"], true ); ?> />
1008 <?php _e( 'Use the WordPress Settings > General for the date format','category-posts' ); ?>
1009 </label>
1010 </p>
1011 <div class="scpwp-data-panel-date-format" style="display:<?php echo ((bool) $use_wp_date_format) ? 'none' : 'block'?>">
1012 <p>
1013 <label for="<?php echo $this->get_field_id("date_format"); ?>">
1014 <?php _e( 'Date format:','category-posts' ); ?>
1015 </label>
1016 <input class="text" placeholder="j M Y" id="<?php echo $this->get_field_id("date_format"); ?>" name="<?php echo $this->get_field_name("date_format"); ?>" type="text" value="<?php echo esc_attr($instance["date_format"]); ?>" size="8" />
1017 </p>
1018 </div>
1019 <p>
1020 <label for="<?php echo $this->get_field_id("date_link"); ?>">
1021 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("date_link"); ?>" name="<?php echo $this->get_field_name("date_link"); ?>"<?php checked( (bool) $instance["date_link"], true ); ?> />
1022 <?php _e( 'Make widget date link','category-posts' ); ?>
1023 </label>
1024 </p>
1025 </div>
1026
1027 <p>
1028 <label for="<?php echo $this->get_field_id("author"); ?>">
1029 <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id("author"); ?>" name="<?php echo $this->get_field_name("author"); ?>"<?php checked( (bool) $instance["author"], true ); ?> />
1030 <?php _e( 'Show post author' ); ?>
1031 </label>
1032 </p>
1033 </div>
1034 <hr>
1035
1036 <p style="text-align:right;">
1037 Follow us on <a target="_blank" href="https://www.facebook.com/TipTopPress">Facebook</a> and
1038 <a target="_blank" href="https://twitter.com/TipTopPress">Twitter</a></br></br>
1039 </p>
1040 </div>
1041 <?php
1042
1043 }
1044
1045 }
1046
1047 function register_widget() {
1048 return \register_widget(__NAMESPACE__.'\Widget');
1049 }
1050
1051 add_action( 'widgets_init', __NAMESPACE__.'\register_widget' );
1052