PluginProbe
Same Category Posts / 1.1.9
Same Category Posts v1.1.9
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
1,106 lines 43.0 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.9
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.9");
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 ( $thumbSize['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 ( ! isset( $instance['post_types'][$tax->name] ) ||
381 ( isset( $instance['post_types'][$tax->name] ) && ! array_key_exists( $tax->name, $instance['post_types'] ) ) ) {
382 if ($tax->hierarchical) {
383 $instance['post_types'][$tax->name] = array( 'post_type'=>$post_type, 'hierarchical'=>true );
384 } else {
385 $instance['post_types'][$tax->name] = array( 'post_type'=>$post_type, 'hierarchical'=>false );
386 }
387 }
388 }
389 // put and set only 'default' taxes
390 if ($set_default) {
391 foreach ( $object_taxes as $tax ) {
392 if ($tax->hierarchical) {
393 $instance['include_tax'][$post_type] = $tax->name; // set as 'default'
394 }
395 }
396 }
397 }
398 }
399
400 // Displays a list of posts from same category on single post pages.
401 function widget($args, $instance) {
402 // Only show widget if on a post page.
403 if ( !is_single() ) return;
404
405 global $wp_query;
406 global $post;
407 $post_old = $post; // Save the post object.
408 $current_post_id = get_the_ID();
409
410 extract( $args );
411 $this->instance = $instance;
412
413 $this->initPostTypesAndTaxes($instance);
414
415 $taxonomies = null;
416 $all_taxonomies = null;
417 $taxes = get_object_taxonomies( $post );
418
419 // Get all taxonomies
420 $all_terms = array();
421 foreach ($taxes as $tax) {
422 $terms = get_terms($tax,array('public'=>true), 'objects');
423 foreach ($terms as $id => $name) {
424 $all_terms[$tax][] = $name->term_id;
425 }
426 }
427
428 // Get post taxonomies
429 $categories = null;
430 foreach ($taxes as $tax) {
431 $post_type = $instance['post_types'][$tax]['post_type'];
432 if ($tax == $instance['include_tax'][$post_type]) {
433 $terms = get_the_terms($post->ID, $tax);
434 if ($terms) {
435 foreach ($terms as $term) {
436 $taxonomies[$tax][] = $term->term_id;
437 }
438 }
439 $categories = get_the_terms($post->ID,$tax);
440 }
441 }
442
443 // Excerpt length filter
444 if ( isset($instance["excerpt_length"]) && $instance["excerpt_length"] > 0 ) {
445 $new_excerpt_length = function ( $length ) use ( $instance ) { return $instance["excerpt_length"]; };
446 add_filter('excerpt_length', $new_excerpt_length);
447 }
448
449 $valid_sort_orders = array('date', 'title', 'comment_count', 'rand');
450 if ( isset($instance['sort_by']) && in_array($instance['sort_by'], $valid_sort_orders) ) {
451 $sort_by = $instance['sort_by'];
452 $sort_order = (bool) isset( $instance['asc_sort_order'] ) ? 'ASC' : 'DESC';
453 } else {
454 // by default, display latest first
455 $sort_by = 'date';
456 $sort_order = 'DESC';
457 }
458
459 // Excerpt more_text
460 if( isset($instance["excerpt_more_text"]) && ltrim($instance["excerpt_more_text"]) != '' )
461 {
462 add_filter('excerpt_more', array($this,'excerpt_more_filter'));
463 }
464
465 // deprecate >= 1.0.12: 'exclude_categories' get 'exclude_terms'
466 // Exclude categories
467 if (!isset($instance['exclude_terms']['category']) && isset($instance['exclude_categories']) && $instance['exclude_categories'])
468 $instance['exclude_terms'] = array( 'category' => $instance['exclude_categories']);
469
470 // Query args
471 $args = array(
472 'orderby' => $sort_by,
473 'order' => $sort_order
474 );
475
476 $args['post_type'] = array( get_post_type( $post ) );
477
478 if ($taxonomies) {
479 $term_query_in = array('relation' => 'OR');
480 $term_query_exclude = null;
481 $term_query_not_in = null;
482 foreach ( $taxonomies as $tax=>$terms) {
483 $exclude_terms = array();
484 if ( isset($instance['exclude_terms']) && $instance['exclude_terms'] && array_key_exists($tax, $instance['exclude_terms']) ) {
485 $terms = array_diff($terms, $instance['exclude_terms'][$tax]);
486 $exclude_terms = $instance['exclude_terms'][$tax];
487 }
488
489 // all terms associated with the current post
490 if ($terms) {
491 $term_query_in[] = array(
492 'taxonomy' => $tax,
493 'field' => 'term_id',
494 'terms' => $terms,
495 'include_children' => isset($instance['exclude_children']) && $instance['exclude_children'] ? false : true,
496 'operator' => 'IN',
497 );
498 }
499
500 // excluded terms
501 if ( $exclude_terms ) {
502 $term_query_exclude[] = array(
503 'taxonomy' => $tax,
504 'field' => 'term_id',
505 'terms' => $exclude_terms,
506 'include_children' => isset( $instance['exclude_no_children'] ) && $instance['exclude_no_children'] ? false : true,
507 'operator' => 'NOT IN',
508 );
509 }
510
511 // get children if not exclude children
512 $childrens = array();
513 $exclude_children = array();
514 if ( ! ( isset($instance['exclude_children'] ) && $instance['exclude_children'] ) ) {
515 foreach ($terms as $key => $termId) {
516 $childrens[] = get_terms( $tax, array( 'parent' => $term->term_id ) );
517 }
518 if ( $childrens ) {
519 foreach ($childrens as $id => $name) {
520 if ( $name ) {
521 $exclude_children[] = $name[$id]->term_id;
522 }
523 }
524 }
525 }
526
527 // all not's (always include_children is false)
528 $not_terms = array_diff( $all_terms[$tax], $terms, $exclude_children, $exclude_terms );
529 if ( $not_terms ) {
530 $term_query_not_in[] = array(
531 'taxonomy' => $tax,
532 'field' => 'term_id',
533 'terms' => $not_terms,
534 'include_children' => false,
535 'operator' => 'NOT IN',
536 );
537 }
538 }
539 }
540
541 $term_query[] = array('relation' => 'AND');
542 $term_query[] = $term_query_in;
543 $term_query[] = $term_query_exclude;
544 $term_query[] = $term_query_not_in;
545
546 if (is_array($term_query))
547 $args['tax_query'] = $term_query;
548
549 $args['post__not_in'] = array();
550 if (isset( $instance['exclude_current_post'] ) && $instance['exclude_current_post']) {
551 $args['post__not_in'] = array( $current_post_id );
552 }
553
554 if(isset( $instance['exclude_sticky_posts'] ) && $instance['exclude_sticky_posts']) {
555 foreach (get_option( 'sticky_posts' ) as $value) {
556 $args['post__not_in'][] = $value;
557 }
558 }
559
560 $args['posts_per_page'] = (isset($instance['num']) && $instance['num']) ? $instance['num'] : -1;
561
562 $my_query = new \WP_Query($args);
563
564 if( $my_query->have_posts() )
565 {
566 echo $before_widget;
567
568 // Widget title
569 if( !isset ( $instance["hide_title"] ) ) {
570 if( isset( $instance["separate_categories"] ) && $instance["separate_categories"] ) {
571 // Separate categories: title to array
572 foreach($categories as $cat) {
573 $widgetHTML[$cat->name]['ID'] = $cat->term_id;
574 if( isset ( $instance["title_link"] ) ) {
575 $title = '<a href="' . get_category_link( $cat ) . '">'. $cat->name . '</a>';
576 if(isset($instance['title']) && strpos($instance['title'], '%cat-all%') !== false)
577 $title = str_replace( "%cat-all%", $title, $instance['title']);
578 else if(isset($instance['title']) && strpos($instance['title'], '%cat%') !== false)
579 $title = str_replace( "%cat%", $title, $instance['title']);
580 $widgetHTML[$cat->name]['title'] = $title;
581 } else {
582 $title = $cat->name;
583 if(isset($instance['title']) && strpos($instance['title'], '%cat-all%') !== false)
584 $title = str_replace( "%cat-all%", $title, $instance['title']);
585 else if(isset($instance['title']) && strpos($instance['title'], '%cat%') !== false)
586 $title = str_replace( "%cat%", $title, $instance['title']);
587 $widgetHTML[$cat->name]['title'] = $title;
588 }
589 }
590 } else {
591 // ! Separate categories: echo
592 echo $before_title;
593 if( isset ( $instance["title_link"] ) ) {
594 $linkList = "";
595 foreach($categories as $cat) {
596 if(isset($instance['exclude_terms']) && $instance['exclude_terms'] && in_array($cat->term_id,$instance['exclude_terms']))
597 continue;
598 $linkList .= '<a href="' . get_category_link( $cat ) . '">'. $cat->name . '</a>, ';
599 }
600 $linkList = trim($linkList, ", ");
601 if( isset($instance['title']) && $instance['title'] ) { // use placeholders if title is not empty
602 if(strpos($instance['title'], '%cat-all%') !== false ||
603 strpos($instance['title'], '%cat%') !== false) { // all-category placeholder is used
604 if(strpos($instance['title'], '%cat-all%') !== false)
605 $linkList = str_replace( "%cat-all%", $linkList, $instance['title']);
606 else if(strpos($instance['title'], '%cat%') !== false)
607 $linkList = str_replace( "%cat%", '<a href="' . get_category_link( $categories[0] ) . '">'. $categories[0]->name . '</a>', $instance['title']);
608 } else // no category placeholder is used
609 $linkList = '<a href="' . get_category_link( $categories[0] ) . '">'. $instance['title'] . '</a>';
610 }
611 echo htmlspecialchars_decode(apply_filters('widget_title',$linkList));
612 } else {
613 $categoryNames = "";
614 if ($categories) {
615 foreach ($categories as $key => $val) {
616 if(isset($instance['exclude_terms']) && $instance['exclude_terms'] && in_array($val->term_id,$instance['exclude_terms'][$val->taxonomy]))
617 continue;
618 $categoryNames .= $val->name . ", ";
619 }
620 $categoryNames = trim($categoryNames, ", ");
621 }
622
623 if( isset($instance['title']) && $instance['title'] ) { // use placeholders if title is not empty
624 if(strpos($instance['title'], '%cat-all%') !== false) // all-category placeholder is used
625 $categoryNames = str_replace( "%cat-all%", $categoryNames, $instance['title']);
626 else if(strpos($instance['title'], '%cat%') !== false) // one-category placeholder is used
627 $categoryNames = str_replace( "%cat%", $categories[0]->name, $instance['title']);
628 else
629 $categoryNames = $instance['title'];
630 }
631 echo htmlspecialchars_decode(apply_filters('widget_title',$categoryNames));
632 }
633 echo $after_title;
634 }
635 }
636 // /Widget title
637
638 // Post list
639 echo "<ul>\n";
640 while ($my_query->have_posts())
641 {
642 $my_query->the_post();
643
644 if( isset( $instance["separate_categories"] ) && $instance["separate_categories"] ) {
645 // Separate categories: get itemHTML to array
646 $object_taxes = get_object_taxonomies( $post, 'objects' );
647 $post_categories = null;
648 foreach ( $object_taxes as $tax ) {
649 $post_type = $instance['post_types'][$tax->name]['post_type'];
650 if ($tax->name == $instance['include_tax'][$post_type]) {
651 $post_categories = get_the_terms($post->ID,$tax->name);
652 break;
653 }
654 }
655 foreach ($post_categories as $val) {
656 $widgetHTML[$val->name][$post->ID]['itemHTML'] = $this->itemHTML($instance,$current_post_id);
657 $widgetHTML[$val->name][$post->ID]['ID'] = $post->ID;
658 }
659 } else {
660 // ! Separate categories: get itemHTML and echo
661 echo $this->itemHTML($instance,$current_post_id);
662 }
663 } // end while
664
665 if (isset( $instance["separate_categories"] ) && $instance["separate_categories"]) {
666 // Separate categories: echo
667 $isOnPage = array();
668 foreach($widgetHTML as $val) {
669 // widget title
670 $haveItemHTML = false;
671 $ret = $before_title . htmlspecialchars_decode(apply_filters('widget_title',isset($val['title'])?$val['title']:"")) . $after_title;
672 $count = 1;
673 $num_per_cat = (isset($instance['num_per_cate'])&&$instance['num_per_cate']!=0?($instance['num_per_cate']):99999);
674 foreach($val as $key) {
675 if(is_array($key) && array_key_exists('itemHTML', $key)) {
676 if( !in_array($key['ID'], $isOnPage) ) {
677 if($count <= $num_per_cat) {
678 $ret .= $key['itemHTML'];
679 $haveItemHTML = true;
680 $isOnPage[] = $key['ID'];
681 } else
682 break;
683 $count++;
684 }
685 }
686 }
687 if ($haveItemHTML)
688 echo $ret;
689 }
690 }
691
692 echo "</ul>\n";
693 // end Post list
694
695 echo $after_widget;
696 }
697
698 if(isset($new_excerpt_length))
699 remove_filter('excerpt_length', $new_excerpt_length);
700 remove_filter('excerpt_more', array($this,'excerpt_more_filter'));
701
702 $post = $post_old; // Restore the post object.
703 }
704
705 /**
706 * Update the options
707 *
708 * @param array $new_instance
709 * @param array $old_instance
710 * @return array
711 */
712 function update($new_instance, $old_instance) {
713
714 return $new_instance;
715 }
716
717 /**
718 * The widget configuration form back end.
719 *
720 * @param array $instance
721 * @return void
722 */
723 function form($instance) {
724
725 // ToDo seperate_cat get seperate_tax (if update, settings)
726
727 $this->initPostTypesAndTaxes($instance);
728
729 $instance = wp_parse_args( ( array ) $instance, array(
730 'title' => '',
731 'hide_title' => '',
732 'separate_categories' => '',
733 'num_per_cate' => '',
734 'num' => '',
735 'exclude_no_children' => '',
736 'exclude_children' => '',
737 'sort_by' => '',
738 'asc_sort_order' => '',
739 'title_link' => '',
740 'exclude_categories' => '',
741 'exclude_terms' => array(),
742 'include_tax' => array(),
743 'post_types' => array(),
744 'exclude_current_post' => '',
745 'exclude_sticky_posts' => '',
746 'author' => '',
747 'date_format' => '',
748 'use_wp_date_format' => '',
749 'date_link' => '',
750 'excerpt' => '',
751 'excerpt_length' => '',
752 'excerpt_more_text' => '',
753 'comment_num' => '',
754 'date' => '',
755 'thumb' => '',
756 'thumbTop' => '',
757 'thumb_w' => '',
758 'thumb_h' => '',
759 'use_css_cropping' => ''
760 ) );
761
762 $title = $instance['title'];
763 $hide_title = $instance['hide_title'];
764 $separate_categories = $instance['separate_categories'];
765 $num_per_cate = $instance['num_per_cate'];
766 $num = $instance['num'];
767 $exclude_no_children = $instance['exclude_no_children'];
768 $exclude_children = $instance['exclude_children'];
769 $sort_by = $instance['sort_by'];
770 $asc_sort_order = $instance['asc_sort_order'];
771 $title_link = $instance['title_link'];
772 $exclude_categories = $instance['exclude_categories'];
773 $exclude_terms = $instance['exclude_terms'];
774 $include_tax = $instance['include_tax'];
775 $post_types = $instance['post_types'];
776 $exclude_current_post = $instance['exclude_current_post'];
777 $exclude_sticky_posts = $instance['exclude_sticky_posts'];
778 $author = $instance['author'];
779 $date_format = $instance['date_format'];
780 $use_wp_date_format = $instance['use_wp_date_format'];
781 $date_link = $instance['date_link'];
782 $excerpt = $instance['excerpt'];
783 $excerpt_length = $instance['excerpt_length'];
784 $excerpt_more_text = $instance['excerpt_more_text'];
785 $comment_num = $instance['comment_num'];
786 $date = $instance['date'];
787 $thumb = $instance['thumb'];
788 $thumbTop = $instance['thumbTop'];
789 $thumb_w = $instance['thumb_w'];
790 $thumb_h = $instance['thumb_h'];
791 $use_css_cropping = $instance['use_css_cropping'];
792
793 ?>
794 <div class="same-category-widget-cont">
795 <h4 data-panel="title"><?php _e('Title')?></h4>
796 <div>
797 <p>
798 <label for="<?php echo $this->get_field_id("title_link"); ?>">
799 <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 ); ?> />
800 <?php _e( 'Make widget title link' ); ?>
801 </label>
802 </p>
803
804 <p>
805 <label for="<?php echo $this->get_field_id("hide_title"); ?>">
806 <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 ); ?> />
807 <?php _e( 'Hide title' ); ?>
808 </label>
809 </p>
810
811 <p>
812 <label for="<?php echo $this->get_field_id("title"); ?>">
813 <?php _e( 'Title *' ); ?>:
814 <input
815 style="width:80%;"
816 class="widefat"
817 id="<?php echo $this->get_field_id("title"); ?>"
818 name="<?php echo $this->get_field_name("title"); ?>"
819 type="text"
820 value="<?php echo esc_attr($instance['title']); ?>" />
821 <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>
822 </label>
823 </p>
824 </div>
825 <h4 data-panel="filter"><?php _e('Filter')?></h4>
826 <div>
827 <?php
828 // get taxonomies except for the built-in
829 $args = array(
830 'public' => true
831 );
832 $taxs = get_taxonomies( $args, 'objects' );
833
834 // now get all tags
835 $args = array(
836 'hide_empty' => false, // we want to show not yet populated terms as well
837 'fields' => 'id=>name' // return array of names matched to ids
838 );
839 $collect_post_types = "";
840 $collect_post_types_end = false;
841 foreach ($taxs as $key=>$tax) {
842 $taxname = $tax->name;
843 $terms = get_terms($taxname,$args);
844 $post_type = $post_types[$taxname]['post_type'];
845
846 if ($terms) {
847
848 if ($collect_post_types != $post_type) {
849 echo ( $collect_post_types_end == false ) ? '' : '</div>';
850 echo 'Show <b>' . get_post_type_object( $post_type )->label . '</b> with:<br>';
851 echo '<div style="border-left:5px solid #F1F1F1;padding-left:10px;">';
852 $collect_post_types = $post_type;
853 $collect_post_types_end = true;
854 }
855 ?>
856 <p>
857 <label>
858 <input
859 name="<?php echo $this->get_field_name('include_tax['.$post_type.']'); ?>"
860 data-taxname-and-post-type="<?php echo $taxname.'-'.$post_type ?>"
861 onchange="javascript:scpwp_namespace.toggleSelectTaxPanel(this)"
862 type="radio"
863 class="checkbox"
864 id="<?php echo $this->get_field_id( $taxname ); ?>"
865 value="<?php echo $taxname ?>"
866 <?php checked( (bool) ($instance['include_tax'][$post_type] == $taxname), true ); ?> />
867 <?php printf( __( 'Same "%s" and exclude:' ), esc_html($tax->labels->name)); ?>
868 </label>
869 </p>
870 <?php
871
872 $selected = array();
873 if (isset($instance['exclude_terms'][$taxname]))
874 $selected = $instance['exclude_terms'][$taxname];
875 else if (isset($instance["exclude_categories"]) && $instance["exclude_categories"] && $taxname == 'category') // deprecate >= 1.0.12: 'exclude_categories' get 'exclude_terms'
876 $selected = $instance["exclude_categories"];
877
878 $style_display_attr = ($instance['include_tax'][$post_type] == $taxname)?'block':'none';
879
880 echo '<div data-post-type='.$post_type.' class=\'scpwp-exclude-taxterms-'.$taxname.'-panel\' style="display:'.$style_display_attr.'">';
881 echo '<select multiple="multiple" name="'.$this->get_field_name('exclude_terms').'['.$taxname.'][]" id="'.$this->get_field_id('exclude_terms['.$taxname.']').'">';
882 foreach ($terms as $id => $name) {
883 $sel = '';
884 if (in_array($id,$selected))
885 $sel = ' selected="selected"';
886 echo '<option value="'.$id.'"'.$sel.'>'.esc_html($name).'</option>';
887 }
888 echo '</select>';
889 echo '<p>(CTRL / ⌘ + Mouseclick: Multiselection and clear)</p>';
890 echo '</div>';
891 }
892 }
893
894 echo '</div>'; // $collect_post_types_end
895
896 ?>
897
898 <p>
899 <label for="<?php echo $this->get_field_id("exclude_no_children"); ?>">
900 <input type="checkbox" class="checkbox"
901 id="<?php echo $this->get_field_id("exclude_no_children"); ?>"
902 name="<?php echo $this->get_field_name("exclude_no_children"); ?>"
903 <?php checked( (bool) $instance["exclude_no_children"], true ); ?> />
904 <?php _e( 'Perform the exclusion without children' ); ?>
905 </label>
906 </p>
907
908 <p>
909 <label for="<?php echo $this->get_field_id("sort_by"); ?>">
910 <?php _e('Sort by'); ?>:
911 <select id="<?php echo $this->get_field_id("sort_by"); ?>" name="<?php echo $this->get_field_name("sort_by"); ?>">
912 <option value="date"<?php selected( $instance["sort_by"], "date" ); ?>>Date</option>
913 <option value="title"<?php selected( $instance["sort_by"], "title" ); ?>>Title</option>
914 <option value="comment_count"<?php selected( $instance["sort_by"], "comment_count" ); ?>>Number of comments</option>
915 <option value="rand"<?php selected( $instance["sort_by"], "rand" ); ?>>Random</option>
916 </select>
917 </label>
918 </p>
919
920 <p>
921 <label for="<?php echo $this->get_field_id("asc_sort_order"); ?>">
922 <input type="checkbox" class="checkbox"
923 id="<?php echo $this->get_field_id("asc_sort_order"); ?>"
924 name="<?php echo $this->get_field_name("asc_sort_order"); ?>"
925 <?php checked( (bool) $instance["asc_sort_order"], true ); ?> />
926 <?php _e( 'Reverse sort order (ascending)' ); ?>
927 </label>
928 </p>
929
930 <p>
931 <label for="<?php echo $this->get_field_id("separate_categories"); ?>">
932 <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 ); ?> />
933 <?php _e( 'Separate terms (If more than one assigned)' ); ?>
934 </label>
935 </p>
936
937 <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'?>">
938 <label for="<?php echo $this->get_field_id("num_per_cate"); ?>">
939 <?php _e('Max. number of posts per separated categories'); ?>:
940 <input style="width: 30%; 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' />
941 </label>
942 </p>
943
944 <p>
945 <label for="<?php echo $this->get_field_id("num"); ?>">
946 <?php _e('Number of posts to show (overall)'); ?>:
947 <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' />
948 </label>
949 </p>
950
951 <p>
952 <label for="<?php echo $this->get_field_id("exclude_current_post"); ?>">
953 <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 ); ?> />
954 <?php _e( 'Exclude current post' ); ?>
955 </label>
956 </p>
957
958 <p>
959 <label for="<?php echo $this->get_field_id("exclude_sticky_posts"); ?>">
960 <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 ); ?> />
961 <?php _e( 'Exclude sticky posts' ); ?>
962 </label>
963 </p>
964
965 <p>
966 <label for="<?php echo $this->get_field_id("exclude_children"); ?>">
967 <input type="checkbox" class="checkbox"
968 id="<?php echo $this->get_field_id("exclude_children"); ?>"
969 name="<?php echo $this->get_field_name("exclude_children"); ?>"
970 <?php checked( (bool) $instance["exclude_children"], true ); ?> />
971 <?php _e( 'Exclude children' ); ?>
972 </label>
973 </p>
974
975 </div>
976 <h4 data-panel="thumbnails"><?php _e('Thumbnails')?></h4>
977 <div>
978 <?php
979 if ( function_exists('the_post_thumbnail') && current_theme_supports("post-thumbnails") ) :
980 ?>
981 <p>
982 <label for="<?php echo $this->get_field_id("thumb"); ?>">
983 <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 ); ?> />
984 <?php _e( 'Show post thumbnail' ); ?>
985 </label>
986 </p>
987
988 <div class="scpwp-show-post-thumbnail-panel" style="border-left:5px solid #F1F1F1;padding-left:10px;display:<?php echo (isset($thumb) && $thumb) ? 'block' : 'none'?>">
989 <p>
990 <label for="<?php echo $this->get_field_id("thumbTop"); ?>">
991 <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 ); ?> />
992 <?php _e( 'Thumbnail to top' ); ?>
993 </label>
994 </p>
995
996 <p>
997 <label>
998 <?php _e('Thumbnail dimensions (in pixels)'); ?>:<br />
999 <label for="<?php echo $this->get_field_id("thumb_w"); ?>">
1000 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"]; ?>" />
1001 </label>
1002
1003 <label for="<?php echo $this->get_field_id("thumb_h"); ?>">
1004 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"]; ?>" />
1005 </label>
1006 </label>
1007 </p>
1008
1009 <p>
1010 <label for="<?php echo $this->get_field_id("use_css_cropping"); ?>">
1011 <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 ); ?> />
1012 <?php _e( 'CSS crop to requested size' ); ?>
1013 </label>
1014 </p>
1015 </div>
1016 <?php
1017 endif;
1018 ?>
1019 </div>
1020 <h4 data-panel="details"><?php _e('Post details')?></h4>
1021 <div>
1022 <p>
1023 <label for="<?php echo $this->get_field_id("excerpt"); ?>">
1024 <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 ); ?> />
1025 <?php _e( 'Show post excerpt' ); ?>
1026 </label>
1027 </p>
1028
1029 <div class="scpwp-show-post-excerpt-panel" style="border-left:5px solid #F1F1F1;padding-left:10px;display:<?php echo (isset($excerpt) && $excerpt) ? 'block' : 'none'?>">
1030 <p>
1031 <label for="<?php echo $this->get_field_id("excerpt_length"); ?>">
1032 <?php _e( 'Excerpt length (in words):' ); ?>
1033 </label>
1034 <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" />
1035 </p>
1036
1037 <p>
1038 <label for="<?php echo $this->get_field_id("excerpt_more_text"); ?>">
1039 <?php _e( 'Excerpt \'more\' text:' ); ?>
1040 </label>
1041 <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"]); ?>" />
1042 </p>
1043 </div>
1044
1045 <p>
1046 <label for="<?php echo $this->get_field_id("comment_num"); ?>">
1047 <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 ); ?> />
1048 <?php _e( 'Show number of comments' ); ?>
1049 </label>
1050 </p>
1051
1052 <p>
1053 <label for="<?php echo $this->get_field_id("date"); ?>" onchange="javascript:scpwp_namespace.toggleDatePanel(this)">
1054 <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 ); ?> />
1055 <?php _e( 'Show post date' ); ?>
1056 </label>
1057 </p>
1058 <div class="cpwp_ident scpwp-data-panel-date" style="display:<?php echo ((bool) $date) ? 'block' : 'none'?>">
1059 <p>
1060 <label for="<?php echo $this->get_field_id("use_wp_date_format"); ?>" onchange="javascript:scpwp_namespace.toggleUseWPDateFormatPanel(this)">
1061 <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 ); ?> />
1062 <?php _e( 'Use the WordPress Settings > General for the date format','category-posts' ); ?>
1063 </label>
1064 </p>
1065 <div class="scpwp-data-panel-date-format" style="display:<?php echo ((bool) $use_wp_date_format) ? 'none' : 'block'?>">
1066 <p>
1067 <label for="<?php echo $this->get_field_id("date_format"); ?>">
1068 <?php _e( 'Date format:','category-posts' ); ?>
1069 </label>
1070 <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" />
1071 </p>
1072 </div>
1073 <p>
1074 <label for="<?php echo $this->get_field_id("date_link"); ?>">
1075 <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 ); ?> />
1076 <?php _e( 'Make widget date link','category-posts' ); ?>
1077 </label>
1078 </p>
1079 </div>
1080
1081 <p>
1082 <label for="<?php echo $this->get_field_id("author"); ?>">
1083 <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 ); ?> />
1084 <?php _e( 'Show post author' ); ?>
1085 </label>
1086 </p>
1087 </div>
1088 <hr>
1089
1090 <p style="text-align:right;">
1091 Follow us on <a target="_blank" href="https://www.facebook.com/TipTopPress">Facebook</a> and
1092 <a target="_blank" href="https://twitter.com/TipTopPress">Twitter</a></br></br>
1093 </p>
1094 </div>
1095 <?php
1096
1097 }
1098
1099 }
1100
1101 function register_widget() {
1102 return \register_widget(__NAMESPACE__.'\Widget');
1103 }
1104
1105 add_action( 'widgets_init', __NAMESPACE__.'\register_widget' );
1106