PluginProbe
Same Category Posts / 1.2.0
Same Category Posts v1.2.0
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.2.0, at same-category-posts.php

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