PluginProbe
Category Posts Block / trunk
Category Posts Block vtrunk
5.0.0 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 2.0 2.1 2.2 2.3 3.1 3.2 3.3 4.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 All 62 releases
category-posts / class-virtual-widget.php

class-virtual-widget.php in Category Posts Block trunk, at class-virtual-widget.php

430 lines 18.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Implementation of virtual widget.
4 *
5 * @package categoryposts.
6 *
7 * @since 4.7
8 */
9
10 namespace categoryPosts;
11
12 // Don't call the file directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Class that represent a virtual widget. Each widget being created will have relevant
19 * CSS output in the header, but still requires a call for getHTML method or renderHTML
20 * to get or output the HTML
21 *
22 * @since 4.7
23 */
24 class Virtual_Widget {
25
26 /**
27 * A container for all the "active" objects
28 *
29 * @var Array
30 *
31 * @since 4.7
32 */
33 private static $collection = array();
34
35 /**
36 * The identifier use as the id of the root html element when the HTML is generated.
37 *
38 * @var string
39 *
40 * @since 4.7
41 */
42 private $id;
43
44 /**
45 * The class name to be use us the class attribute on the root html element.
46 *
47 * @var string
48 *
49 * @since 4.7
50 */
51 private $class;
52
53 /**
54 * Construct the virtual widget. This should happen before wp_head action with priority
55 * 10 is executed if any CSS output should be generated.
56 *
57 * @param string $id The identifier use as the id of the root html element when the HTML
58 * is generated.
59 *
60 * @param string $class The class name to be use us the class attribute on the root html element.
61 *
62 * @param array $args The setting to be applied to the widget.
63 *
64 * @since 4.7
65 */
66 public function __construct( $id, $class, $args ) {
67 $this->id = $id;
68 $this->class = $class;
69 self::$collection[ $id ] = upgrade_settings( $args );
70 }
71
72 /**
73 * Do what ever cleanup needed when the object is destroyed.
74 *
75 * @since 4.7
76 */
77 public function __destruct() {
78 unset( self::$collection[ $this->id ] );
79 }
80
81 /**
82 * Return the HTML of the widget as is generated based on the settings passed at construction time
83 *
84 * @return string
85 *
86 * @since 4.7
87 */
88 public function getHTML() {
89
90 $widget = new Widget();
91 $widget->number = $this->id; // needed to make a unique id for the widget html element.
92 ob_start();
93 $args = self::$collection[ $this->id ];
94 $args['is_shortcode'] = true; // indicate that we are doing shortcode processing to outputting funtions.
95 $widget->widget(
96 array(
97 'before_widget' => '',
98 'after_widget' => '',
99 'before_title' => '',
100 'after_title' => '',
101 ),
102 $args
103 );
104 $ret = ob_get_clean();
105 $ret = '<div id="' . esc_attr( $this->id ) . '" class="' . esc_attr( $this->class ) . '">' . $ret . '</div>';
106 return $ret;
107 }
108
109 /**
110 * Get an array of HTML pre item, for item starting from a specific position.
111 *
112 * @since 4.9
113 *
114 * @param int $start The start element (0 based).
115 * @param int $number The maximal number of elements to return. A value of 0
116 * Indicates to use the widget settings for that.
117 * @param string $context The ID of the post in which the items will be displayed.
118 * A empty string or any value which is not of an ID
119 * of actual post will be treated as if there is no context.
120 *
121 * @return string[] Array of HTML per element with the $start element first
122 * $start+1 next etc. An empty array is returned if there
123 * are no applicable items.
124 */
125 public function get_elements_HTML( $start, $number, $context ) {
126 $ret = array();
127
128 $widget = new Widget();
129 $widget->number = $this->id; // needed to make a unique id for the widget html element.
130
131 $ret = $widget->get_elements_HTML( self::$collection[ $this->id ], $context, $start, $number );
132 return $ret;
133 }
134
135 /**
136 * Output the widget HTML
137 *
138 * Just a wrapper that output getHTML
139 *
140 * @return void
141 *
142 * @since 4.7
143 */
144 public function renderHTML() {
145 echo $this->getHTML(); // Xss off. Raw HTML is generated elsewhre.
146 }
147
148 /**
149 * Calculate the CSS rules required for the widget as is generated based on the settings passed at construction time
150 *
151 * @param string $context One of the CONTEXT_* constants. For backward compatibility
152 * a bool is accepted as well, true being a shortcode and
153 * false a widget.
154 * @param array $rules "returned" Collection of CSS rules.
155 *
156 * @since 4.7
157 */
158 public function getCSSRules( $context, &$rules ) {
159
160 if ( is_bool( $context ) ) { // Signature used before 5.0.0.
161 $context = $context ? CONTEXT_SHORTCODE : CONTEXT_WIDGET;
162 }
163
164 $is_shortcode = ( CONTEXT_SHORTCODE === $context );
165
166 $ret = array();
167 $settings = self::$collection[ $this->id ];
168 $everything_is_link = isset( $settings['everything_is_link'] ) && $settings['everything_is_link'];
169
170 $widget_id = $this->id;
171 if ( CONTEXT_WIDGET === $context ) {
172 $widget_id .= '-internal';
173 }
174 $disable_css = isset( $settings['disable_css'] ) && $settings['disable_css'];
175
176 if ( ! $disable_css ) { // checks if css disable is not set.
177
178 $styles = array( // styles that should be applied to all widgets.
179 'normalize' => 'ul {padding: 0;}',
180 'thumb_clenup' => '.cat-post-item img {max-width: initial; max-height: initial; margin: initial;}',
181 'author_clenup' => '.cat-post-author {margin-bottom: 0;}',
182 'thumb' => '.cat-post-thumbnail {margin: 5px 10px 5px 0;}',
183 'item_clenup' => '.cat-post-item:before {content: ""; clear: both;}',
184 'more_link' => '.cat-post-excerpt-more {display: inline-block;}',
185 'item_style' => '.cat-post-item {list-style: none; margin: 3px 0 10px; padding: 3px 0;}',
186 );
187
188 if ( ! ( isset( $settings['disable_font_styles'] ) && $settings['disable_font_styles'] ) ) { // checks if disable font styles is not set.
189 // add general styles which apply to font styling.
190 $styles['current_title_font'] = '.cat-post-current .cat-post-title {font-weight: bold; text-transform: uppercase;}';
191 $styles['post-taxs'] = '[class*=cat-post-tax] {font-size: 0.85em;}';
192 $styles['post-tax-childs'] = '[class*=cat-post-tax] * {display:inline-block;}';
193 }
194
195 // everything link related styling
196 // if we are dealing with "everything is a link" option, we need to add the clear:both to the a element, not the div.
197 if ( $everything_is_link ) {
198 $styles['after_item'] = '.cat-post-item a:after {content: ""; display: table; clear: both;}';
199 } else {
200 $styles['after_item'] = '.cat-post-item:after {content: ""; display: table; clear: both;}';
201 }
202
203 // title height in lines.
204 if ( isset( $settings['template'] ) && preg_match( '/%title%/', $settings['template'] ) ) {
205 $styles['item_title_lines'] = '.cat-post-item .cat-post-title {overflow: hidden;text-overflow: ellipsis;white-space: initial;' .
206 'display: -webkit-box;-webkit-line-clamp: ' . intval( $settings['item_title_lines'] ) . ';-webkit-box-orient: vertical;padding-bottom: 0 !important;}';
207 }
208
209 // wrap text around image.
210 if ( isset( $settings['template'] ) && preg_match( '/%excerpt%/', $settings['template'] ) ) {
211 $selector_wrap_text = 'p.cpwp-excerpt-text';
212 $no_wrap = isset( $settings['text_do_not_wrap_thumb'] ) && $settings['text_do_not_wrap_thumb'];
213 if ( ! $no_wrap ) {
214 // wrap thumb and line-clamp: set the CSS two parent knotes higher (first parent for float, second parent is a browser hack for that float works well).
215 $styles['wrap_thumb'] = '.cpwp-wrap-text p {display: inline;}';
216 $selector_wrap_text = '.cpwp-wrap-text';
217 }
218 $styles['excerpt_lines'] = '.cat-post-item ' . $selector_wrap_text . ' {overflow: hidden;text-overflow: ellipsis;white-space: initial;' .
219 'display: -webkit-box;-webkit-line-clamp: ' . intval( $settings['excerpt_lines'] ) . ';-webkit-box-orient: vertical;padding-bottom: 0 !important;}';
220 // float text instead wrap and don't hide the excerpt if there is no space
221 $styles['float_min_nowrap'] = 'p.cpwp-excerpt-text {min-width: 120px;}';
222 }
223
224 // add post format css if needed.
225 if ( isset( $settings['template'] ) && preg_match( '/%thumb%/', $settings['template'] ) ) {
226 if ( ! isset( $settings['show_post_format'] ) || ( ( 'none' !== $settings['show_post_format'] ) && ( 'nocss' !== $settings['show_post_format'] ) ) ) {
227 static $fonts_added = false;
228 if ( ! $fonts_added ) {
229 $fonturl = esc_url( plugins_url( 'icons/font', __FILE__ ) );
230 $ret['post_format_font'] = "@font-face {\n" .
231 "font-family: 'cat_post';\n" .
232 "src: url('$fonturl/cat_post.eot?58348147');\n" .
233 "src: url('$fonturl/cat_post.eot?58348147#iefix') format('embedded-opentype'),\n" .
234 " url('$fonturl/cat_post.woff2?58348147') format('woff2'),\n" .
235 " url('$fonturl/cat_post.woff?58348147') format('woff'),\n" .
236 " url('$fonturl/cat_post.ttf?58348147') format('truetype');\n" .
237 " font-weight: normal;\n" .
238 " font-style: normal;\n" .
239 "}\n";
240 }
241 $fonts_added = true;
242
243 $placement = '';
244 switch ( $settings['show_post_format'] ) {
245 case 'topleft':
246 $placement = 'top:10%; left:10%;';
247 break;
248 case 'bottomleft':
249 $placement = 'bottom:10%; left:10%;';
250 break;
251 case 'ceter':
252 $placement = 'top:calc(50% - 34px); left:calc(50% - 34px);';
253 break;
254 case 'topright':
255 $placement = 'top:10%; right:10%;';
256 break;
257 case 'bottomright':
258 $placement = 'bottom:10%; right:10%;';
259 break;
260 }
261 $styles['post_format_thumb'] = '.cat-post-thumbnail span {position:relative; display:inline-block;}';
262 $styles['post_format_icon_styling'] = '.cat-post-format:after {font-family: "cat_post"; position:absolute; color:#FFFFFF; font-size:64px; line-height: 1; ' . $placement . '}';
263
264 $styles['post_format_icon_aside'] = ".cat-post-format-aside:after { content: '\\f0f6'; }";
265 $styles['post_format_icon_chat'] = ".cat-post-format-chat:after { content: '\\e802'; }";
266 $styles['post_format_icon_gallery'] = ".cat-post-format-gallery:after { content: '\\e805'; }";
267 $styles['post_format_icon_link'] = ".cat-post-format-link:after { content: '\\e809'; }";
268 $styles['post_format_icon_image'] = ".cat-post-format-image:after { content: '\\e800'; }";
269 $styles['post_format_icon_quote'] = ".cat-post-format-quote:after { content: '\\f10d'; }";
270 $styles['post_format_icon_status'] = ".cat-post-format-status:after { content: '\\e80a'; }";
271 $styles['post_format_icon_video'] = ".cat-post-format-video:after { content: '\\e801'; }";
272 $styles['post_format_icon_audio'] = ".cat-post-format-audio:after { content: '\\e803'; }";
273
274 }
275 }
276
277 // everything link related styling
278 // if we are dealing with "everything is a link" option, we need to add the clear:both to the a element, not the div.
279 if ( $everything_is_link ) {
280 $styles['clear_previous_item'] = '.cat-post-item a:after {content: ""; clear: both;}';
281 } else {
282 $styles['clear_previous_item'] = '.cat-post-item:after {content: ""; display: table; clear: both;}';
283 }
284
285 foreach ( $styles as $key => $style ) {
286 $ret[ $key ] = '#' . $widget_id . ' ' . $style;
287 }
288
289 if ( $is_shortcode ) {
290 // Twenty Sixteen Theme adds underlines to links with box whadow wtf ...
291 $ret['twentysixteen_thumb'] = '#' . $widget_id . ' .cat-post-thumbnail {box-shadow:none}'; // this for the thumb link.
292 if ( ! ( isset( $settings['disable_font_styles'] ) && $settings['disable_font_styles'] ) ) { // checks if disable font styles is not set.
293 $ret['twentysixteen_tag_link'] = '#' . $widget_id . ' .cat-post-tax-tag a {box-shadow:none}'; // this for the tag link.
294 $ret['twentysixteen_tag_span'] = '#' . $widget_id . ' .cat-post-tax-tag span {box-shadow:none}'; // this for the tag link.
295 }
296 // Twenty Fifteen Theme adds border ...
297 $ret['twentyfifteen_thumb'] = '#' . $widget_id . ' .cat-post-thumbnail {border:0}'; // this for the thumb link.
298 if ( ! ( isset( $settings['disable_font_styles'] ) && $settings['disable_font_styles'] ) ) { // checks if disable font styles is not set.
299 $ret['twentysixteen_tag_link'] = '#' . $widget_id . ' .cat-post-tax-tag a {border:0}'; // this for the tag link.
300 $ret['twentysixteen_tag_span'] = '#' . $widget_id . ' .cat-post-tax-tag span {border:0}'; // this for the tag link.
301 }
302 }
303
304 // localized widget CSS rules for the thumbnail.
305 $ret['left'] = '#' . $widget_id . ' .cat-post-thumbnail {display:block; float:left; margin:5px 10px 5px 0;}';
306 $ret['crop'] = '#' . $widget_id . ' .cat-post-crop {overflow:hidden;display:block;}';
307
308 // probably all Themes have too much margin on their p element when used in the shortcode or widget.
309 $ret['p_styling'] = '#' . $widget_id . ' p {margin:5px 0 0 0}'; // since on bottom it will make the spacing on cover
310 // bigger (add to the padding) use only top for now.
311 $ret['div_styling'] = '#' . $widget_id . ' li > div {margin:5px 0 0 0; clear:both;}'; // Add margin between the rows.
312
313 // use WP dashicons in the template (e.g. for premade Template 'All and icons').
314 $ret['dashicons'] = '#' . $widget_id . ' .dashicons {vertical-align:middle;}';
315 }
316
317 // Regardless if css is disabled we need some styling for the thumbnail
318 // to make sure cropping is properly done, and they fit the allocated space.
319 if ( isset( $settings['template'] ) && preg_match( '/%thumb%/', $settings['template'], $m, PREG_OFFSET_CAPTURE ) ) {
320 if ( isset( $settings['thumb_h'] ) && 0 !== intval( $settings['thumb_h'] ) ) {
321 $ret['thumb_crop_h'] = '#' . $widget_id . ' .cat-post-thumbnail .cat-post-crop img {height: ' . intval($settings['thumb_h']) . 'px;}';
322 }
323 if ( isset( $settings['thumb_w'] ) && 0 !== intval( $settings['thumb_w'] ) ) {
324 $ret['thumb_crop_w'] = '#' . $widget_id . ' .cat-post-thumbnail .cat-post-crop img {width: ' . intval($settings['thumb_w']) . 'px;}';
325 }
326 $ret['thumb_crop'] = '#' . $widget_id . ' .cat-post-thumbnail .cat-post-crop img {object-fit: cover; max-width: 100%; display: block;}';
327 $ret['thumb_crop_not_supported'] = '#' . $widget_id . ' .cat-post-thumbnail .cat-post-crop-not-supported img {width: 100%;}';
328 $ret['thumb_fluid_width'] = '#' . $widget_id . ' .cat-post-thumbnail {max-width:' . intval( $settings['thumb_fluid_width'] ) . '%;}';
329 $ret['thumb_styling'] = '#' . $widget_id . ' .cat-post-item img {margin: initial;}';
330 }
331
332 // Some hover effect require css to work, add it even if CSS is disabled.
333 if ( isset( $settings['thumb_hover'] ) ) {
334 switch ( $settings['thumb_hover'] ) {
335 case 'white':
336 $ret['white_hover_background'] = '#' . $widget_id . ' .cat-post-white span {background-color: white;}';
337 $ret['white_hover_thumb'] = '#' . $widget_id . ' .cat-post-white img {padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
338 $ret['white_hover_transform'] = '#' . $widget_id . ' .cat-post-white:hover img {opacity: 0.8;}';
339 break;
340 case 'dark':
341 $ret['dark_hover_thumb'] = '#' . $widget_id . ' .cat-post-dark img {padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
342 $ret['dark_hover_transform'] = '#' . $widget_id . ' .cat-post-dark:hover img {-webkit-filter: brightness(75%); -moz-filter: brightness(75%); -ms-filter: brightness(75%); -o-filter: brightness(75%); filter: brightness(75%);}';
343 break;
344 case 'scale':
345 $ret['scale_hover_thumb'] = '#' . $widget_id . ' .cat-post-scale img {margin: initial; padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
346 $ret['scale_hover_transform'] = '#' . $widget_id . ' .cat-post-scale:hover img {-webkit-transform: scale(1.1, 1.1); -ms-transform: scale(1.1, 1.1); transform: scale(1.1, 1.1);}';
347 break;
348 case 'blur':
349 $ret['blur_hover_thumb'] = '#' . $widget_id . ' .cat-post-blur img {padding-bottom: 0 !important; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
350 $ret['blur_hover_transform'] = '#' . $widget_id . ' .cat-post-blur:hover img {-webkit-filter: blur(2px); -moz-filter: blur(2px); -o-filter: blur(2px); -ms-filter: blur(2px); filter: blur(2px);}';
351 break;
352 case 'icon':
353 $fonturl = esc_url( plugins_url( 'icons/font', __FILE__ ) );
354 $ret['icon_hover_font'] = "@font-face {\n" .
355 "font-family: 'cat_post';\n" .
356 "src: url('$fonturl/cat_post.eot?58348147');\n" .
357 "src: url('$fonturl/cat_post.eot?58348147#iefix') format('embedded-opentype'),\n" .
358 " url('$fonturl/cat_post.woff2?58348147') format('woff2'),\n" .
359 " url('$fonturl/cat_post.woff?58348147') format('woff'),\n" .
360 " url('$fonturl/cat_post.ttf?58348147') format('truetype');\n" .
361 " font-weight: normal;\n" .
362 " font-style: normal;\n" .
363 "}\n";
364
365 $ret['icon_hover_thumb'] = '#' . $widget_id . ' .cat-post-format-standard:after {opacity:0; -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; -o-transition: all 0.3s ease; transition: all 0.3s ease;}';
366 $ret['icon_hover_transform'] = '#' . $widget_id . ' .cat-post-thumbnail:hover .cat-post-format-standard:after {opacity:1;}';
367 if ( isset( $settings['show_post_format'] ) && ( 'none' === $settings['show_post_format'] ) ) {
368 $ret[] = '#' . $widget_id . ' .cat-post-thumbnail span {position:relative; display:inline-block;}';
369 $ret[] = '#' . $widget_id . ' .cat-post-icon .cat-post-format:after {font-family: "cat_post"; position:absolute; color:#FFFFFF; font-size:64px; line-height: 1; ' .
370 'top:calc(50% - 34px); left:calc(50% - 34px);}';
371 }
372 $ret[] = '#' . $widget_id . " .cat-post-format-standard:after {padding-left:12px; content: '\\e806'; }";
373 break;
374 }
375 }
376 if ( $settings['enable_loadmore'] ) {
377 // $this->id is used over $widget_id because we need the id of the outer div, not the UL itself.
378 $ret['loadmore'] = '#' . $this->id . ' .' . __NAMESPACE__ . '-loadmore {text-align:center;margin-top:10px}';
379
380 // Scrollbar
381 if ( isset( $settings['loadmore_scrollTo'] ) && $settings['loadmore_scrollTo'] ) {
382 $ret['loadmore_scrollTo'] = '#' . $widget_id . ' {overflow-y:scroll;}';
383 }
384 }
385 $rules[] = $ret;
386 }
387
388 /**
389 * Output the widget CSS
390 *
391 * Just a wrapper that output getCSSRules
392 *
393 * @param string $context One of the CONTEXT_* constants, see getCSSRules().
394 *
395 * @since 4.7
396 */
397 public function outputCSS( $context ) {
398 $rules = array();
399 $this->getCSSRules( $context, $rules );
400 foreach ( $rules as $group ) {
401 foreach ( $group as $rule ) {
402 echo "$rule\n"; // Xss off - raw css can not be html escaped.
403 }
404 }
405 }
406
407 /**
408 * Get the id the virtual widget was registered with
409 *
410 * @return string
411 *
412 * @since 4.7
413 */
414 public function id() {
415 return $this->id;
416 }
417
418 /**
419 * Get all the setting of the virtual widgets in an array
420 *
421 * @return array
422 *
423 * @since 4.7
424 */
425 public static function getAllSettings() {
426 return self::$collection;
427 }
428
429 }
430