cl01/wp-content/plugins/recent-posts-widget-with-thumbnails/recent-posts-widget-with-thumbnails.php
2025-02-24 12:39:24 +08:00

1094 lines
45 KiB
PHP
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/*
* Plugin Name: Recent Posts Widget With Thumbnails
* Plugin URI: https://wordpress.org/plugins/recent-posts-widget-with-thumbnails/
* Description: Small and fast plugin to display in the sidebar a list of linked titles and thumbnails of the most recent postings
* Version: 7.1.1
* Requires at least: 4.6
* Requires PHP: 5.2
* Author: Kybernetik Services
* Author URI: https://www.kybernetik-services.com/?utm_source=wordpress_org&utm_medium=plugin&utm_campaign=recent-posts-widget-with-thumbnails&utm_content=author
* Text Domain: recent-posts-widget-with-thumbnails
* License: GPL-2.0+
* License URI: https://www.gnu.org/licenses/gpl-2.0.txt
*/
/**
* Recent_Posts_Widget_With_Thumbnails widget class
*
* @since 1.0
*/
class Recent_Posts_Widget_With_Thumbnails extends WP_Widget {
var $defaults; // default values
var $bools_false; // key names of bool variables of value 'false'
var $bools_true; // key names of bool variables of value 'true'
var $ints; // key names of integer variables of any value
var $customs; // user defined values
var $use_inline_css;// class wide setting, bool type
var $use_no_css; // class wide setting, bool type
// Create the widget options and such here, then call
// $this->WP_Widget to let wordpress know about it.
function __construct() {
$language_codes = explode( '_', get_locale() );
switch ( $language_codes[ 0 ] ) {
case 'ar':
$widget_name = 'آخر المقالات مع الصوّر المصغّرة';
$widget_desc = 'قائمة موقعك المشاركات الأخيرة، مع عنوان نقر والصور المصغرة';
break;
case 'fa':
$widget_name = 'نوشته های اخیر با تصویر بندانگشتی';
$widget_desc = 'فهرست سایت شما ارسال جدید، با عنوان قابل کلیک و عکسها';
break;
case 'de':
$widget_name = 'Neueste Beitr&auml;ge mit Vorschaubildern';
$widget_desc = 'Liste deiner aktuellsten Beitr&auml;ge, mit klickbaren &Uuml;berschriften und Vorschaubildern.';
break;
case 'pl':
$widget_name = 'Ostatnie posty z miniaturami';
$widget_desc = 'Lista ostatnich wpisów twojej strony z klikalnymi tytułami i miniaturami.';
break;
case 'ru':
$widget_name = 'Последние записи с эскизами';
$widget_desc = 'Список последних сообщений вашего сайта, с заголовком интерактивными и иконками.';
break;
case 'tr':
$widget_name = 'Küçük Resimlerle Son Yazılar';
$widget_desc = 'Başlık ve küçük resimleri tıklanabilir olan sitenizin en son yazıların listesi.';
break;
case 'ja':
$widget_name = 'Recent Posts With Thumbnails';
$widget_desc = 'サイトの最新の投稿を、クリック可能なタイトルとサムネイル付きで一覧表示します。';
break;
case 'ca':
$widget_name = 'Publicacions recents amb miniatures';
$widget_desc = 'Llista de les publicacions més recents del vostre lloc, amb títol i miniatures que es poden fer clic.';
break;
default:
$widget_name = 'Recent Posts With Thumbnails';
$widget_desc = 'List of your site&#8217;s most recent posts, with clickable title and thumbnails.';
}
$this->defaults[ 'author_label' ] = __( 'By', 'recent-posts-widget-with-thumbnails' );
$this->defaults[ 'category_ids' ] = array( 0 ); // selected categories
$this->defaults[ 'category_label' ] = _x( 'In', 'In {categories}', 'recent-posts-widget-with-thumbnails' ); // label for category list
$this->defaults[ 'css_file_path' ] = dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'public.css'; // path of the public css file
$this->defaults[ 'excerpt_length' ] = absint( apply_filters( 'rpwwt_excerpt_length', 55 ) ); // default length: 55 characters
$this->defaults[ 'excerpt_more' ] = apply_filters( 'rpwwt_excerpt_more', ' ' . '[&hellip;]' ); // set ellipses as default 'more'
$this->defaults[ 'is_nav_widget' ] = current_theme_supports( 'html5', 'navigation-widgets' ); // available support of navigation in widgets (NAV element for more accessibility), since WP 5.5
$this->defaults[ 'nav_label' ] = __( 'Recent Posts With Thumbnails', 'recent-posts-widget-with-thumbnails' ); // ARIA label of the navigation list
$this->defaults[ 'number_posts' ] = 5; // number of posts to show in the widget
$this->defaults[ 'orderby' ] = 'date'; // default order value
$this->defaults[ 'order' ] = 'desc'; // default sort value
$this->defaults[ 'plugin_slug' ] = 'recent-posts-widget-with-thumbnails'; // identifier of this plugin for WP
$this->defaults[ 'plugin_version' ] = '7.1.1'; // current plugin version
$this->defaults[ 'post_title_length' ] = 1000; // default length: 1000 characters
$this->defaults[ 'thumb_alt' ] = '';
$this->defaults[ 'thumb_dimensions' ] = 'custom'; // dimensions of the thumbnail
$this->defaults[ 'thumb_height' ] = absint( round( get_option( 'thumbnail_size_h', 110 ) / 2 ) ); // custom height of the thumbnail
$this->defaults[ 'thumb_url' ] = plugins_url( 'default_thumb.gif', __FILE__ ); // URL of the default thumbnail
$this->defaults[ 'thumb_width' ] = absint( round( get_option( 'thumbnail_size_w', 110 ) / 2 ) ); // custom width of the thumbnail
$this->defaults[ 'widget_title' ] = ''; // title of the widget
// Domain name and protocol of WP site
$parsed_url = parse_url( home_url() );
$this->defaults[ 'site_protocol' ] = $parsed_url[ 'host' ];
$this->defaults[ 'site_url' ] = $parsed_url[ 'scheme' ];
unset( $parsed_url );
// other vars
$this->bools_false = array( 'hide_current_post', 'only_sticky_posts', 'hide_sticky_posts', 'hide_title', 'keep_aspect_ratio', 'keep_sticky', 'only_1st_img', 'random_order', 'show_author', 'show_categories', 'show_comments_number', 'show_date', 'show_excerpt', 'ignore_excerpt', 'ignore_post_content_excerpt', 'set_more_as_link', 'try_1st_img', 'use_default', 'use_default_only', 'open_new_window', 'print_post_categories', 'set_cats_as_links', 'use_inline_css', 'use_no_css', 'hide_alt_texts' );
$this->bools_true = array( 'show_thumb' );
$this->ints = array( 'excerpt_length', 'number_posts', 'post_title_length', 'thumb_height', 'thumb_width' );
$this->valid_excerpt_sources = array( 'post_content', 'excerpt_field' );
$this->optional_text_fields = array( 'author_label', 'excerpt_more', 'category_label', 'thumb_alt' );
$widget_ops = array( 'classname' => $this->defaults[ 'plugin_slug' ], 'description' => $widget_desc );
parent::__construct( $this->defaults[ 'plugin_slug' ], $widget_name, $widget_ops );
add_action( 'save_post', array( $this, 'flush_widget_cache' ) );
add_action( 'deleted_post', array( $this, 'flush_widget_cache' ) );
add_action( 'switch_theme', array( $this, 'flush_widget_cache' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_public_style' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_style' ) );
// not in use, just for the po-editor to display the translation on the plugins overview list
$widget_name = __( 'Recent Posts With Thumbnails', 'recent-posts-widget-with-thumbnails' );
$widget_desc = __( 'List of your site&#8217;s most recent posts, with clickable title and thumbnails.', 'recent-posts-widget-with-thumbnails' );
}
// display the widget on the front end.
function widget( $args, $instance ) {
global $post;
if ( ! isset( $args[ 'widget_id' ] ) ) {
$args[ 'widget_id' ] = $this->id;
}
// get and sanitize values
$title = ( ! empty( $instance[ 'title' ] ) ) ? $instance[ 'title' ] : $this->defaults[ 'widget_title' ];
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
$category_ids = ( ! empty( $instance[ 'category_ids' ] ) ) ? array_map( 'absint', $instance[ 'category_ids' ] ) : $this->defaults[ 'category_ids' ];
$default_url = ( ! empty( $instance[ 'default_url' ] ) ) ? $instance[ 'default_url' ] : $this->defaults[ 'thumb_url' ];
$thumb_dimensions = ( ! empty( $instance[ 'thumb_dimensions' ] ) ) ? $instance[ 'thumb_dimensions' ] : $this->defaults[ 'thumb_dimensions' ];
$orderby = ( ! empty( $instance[ 'orderby' ] ) ) ? $instance[ 'orderby' ] : $this->defaults[ 'orderby' ];
$order = ( ! empty( $instance[ 'order' ] ) && 'rand' != $orderby ) ? $instance[ 'order' ] : $this->defaults[ 'order' ];
// initialize integer variables
$ints = array();
foreach ( $this->ints as $key ) {
$ints[ $key ] = ( ! empty( $instance[ $key ] ) ) ? absint( $instance[ $key ] ) : $this->defaults[ $key ];
}
// initialize bool variables
$bools = array();
foreach ( $this->bools_false as $key ) {
$bools[ $key ] = ( isset( $instance[ $key ] ) ) ? (bool) $instance[ $key ] : false;
}
foreach ( $this->bools_true as $key ) {
$bools[ $key ] = ( isset( $instance[ $key ] ) ) ? (bool) $instance[ $key ] : false;
}
// special case: class wide setting
$this->use_inline_css = $bools[ 'use_inline_css' ];
$this->use_no_css = $bools[ 'use_no_css' ];
// if 'all categories' was selected ignore other selections of categories
if ( in_array( 0, $category_ids ) ) {
$category_ids = $this->defaults[ 'category_ids' ];
}
// if no URL take default URL
if ( '' == esc_url_raw( $default_url ) ) {
$default_url = $this->defaults[ 'thumb_url' ];
}
// ToDo: add option to filter custom post types as well
// standard params
$query_args = array(
'posts_per_page' => $ints[ 'number_posts' ],
'no_found_rows' => true,
'post_status' => 'publish',
'orderby' => $orderby
);
if( 'rand' != $orderby ) {
$query_args[ 'order' ] = $order;
}
// make downward compatible from version 7.1 and up
// deprecated $bools[ 'random_order' ]
if( $bools['random_order'] ) {
$this->ints[ 'orderby' ] = 'rand';
}
// set order of posts in widget
//$query_args[ 'orderby' ] = ( $bools[ 'random_order' ] ) ? 'rand' : 'menu_order, post_date';
// add categories param only if 'all categories' was not selected
if ( ! in_array( 0, $category_ids ) ) {
$query_args[ 'category__in' ] = $category_ids;
}
// exclude current displayed post
if ( $bools[ 'hide_current_post' ] ) {
if ( isset( $post->ID ) and is_singular() ) {
$query_args[ 'post__not_in' ] = array( $post->ID );
}
}
// ignore sticky posts if desired, else show them on top
$query_args[ 'ignore_sticky_posts' ] = ( $bools[ 'keep_sticky' ] ) ? false : true;
// exclude sticky posts
if ( $bools[ 'only_sticky_posts' ] ) {
// set the filter with IDs of sticky posts
$query_args[ 'post__in' ] = get_option( 'sticky_posts', array() );
// The next line appears illogical in comparison with the
// previous line, but is necessary to display the correct
// number of posts if the number of sticky posts is greater
// than the number of posts to be displayed.
$query_args[ 'ignore_sticky_posts' ] = true;
} elseif ( $bools[ 'hide_sticky_posts' ] ) {
// get IDs of sticky posts
$post_ids = get_option( 'sticky_posts', array() );
// if there are sticky posts
if ( $post_ids ) {
// if argument 'post__not_in' is defined
if ( isset( $query_args[ 'post__not_in' ] ) ) {
// merge argument arrays
$tmp1 = array_merge( $query_args[ 'post__not_in' ], $post_ids );
// make post IDs in array unique by using a faster way than array_unique()
$tmp2 = array();
foreach( $tmp1 as $key => $val ) {
$tmp2[ $val ] = true;
}
// set argument with cleaned array
$query_args[ 'post__not_in' ] = array_keys( $tmp2 );
// delete temporary variables
unset( $tmp1, $tmp2 );
} else {
// set argument with array of post IDs
$query_args[ 'post__not_in' ] = $post_ids;
}
}
// delete temporary variable
unset( $post_ids );
}
// apply correction function if query includes sticky posts and categories filter
if ( isset( $query_args[ 'category__in' ] ) and $bools[ 'keep_sticky' ] ) {
add_filter( 'the_posts', array( $this, 'get_stickies_on_top' ) );
}
// run the query: get the latest posts
$r = new WP_Query( apply_filters( 'rpwwt_widget_posts_args', $query_args ) );
// remove correction function if query includes sticky posts and categories filter
if ( isset( $query_args[ 'category__in' ] ) and $bools[ 'keep_sticky' ] ) {
remove_filter( 'the_posts', array( $this, 'get_stickies_on_top' ) );
}
if ( $r->have_posts() ) :
// translate repeately used texts once (for more performance)
$text = ', ';
$this->defaults[ 'comma' ] = __( $text );
$text = '&hellip;';
$this->defaults[ 'ellipses' ] = __( $text );
$text = '(no title)';
$this->defaults[ 'no_title' ] = __( $text );
$text = 'Post';
$this->defaults[ 'Post' ] = _x( $text, 'post type singular name' );
// get current post ID
$queried_object_id = get_queried_object_id();
// set the desired image dimensions
if ( 'custom' == $thumb_dimensions ) {
// set dimensions with specified size array
$this->customs[ 'thumb_dimensions' ] = array( $ints[ 'thumb_width' ], $ints[ 'thumb_height' ] );
} else {
// overwrite thumb_width and thumb_height with closest size
list( $ints[ 'thumb_width' ], $ints[ 'thumb_height' ] ) = $this->get_image_dimensions( $thumb_dimensions );
// set dimensions with specified size name
$this->customs[ 'thumb_dimensions' ] = $thumb_dimensions;
}
// for some text fields: let there be an empty fields if desired
foreach ( $this->optional_text_fields as $field ) {
if ( isset( $instance[ $field ] ) ) {
if ( '' === $instance[ $field ] ) {
$this->customs[ $field ] = '';
} else {
$this->customs[ $field ] = $instance[ $field ];
}
} else {
$this->customs[ $field ] = $this->defaults[ $field ];
}
}
// set other global vars
$this->customs[ 'ignore_excerpt' ] = $bools[ 'ignore_excerpt' ]; // whether to ignore post excerpt field or not
$this->customs[ 'ignore_post_content_excerpt' ] = $bools[ 'ignore_post_content_excerpt' ]; // whether to ignore post content or not
$this->customs[ 'set_more_as_link' ] = $bools[ 'set_more_as_link' ]; // whether to set 'more' signs as link or not
$this->customs[ 'set_cats_as_links' ] = $bools[ 'set_cats_as_links' ]; // whether to set category names as links or not
$this->customs[ 'excerpt_length' ] = $ints[ 'excerpt_length' ]; // number of characters of excerpt
$this->customs[ 'post_title_length' ] = $ints[ 'post_title_length' ]; // maximum number of characters of post title
// set default image code
$default_attr = array(
'src' => esc_url( $default_url ),
'class' => sprintf( "attachment-%dx%d", $ints[ 'thumb_width' ], $ints[ 'thumb_height' ] ),
'alt' => $bools[ 'hide_alt_texts' ] ? '' : esc_attr( $this->customs[ 'thumb_alt' ] ),
'loading' => 'lazy',
);
$default_img = '<img ';
$default_img .= rtrim( image_hwstring( $ints[ 'thumb_width' ], $ints[ 'thumb_height' ] ) );
foreach ( $default_attr as $name => $value ) {
$default_img .= ' ' . $name . '="' . $value . '"';
}
$default_img .= ' />';
// set link target
if ( $bools[ 'open_new_window' ] ) {
$this->customs[ 'link_target' ] = ' target="_blank"';
} else {
$this->customs[ 'link_target' ] = '';
}
//set image attributes
$attr = '';
if ( $bools[ 'hide_alt_texts' ] ) {
$attr = array( 'alt' => '' );
}
// print list
include 'includes/widget.php';
// Reset the global $the_post as this query will have stomped on it
wp_reset_postdata();
endif;
}
// The widget form in the admin area.
function update( $new_widget_settings, $old_widget_settings ) {
$instance = $old_widget_settings;
// sanitize user input before update
$instance[ 'title' ] = ( isset( $new_widget_settings[ 'title' ] ) ) ? strip_tags( $new_widget_settings[ 'title' ] ) : $this->defaults[ 'widget_title' ];
$instance[ 'default_url' ] = ( isset( $new_widget_settings[ 'default_url' ] ) ) ? esc_url_raw( $new_widget_settings[ 'default_url' ] ) : $this->defaults[ 'thumb_url' ];
$instance[ 'thumb_dimensions' ] = ( isset( $new_widget_settings[ 'thumb_dimensions' ] ) ) ? strip_tags( $new_widget_settings[ 'thumb_dimensions' ] ) : $this->defaults[ 'thumb_dimensions' ];
$instance[ 'category_ids' ] = ( isset( $new_widget_settings[ 'category_ids' ] ) ) ? array_map( 'absint', $new_widget_settings[ 'category_ids' ] ) : $this->defaults[ 'category_ids' ];
$instance[ 'orderby' ] = ( isset( $new_widget_settings[ 'orderby' ] ) ) ? $new_widget_settings[ 'orderby' ] : $this->defaults[ 'orderby' ];
$instance[ 'order' ] = ( isset( $new_widget_settings[ 'order' ] ) ) ? $new_widget_settings[ 'order' ] : $this->defaults[ 'order' ];
// initialize integer variables
foreach ( $this->ints as $key ) {
$instance[ $key ] = ( isset( $new_widget_settings[ $key ] ) ) ? absint( $new_widget_settings[ $key ] ) : $this->defaults[ $key ];
}
// initialize bool variables
foreach ( $this->bools_false as $key ) {
$instance[ $key ] = isset( $new_widget_settings[ $key ] ) && $new_widget_settings[ $key ];
}
foreach ( $this->bools_true as $key ) {
$instance[ $key ] = isset( $new_widget_settings[ $key ]) && $new_widget_settings[ $key ];
}
// for some text fields: let there be an empty fields if desired
foreach ( $this->optional_text_fields as $field ) {
if ( isset( $new_widget_settings[ $field ] ) ) {
if ( '' == $new_widget_settings[ $field ] ) {
$instance[ $field ] = '';
} else {
$instance[ $field ] = $new_widget_settings[ $field ];
}
} else {
$instance[ $field ] = $this->defaults[ $field ];
}
}
// if 'all categories' was selected ignore other selections of categories
if ( in_array( 0, $instance[ 'category_ids' ] ) ) {
$instance[ 'category_ids' ] = $this->defaults[ 'category_ids' ];
}
// empty widget cache
$this->flush_widget_cache();
$alloptions = wp_cache_get( 'alloptions', 'options' );
if ( isset( $alloptions[ $this->defaults[ 'plugin_slug' ] ] ) ) {
delete_option( $this->defaults[ 'plugin_slug' ] );
}
// delete current css file to let make new one via $this->enqueue_public_style()
if ( file_exists( $this->defaults[ 'css_file_path' ] ) ) {
// remove the file
unlink( $this->defaults[ 'css_file_path' ] );
}
// return sanitized current widget settings
return $instance;
}
function flush_widget_cache() {
wp_cache_delete( $this->defaults[ 'plugin_slug' ], 'widget' );
}
// Saves the data, called via AJAX. But the saving logic comes here.
function form( $instance ) {
// get and sanitize values
$title = ( isset( $instance[ 'title' ] ) ) ? $instance[ 'title' ] : $this->defaults[ 'widget_title' ];
$thumb_dimensions = ( isset( $instance[ 'thumb_dimensions' ] ) ) ? $instance[ 'thumb_dimensions' ] : $this->defaults[ 'thumb_dimensions' ];
$default_url = ( isset( $instance[ 'default_url' ] ) ) ? $instance[ 'default_url' ] : $this->defaults[ 'thumb_url' ];
$category_ids = ( isset( $instance[ 'category_ids' ] ) ) ? $instance[ 'category_ids' ] : $this->defaults[ 'category_ids' ];
// initialize integer variables
$ints = array();
foreach ( $this->ints as $key ) {
$ints[ $key ] = ( isset( $instance[ $key ] ) ) ? absint( $instance[ $key ] ) : $this->defaults[ $key ];
}
// initialize bool variables
$bools = array();
foreach ( $this->bools_false as $key ) {
$bools[ $key ] = ( isset( $instance[ $key ] ) ) ? (bool) $instance[ $key ] : false;
}
foreach ( $this->bools_true as $key ) {
$bools[ $key ] = ( isset( $instance[ $key ] ) ) ? (bool) $instance[ $key ] : true;
}
// for some text fields: let there be an empty fields if desired
foreach ( $this->optional_text_fields as $field ) {
if ( isset( $instance[ $field ] ) ) {
if ( '' == $instance[ $field ] ) {
$optional_texts[ $field ] = '';
} else {
$optional_texts[ $field ] = $instance[ $field ];
}
} else {
$optional_texts[ $field ] = $this->defaults[ $field ];
}
}
// if 'all categories' was selected ignore other selections of categories
if ( in_array( 0, $category_ids ) ) {
$category_ids = $this->defaults[ 'category_ids' ];
}
// if no URL take default URL
if ( '' == esc_url_raw( $default_url ) ) {
$default_url = $this->defaults[ 'thumb_url' ];
}
// compute ids only once to improve performance
$field_ids = array();
$field_ids[ 'author_label' ] = $this->get_field_id( 'author_label' );
$field_ids[ 'category_ids' ] = $this->get_field_id( 'category_ids' );
$field_ids[ 'category_label' ] = $this->get_field_id( 'category_label' );
$field_ids[ 'default_url' ] = $this->get_field_id( 'default_url' );
$field_ids[ 'excerpt_more' ] = $this->get_field_id( 'excerpt_more' );
$field_ids[ 'thumb_alt' ] = $this->get_field_id( 'thumb_alt' );
$field_ids[ 'thumb_dimensions' ]= $this->get_field_id( 'thumb_dimensions' );
$field_ids[ 'title' ] = $this->get_field_id( 'title' );
$field_ids[ 'orderby' ] = $this->get_field_id( 'orderby' );
$field_ids[ 'order' ] = $this->get_field_id( 'order' );
foreach ( array_merge( $this->ints, $this->bools_false, $this->bools_true ) as $key ) {
$field_ids[ $key ] = $this->get_field_id( $key );
}
// get texts and values for image sizes dropdown
global $_wp_additional_image_sizes;
$wp_standard_image_size_labels = array();
$label = 'Full Size'; $wp_standard_image_size_labels[ 'full' ] = __( $label );
$label = 'Large'; $wp_standard_image_size_labels[ 'large' ] = __( $label );
$label = 'Medium'; $wp_standard_image_size_labels[ 'medium' ] = __( $label );
$label = 'Thumbnail'; $wp_standard_image_size_labels[ 'thumbnail' ] = __( $label );
$wp_standard_image_size_names = array_keys( $wp_standard_image_size_labels );
$size_options = array();
foreach ( get_intermediate_image_sizes() as $size_name ) {
// Don't take numeric sizes that appear
if( is_integer( $size_name ) ) {
continue;
}
$option_values = array();
// Set technical name
$option_values[ 'size_name' ] = $size_name;
// Set name
$option_values[ 'name' ] = in_array( $size_name, $wp_standard_image_size_names ) ? $wp_standard_image_size_labels[$size_name] : $size_name;
// Set width
$option_values[ 'width' ] = isset( $_wp_additional_image_sizes[$size_name]['width'] ) ? $_wp_additional_image_sizes[$size_name]['width'] : get_option( "{$size_name}_size_w" );
// Set height
$option_values[ 'height' ] = isset( $_wp_additional_image_sizes[$size_name]['height'] ) ? $_wp_additional_image_sizes[$size_name]['height'] : get_option( "{$size_name}_size_h" );
// add option to options list
$size_options[] = $option_values;
}
// create text to Media Settings page
$text = 'Settings'; $label_settings = __( $text );
$text = 'Media'; $label_media = _x( $text, 'post type general name' );
$label = sprintf( '%s &rsaquo; %s', $label_settings, $label_media );
$media_trail = ( current_user_can( 'manage_options' ) ) ? sprintf( '<a href="%s" target="_blank">%s</a>', esc_url( admin_url( 'options-media.php' ) ), esc_html( $label ) ) : sprintf( '<em>%s</em>', esc_html( $label ) );
// oder settings
$option_values[ 'orderby' ] = ( isset( $instance[ 'orderby' ] ) ) ? $instance[ 'orderby' ] : $this->defaults[ 'orderby' ];
// make downward compatible from version 7.1 and up
// deprecated $bools[ 'random_order' ]
if( true == $bools[ 'random_order' ] ) {
$option_values[ 'orderby' ] = 'rand';
}
$option_values[ 'order' ] = ( isset( $instance[ 'order' ] ) && 'rand' != $option_values[ 'orderby' ] ) ? $instance[ 'order' ] : $this->defaults[ 'order' ];
// get texts and values for categories dropdown
$all_text = __( 'All Categories', 'recent-posts-widget-with-thumbnails' );
$label_all_cats = $all_text;
// get categories
$categories = get_categories( array( 'hide_empty' => 0, 'hierarchical' => 1 ) );
$number_of_cats = count( $categories );
// get size (number of rows to display) of selection box: not more than 10
$number_of_rows = ( 10 > $number_of_cats ) ? $number_of_cats + 1 : 10;
// start selection box
$selection_element = sprintf(
'<select name="%s[]" id="%s" class="rpwwt-cat-select" multiple size="%d">',
$this->get_field_name( 'category_ids' ),
$field_ids[ 'category_ids' ],
$number_of_rows
);
$selection_element .= "\n";
// make selection box entries
$cat_list = array();
if ( 0 < $number_of_cats ) {
// make a hierarchical list of categories
while ( $categories ) {
// go on with the first element in the categories list:
// if there is no parent
if ( '0' == $categories[ 0 ]->parent ) {
// get and remove it from the categories list
$current_entry = array_shift( $categories );
// append the current entry to the new list
$cat_list[] = array(
'id' => absint( $current_entry->term_id ),
'name' => esc_html( $current_entry->name ),
'depth' => 0
);
// go on looping
continue;
}
// if there is a parent:
// try to find parent in new list and get its array index
$parent_index = $this->get_cat_parent_index( $cat_list, $categories[ 0 ]->parent );
// if parent is not yet in the new list: try to find the parent later in the loop
if ( false === $parent_index ) {
// get and remove current entry from the categories list
$current_entry = array_shift( $categories );
// append it at the end of the categories list
$categories[] = $current_entry;
// go on looping
continue;
}
// if there is a parent and parent is in new list:
// set depth of current item: +1 of parent's depth
$depth = $cat_list[ $parent_index ][ 'depth' ] + 1;
// set new index as next to parent index
$new_index = $parent_index + 1;
// find the correct index where to insert the current item
foreach( $cat_list as $entry ) {
// if there are items with same or higher depth than current item
if ( $depth <= $entry[ 'depth' ] ) {
// increase new index
$new_index = $new_index + 1;
// go on looping in foreach()
continue;
}
// if the correct index is found:
// get current entry and remove it from the categories list
$current_entry = array_shift( $categories );
// insert current item into the new list at correct index
$end_array = array_splice( $cat_list, $new_index ); // $cat_list is changed, too
$cat_list[] = array(
'id' => absint( $current_entry->term_id ),
'name' => esc_html( $current_entry->name ),
'depth' => $depth
);
$cat_list = array_merge( $cat_list, $end_array );
// quit foreach(), go on while-looping
break;
} // foreach( cat_list )
} // while( categories )
// make HTML of selection box
$selected = ( in_array( 0, $category_ids ) ) ? ' selected="selected"' : '';
$selection_element .= "\t";
$selection_element .= '<option value="0"' . $selected . '>' . $label_all_cats . '</option>';
$selection_element .= "\n";
foreach ( $cat_list as $category ) {
$cat_name = apply_filters( 'rpwwt_list_cats', $category[ 'name' ], $category );
$pad = ( 0 < $category[ 'depth' ] ) ? str_repeat('&ndash;&nbsp;', $category[ 'depth' ] ) : '';
$selection_element .= "\t";
$selection_element .= '<option value="' . $category[ 'id' ] . '"';
$selection_element .= ( in_array( $category[ 'id' ], $category_ids ) ) ? ' selected="selected"' : '';
$selection_element .= '>' . $pad . $cat_name . '</option>';
$selection_element .= "\n";
}
}
// close selection box
$selection_element .= "</select>\n";
// print form in widgets page
include 'includes/form.php';
}
/**
* Return the array index of a given ID
*
* @since 4.1
*/
private function get_cat_parent_index( $arr, $id ) {
$len = count( $arr );
if ( 0 == $len ) {
return false;
}
$id = absint( $id );
for ( $i = 0; $i < $len; $i++ ) {
if ( $id == $arr[ $i ][ 'id' ] ) {
return $i;
}
}
return false;
}
/**
* Load the widget's CSS in the HEAD section of the frontend
*
* @since 2.3
*/
public function enqueue_public_style () {
$is_file = false;
$css_code = '';
// make sure the CSS file exists; if not available: generate it
if ( file_exists( $this->defaults[ 'css_file_path' ] ) ) {
$is_file = true;
} else {
// get stored settings
$all_settings = $this->get_settings();
// quit if at least 1 widget was set for no CSS at all
foreach ( $all_settings as $id => $settings ) {
if ( isset( $settings[ 'use_no_css' ] ) and $settings[ 'use_no_css' ] ) {
return;
}
} // foreach ( $all_settings as $id => $settings )
// get the CSS code
list( $css_code, $use_inline_css ) = $this->generate_css_code( $all_settings );
// if not to print the CSS as inline code in the HTML document
if ( ! $use_inline_css ) {
// write file safely
if ( @file_put_contents( $this->defaults[ 'css_file_path' ], $css_code ) ) {
// file writing was successfull, so change file permissions
chmod( $this->defaults[ 'css_file_path' ], 0644 );
$is_file = true;
} // if CSS file successfully created
} // if no inline CSS
} // if CSS file exists
// if there is a CSS file
if ( $is_file ) {
// enqueue the CSS file
wp_enqueue_style(
$this->defaults[ 'plugin_slug' ] . '-public-style',
plugin_dir_url( __FILE__ ) . 'public.css',
array(),
$this->defaults[ 'plugin_version' ],
'all'
);
} else {
// print inline CSS
print "\n<!-- Recent Posts Widget With Thumbnails: inline CSS -->\n";
printf( "<style type='text/css'>\n%s</style>\n", $css_code );
} // if $is_file
}
/**
* Load the widget's CSS in the HEAD section of the backend
*
* @since 4.0
*/
public function enqueue_admin_style () {
// load CSS file on Widgets page only
$screen = get_current_screen();
if ( 'widgets' == $screen->id ) {
// enqueue the style
wp_enqueue_style(
$this->defaults[ 'plugin_slug' ] . '-admin-style',
plugin_dir_url( __FILE__ ) . 'admin.css',
array(),
$this->defaults[ 'plugin_version' ],
'all'
);
}
}
/**
* Returns the id of the first image in the content, else 0
*
* @access private
* @since 2.0
*
* @return integer the post id of the first content image
*/
private function get_first_content_image_id () {
// set variables
global $wpdb;
$post = get_post();
if ( $post and isset( $post->post_content ) ) {
// look for images in HTML code
preg_match_all( '/<img[^>]+>/i', $post->post_content, $all_img_tags );
if ( $all_img_tags ) {
foreach ( $all_img_tags[ 0 ] as $img_tag ) {
// find class attribute and catch its value
preg_match( '/<img.*?class\s*=\s*[\'"]([^\'"]+)[\'"][^>]*>/i', $img_tag, $img_class );
if ( $img_class ) {
// Look for the WP image id
preg_match( '/wp-image-([\d]+)/i', $img_class[ 1 ], $thumb_id );
// if first image id found: check whether is image
if ( $thumb_id ) {
$img_id = absint( $thumb_id[ 1 ] );
// if is image: return its id
if ( wp_attachment_is_image( $img_id ) ) {
return $img_id;
}
} // if(thumb_id)
} // if(img_class)
// else: try to catch image id by its url as stored in the database
// find src attribute and catch its value
preg_match( '/<img.*?src\s*=\s*[\'"]([^\'"]+)[\'"][^>]*>/i', $img_tag, $img_src );
if ( $img_src ) {
// delete optional query string in img src
$url = preg_replace( '/([^?]+).*/', '\1', $img_src[ 1 ] );
// delete image dimensions data in img file name, just take base name and extension
$url = preg_replace( '/(.+)-\d+x\d+\.(\w+)/', '\1.\2', $url );
// if path is protocol relative then set it absolute
if ( 0 === strpos( $url, '//' ) ) {
$url = $this->defaults[ 'site_protocol' ] . ':' . $url;
// if path is domain relative then set it absolute
} elseif ( 0 === strpos( $url, '/' ) ) {
$url = $this->defaults[ 'site_url' ] . $url;
}
// look up its id in the db
$thumb_id = $wpdb->get_var( $wpdb->prepare( "SELECT `ID` FROM $wpdb->posts WHERE `guid` = '%s'", $url ) );
// if id is available: return it
if ( $thumb_id ) {
return absint( $thumb_id );
} // if(thumb_id)
} // if(img_src)
} // foreach(img_tag)
} // if(all_img_tags)
} // if (post content)
// if nothing found: return 0
return 0;
}
/**
* Returns the thumbnail of first post's image or empty string on failure
*
* @access private
* @since 2.0
*
* @return bool success on finding an image
*/
private function the_first_post_image ( $attr ) {
// look for first image
$thumb_id = $this->get_first_content_image_id();
// if there is first image then show first image
if ( $thumb_id ) :
return wp_get_attachment_image( $thumb_id, $this->customs[ 'thumb_dimensions' ], $attr );
else :
return '';
endif; // thumb_id
}
/**
* Returns the assigned categories of a post in a string
*
* @access private
* @since 4.6
*
*/
private function get_the_categories ( $id ) {
$terms = get_the_terms( $id, 'category' );
if ( is_wp_error( $terms ) ) {
return __( 'Error on listing categories', 'recent-posts-widget-with-thumbnails' );
}
if ( empty( $terms ) ) {
$text = 'No categories';
return __( $text );
}
$categories = array();
if ( $this->customs[ 'set_cats_as_links' ] ) {
foreach ( $terms as $term ) {
// get link to category
$categories[] = sprintf(
'<a href="%s">%s</a>',
get_category_link( $term->term_id ),
esc_html( $term->name )
);
}
} else {
foreach ( $terms as $term ) {
// get sanitized category name
$categories[] = esc_html( $term->name );
}
}
/*foreach ( $terms as $term ) {
$categories[] = $term->name;
}*/
$string = '';
if ( $this->customs[ 'category_label' ] ) {
$string = $this->customs[ 'category_label' ] . ' ';
}
$string .= join( $this->defaults[ 'comma' ], $categories );
return apply_filters( 'rpwwt_categories', $string );
}
/**
* Returns the assigned author of a post in a string
*
* @access private
* @since 4.8
*
*/
private function get_the_author () {
$author = get_the_author();
if ( empty( $author ) ) {
return '';
} else {
$string = '';
if ( $this->customs[ 'author_label' ] ) {
$string = $this->customs[ 'author_label' ] . ' ';
}
return $string . $author;
//return sprintf( $this->defaults[ 'author_label' ], $author );
}
}
/**
* Generate the css code with stored settings
*
* @since 2.3
*/
private function generate_css_code ( $all_instances ) {
$set_default = true;
$ints = array();
$use_inline_css = false;
// generate CSS
$css_code = ".rpwwt-widget ul { list-style: outside none none; margin-left: 0; margin-right: 0; padding-left: 0; padding-right: 0; }\n";
$css_code .= ".rpwwt-widget ul li { overflow: hidden; margin: 0 0 1.5em; }\n";
$css_code .= ".rpwwt-widget ul li:last-child { margin: 0; }\n";
$css_code .= ".rpwwt-widget .screen-reader-text {border: 0; clip: rect(1px, 1px, 1px, 1px); -webkit-clip-path: inset(50%); clip-path: inset(50%); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute !important; width: 1px; word-wrap: normal !important; word-break: normal; }\n";
$css_code .= ".rpwwt-widget .screen-reader-text:focus {background-color: #f1f1f1; border-radius: 3px; box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6); clip: auto !important; -webkit-clip-path: none; clip-path: none; color: #21759b; display: block; font-size: 0.875rem; font-weight: 700; height: auto; right: 5px; line-height: normal; padding: 15px 23px 14px; text-decoration: none; top: 5px; width: auto; z-index: 100000; }\n";
if ( is_rtl() ) {
$css_code .= ".rpwwt-widget ul li img { display: inline; float: right; margin: .3em 0 .75em .75em; }\n";
} else {
$css_code .= ".rpwwt-widget ul li img { display: inline; float: left; margin: .3em .75em .75em 0; }\n";
}
foreach ( $all_instances as $number => $settings ) {
// set width and height
$ints[ 'thumb_width' ] = $this->defaults[ 'thumb_width' ];
$ints[ 'thumb_height' ] = $this->defaults[ 'thumb_height' ];
$thumb_dimensions = isset( $settings[ 'thumb_dimensions' ] ) ? $settings[ 'thumb_dimensions' ] : $this->defaults[ 'thumb_dimensions' ];
if ( 'custom' == $thumb_dimensions ) {
if ( isset( $settings[ 'thumb_width' ] ) ) {
$ints[ 'thumb_width' ] = absint( $settings[ 'thumb_width' ] );
}
if ( isset( $settings[ 'thumb_height' ] ) ) {
$ints[ 'thumb_height' ] = absint( $settings[ 'thumb_height' ] );
}
} else {
list( $ints[ 'thumb_width' ], $ints[ 'thumb_height' ] ) = $this->get_image_dimensions( $thumb_dimensions );
} // $settings[ 'thumb_dimensions' ]
// get aspect ratio option
$bools[ 'keep_aspect_ratio' ] = false;
if ( isset( $settings[ 'keep_aspect_ratio' ] ) ) {
$bools[ 'keep_aspect_ratio' ] = (bool) $settings[ 'keep_aspect_ratio' ];
// set CSS code
if ( $bools[ 'keep_aspect_ratio' ] ) {
$css_code .= sprintf( '#rpwwt-%s-%d img { max-width: %dpx; width: 100%%; height: auto; }', $this->defaults[ 'plugin_slug' ], $number, $ints[ 'thumb_width' ] );
$css_code .= "\n";
} else {
$css_code .= sprintf( '#rpwwt-%s-%d img { width: %dpx; height: %dpx; }', $this->defaults[ 'plugin_slug' ], $number, $ints[ 'thumb_width' ], $ints[ 'thumb_height' ] );
$css_code .= "\n";
}
} else {
$css_code .= sprintf( '#rpwwt-%s-%d img { width: %dpx; height: %dpx; }', $this->defaults[ 'plugin_slug' ], $number, $ints[ 'thumb_width' ], $ints[ 'thumb_height' ] );
$css_code .= "\n";
}
// override default code
$set_default = false;
// inline CSS if at least 1 widget was set for that
if ( isset( $settings[ 'use_inline_css' ] ) ) {
$bools[ 'use_inline_css' ] = (bool) $settings[ 'use_inline_css' ];
if ( $bools[ 'use_inline_css' ] ) {
$use_inline_css = true;
}
}
} // foreach ( $all_instances as $number => $settings )
// set at least this statement if no settings are stored
if ( $set_default ) {
$css_code .= sprintf( '.rpwwt-widget ul li img { width: %dpx; height: %dpx; }', $this->defaults[ 'thumb_width' ], $this->defaults[ 'thumb_height' ] );
$css_code .= "\n";
}
return array( $css_code, $use_inline_css );
}
/**
* Returns the shortened excerpt, must use in a loop.
*
* @since 3.0
*/
private function get_the_trimmed_excerpt () {
$post = get_post();
if ( empty( $post ) ) {
return '';
}
$excerpt = '';
if ( post_password_required( $post ) ) {
$excerpt = 'There is no excerpt because this is a protected post.';
return esc_html__( $excerpt );
}
// get excerpt from text field if desired
if ( ! $this->customs[ 'ignore_excerpt' ] ) {
$excerpt = apply_filters( 'rpwwt_the_excerpt', $post->post_excerpt, $post );
}
// text processings if no manual excerpt is available
if ( empty( $excerpt ) and ! $this->customs[ 'ignore_post_content_excerpt' ] ) {
// get excerpt from post content
$excerpt = strip_shortcodes( get_the_content( '' ) );
$excerpt = apply_filters( 'the_excerpt', $excerpt );
$excerpt = str_replace( ']]>', ']]&gt;', $excerpt );
$excerpt = wp_trim_words( $excerpt, $this->customs[ 'excerpt_length' ], $this->customs[ 'excerpt_more' ] );
// if excerpt is longer than desired
if ( mb_strlen( $excerpt ) > $this->customs[ 'excerpt_length' ] ) {
// get excerpt in desired length
$sub_excerpt = mb_substr( $excerpt, 0, $this->customs[ 'excerpt_length' ] );
// get array of shortened excerpt words
$excerpt_words = explode( ' ', $sub_excerpt );
// get the length of the last word in the shortened excerpt
$excerpt_cut = - ( mb_strlen( $excerpt_words[ count( $excerpt_words ) - 1 ] ) );
// if there is no empty string
if ( $excerpt_cut < 0 ) {
// get the shorter excerpt until the last word
$excerpt = mb_substr( $sub_excerpt, 0, $excerpt_cut );
} else {
// get the shortened excerpt
$excerpt = $sub_excerpt;
} // if ( $excerpt_cut < 0 )
} // if ( mb_strlen( $excerpt ) > $this->customs[ 'excerpt_length' ] )
} // if ( empty( $excerpt ) )
if ( $excerpt ) {
// append 'more' text, set 'more' signs as link if desired
if ( $this->customs[ 'set_more_as_link' ] ) {
$excerpt .= sprintf( '<a href="%s"%s class="rpwwt-post-excerpt-more">%s</a>', get_the_permalink( $post ), $this->customs[ 'link_target' ], $this->customs[ 'excerpt_more' ] );
} else {
$excerpt .= '<span class="rpwwt-post-excerpt-more">' . $this->customs[ 'excerpt_more' ] . '</span>';
}
}
// return text
return $excerpt;
}
/**
* Returns the shortened post title, must use in a loop.
*
* @since 4.5
*/
private function get_the_trimmed_post_title () {
// get current post's post_title
$post_title = get_the_title();
// if post_title is longer than desired
if ( mb_strlen( $post_title ) > $this->customs[ 'post_title_length' ] ) {
// get post_title in desired length
$post_title = mb_substr( $post_title, 0, $this->customs[ 'post_title_length' ] );
// append ellipses
$post_title .= $this->defaults[ 'ellipses' ];
}
// return text
return $post_title;
}
/**
* Returns width and height of a image size name, else default sizes
*
* @since 4.0
*/
private function get_image_dimensions ( $size = 'thumbnail' ) {
$width = 0;
$height = 0;
// check if selected size is in registered images sizes
if ( in_array( $size, get_intermediate_image_sizes() ) ) {
// if in WordPress standard image sizes
if ( in_array( $size, array( 'thumbnail', 'medium', 'large' ) ) ) {
$width = get_option( $size . '_size_w' );
$height = get_option( $size . '_size_h' );
} else {
// custom image sizes, formerly added via add_image_size()
global $_wp_additional_image_sizes;
$width = $_wp_additional_image_sizes[ $size ][ 'width' ];
$height = $_wp_additional_image_sizes[ $size ][ 'height' ];
}
}
// check if vars have true values, else use default size
if ( ! $width ) $width = $this->defaults[ 'thumb_width' ];
if ( ! $height ) $height = $this->defaults[ 'thumb_height' ];
// return sizes
return array( $width, $height );
}
/**
* Shows sticky posts on top of categories list
*
* @since 6.2.1
*/
public function get_stickies_on_top( $posts ) {
// get sticky post IDs
$sticky_posts = get_option( 'sticky_posts' );
// initialize variables for the correct number of posts in the result list
$num_posts = count( $posts );
$sticky_offset = 0;
// loop over posts and relocate stickies to the front
for( $i = 0; $i < $num_posts; $i++ ) {
// if sticky post
if ( in_array( $posts[ $i ]->ID, $sticky_posts ) ) {
$sticky_post = $posts[ $i ];
// remove sticky post from current position
array_splice( $posts, $i, 1 );
// move to front, after other stickies
array_splice( $posts, $sticky_offset, 0, array( $sticky_post ) );
// increment the sticky offset. the next sticky will be placed at this offset.
$sticky_offset++;
// remove post from sticky posts array
//$offset = array_search( $sticky_post->ID, $sticky_posts );
//unset( $sticky_posts[ $offset ] );
} // if ( in_array( $posts[ $i ]->ID, $sticky_posts ) )
} // for()
// return new list
return $posts;
}
/**
* Returns the ARIA label for the NAV element
*
* @since 6.7.1
*/
private function get_aria_nav_label( $title ) {
// the title may be filtered: Strip out HTML
$title = trim( strip_tags( $title ) );
// and make sure the aria-label is never empty
return $title ? $title : $this->defaults[ 'nav_label' ];
}
}
/**
* Register widget on init
*
* @since 1.0
*/
function register_recent_posts_widget_with_thumbnails () {
register_widget( 'Recent_Posts_Widget_With_Thumbnails' );
}
add_action( 'widgets_init', 'register_recent_posts_widget_with_thumbnails', 1 );