File: /mnt/data/dreamssalon-wp/wp-content/plugins/dreamsalon-widgets/widget-functions.php
<?php
/**
* Widget Functions and Overrides
* Contains custom widget modifications and overrides
*/
// Image border radius filter
function add_border_radius_to_image($img_html) {
// Check if image already has style attribute
if (preg_match('/style="([^"]*)"/', $img_html, $matches)) {
// Append border-radius to existing style
$existing_style = $matches[1];
$new_style = $existing_style . ' border-radius: 6px;';
$img_html = str_replace('style="' . $existing_style . '"', 'style="' . $new_style . '"', $img_html);
} else {
// Add style attribute with border-radius
$img_html = preg_replace('/<img/', '<img style="border-radius: 6px;"', $img_html);
}
return $img_html;
}
add_filter('the_content', 'format_images_into_grid');
// Complete override for categories widget
function override_categories_widget_output($params) {
if (isset($params[0]['widget_name']) && $params[0]['widget_name'] === 'Categories') {
// Get widget instance
$widget_id = $params[0]['widget_id'];
$all_widgets = get_option('widget_categories');
$widget_number = str_replace('categories-', '', $widget_id);
if (isset($all_widgets[$widget_number])) {
$instance = $all_widgets[$widget_number];
// Start capturing output
ob_start();
// Build the new widget structure
?>
<div class="card sidebar-item widget-categories">
<div class="card-header">
<h4 class="sidebar-widget-title"><?php echo $instance['title'] ? esc_html($instance['title']) : 'Categories'; ?></h4>
</div>
<div class="card-body">
<ul>
<?php
// Get categories with proper parameters
$categories_args = array(
'show_count' => !empty($instance['count']) ? 1 : 0,
'hierarchical' => !empty($instance['hierarchical']) ? 1 : 0,
'title_li' => '',
'echo' => 0
);
$categories = wp_list_categories($categories_args);
// Add chevron icons and aria-labels
$categories = preg_replace_callback(
'/<a href="([^"]+)">([^<]+)<\/a>/',
function($matches) {
return '<a href="' . $matches[1] . '" aria-label="Category link"><i class="fa-solid fa-chevron-right"></i>' . $matches[2] . '</a>';
},
$categories
);
echo $categories;
?>
</ul>
</div>
</div>
<?php
$new_output = ob_get_clean();
// Replace all widget parameters to output only our custom structure
$params[0]['before_widget'] = '';
$params[0]['after_widget'] = '';
$params[0]['before_title'] = '<!--';
$params[0]['after_title'] = '-->';
// Store our custom output
add_filter('widget_categories_args', function() use ($new_output) {
static $output_done = false;
if (!$output_done) {
$output_done = true;
echo $new_output;
}
return array('echo' => 0); // Prevent default output
});
}
}
return $params;
}
add_filter('dynamic_sidebar_params', 'override_categories_widget_output', 999);
// Search widget override
function override_search_widget_output($params) {
if (isset($params[0]['widget_name']) && $params[0]['widget_name'] === 'Search') {
// Get widget instance
$widget_id = $params[0]['widget_id'];
$all_widgets = get_option('widget_search');
$widget_number = str_replace('search-', '', $widget_id);
if (isset($all_widgets[$widget_number])) {
$instance = $all_widgets[$widget_number];
// Start capturing output
ob_start();
// Build the new widget structure
?>
<div class="card sidebar-item widget-search">
<div class="card-header">
<h4 class="sidebar-widget-title mb-0"><?php echo $instance['title'] ? esc_html($instance['title']) : 'Search'; ?></h4>
</div>
<div class="card-body">
<form role="search" method="get" class="sidebar-search" action="<?php echo esc_url( home_url( '/' ) ); ?>">
<div class="input-group">
<input
type="search"
class="form-control"
value="<?php echo get_search_query(); ?>"
name="s"
placeholder="<?php echo esc_attr__( 'Search...', 'dreamsalon_elementor' ); ?>"
aria-label="<?php echo esc_attr__( 'Search for:', 'dreamsalon_elementor' ); ?>"
>
<button type="submit" class="sidebar-search-btn btn btn-primary">
<i class="fa-solid fa-magnifying-glass"></i>
</button>
</div>
</form>
</div>
</div>
<?php
$new_output = ob_get_clean();
// Replace all widget parameters to output only our custom structure
$params[0]['before_widget'] = '';
$params[0]['after_widget'] = '';
$params[0]['before_title'] = '<!--';
$params[0]['after_title'] = '-->';
// Store our custom output
add_filter('get_search_form', function() use ($new_output) {
static $output_done = false;
if (!$output_done) {
$output_done = true;
echo $new_output;
}
return ''; // Prevent default output
});
}
}
return $params;
}
add_filter('dynamic_sidebar_params', 'override_search_widget_output', 999);
// Custom Share Widget
class WP_Widget_Share extends WP_Widget {
/**
* Sets up a new Share widget instance.
*
* @since 1.0.0
*/
public function __construct() {
$widget_ops = array(
'description' => __( 'Social media share buttons with customizable platforms.', 'dreamsalon_elementor' ),
'customize_selective_refresh' => true,
'show_instance_in_rest' => true,
);
parent::__construct( 'share_widget', __( 'Share Buttons', 'dreamsalon_elementor' ), $widget_ops );
}
/**
* Outputs the content for the current Share widget instance.
*
* @since 1.0.0
*
* @param array $args Display arguments including 'before_title', 'after_title',
* 'before_widget', and 'after_widget'.
* @param array $instance Settings for the current Share widget instance.
*/
public function widget( $args, $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Share', 'dreamsalon_elementor' );
// Get social platforms from instance
$platforms = array();
$available_platforms = $this->get_available_platforms();
foreach ( $available_platforms as $key => $platform ) {
if ( ! empty( $instance[$key] ) ) {
$platforms[$key] = $platform;
}
}
// If no platforms are selected, use default set
if ( empty( $platforms ) ) {
$platforms = array_slice( $available_platforms, 0, 6 ); // Default to first 6 platforms
}
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
// Get current page URL and title for sharing
$current_url = is_singular() ? get_permalink() : home_url( add_query_arg( array() ) );
$current_title = is_singular() ? get_the_title() : get_bloginfo( 'name' );
// Custom HTML structure
echo '<div class="card sidebar-item mb-0">';
echo '<div class="card-header">';
echo '<h4 class="sidebar-widget-title">' . esc_html( $title ) . '</h4>';
echo '</div>';
echo '<div class="card-body">';
echo '<div class="d-flex align-items-center flex-wrap gap-2">';
foreach ( $platforms as $key => $platform ) {
$share_url = $this->get_share_url( $key, $current_url, $current_title );
echo '<a href="' . esc_url( $share_url ) . '" class="btn btn-dark rounded-circle d-inline-flex align-items-center justify-content-center p-2" aria-label="' . esc_attr( $platform['name'] ) . '" target="_blank" rel="noopener noreferrer">';
echo '<i class="' . esc_attr( $platform['icon'] ) . ' fs-20" aria-hidden="true"></i>';
echo '</a>';
}
echo '</div>';
echo '</div>'; // .card-body
echo '</div>'; // .card
}
/**
* Handles updating settings for the current Share widget instance.
*
* @since 1.0.0
*
* @param array $new_instance New settings for this instance as input by the user via
* WP_Widget::form().
* @param array $old_instance Old settings for this instance.
* @return array Settings to save or bool false to cancel saving.
*/
public function update( $new_instance, $old_instance ) {
$instance = array();
$instance['title'] = ! empty( $new_instance['title'] ) ? sanitize_text_field( $new_instance['title'] ) : '';
// Update platform settings
$available_platforms = $this->get_available_platforms();
foreach ( $available_platforms as $key => $platform ) {
$instance[$key] = ! empty( $new_instance[$key] ) ? 1 : 0;
}
return $instance;
}
/**
* Outputs the Share widget settings form.
*
* @since 1.0.0
*
* @param array $instance Current settings.
*/
public function form( $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Share', 'dreamsalon_elementor' );
$available_platforms = $this->get_available_platforms();
?>
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'dreamsalon_elementor' ); ?></label>
<input type="text" class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo esc_attr( $title ); ?>" />
</p>
<p><strong><?php _e( 'Select Social Platforms:', 'dreamsalon_elementor' ); ?></strong></p>
<?php foreach ( $available_platforms as $key => $platform ) :
$checked = ! empty( $instance[$key] ) ? 'checked' : '';
?>
<p>
<input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id( $key ); ?>" name="<?php echo $this->get_field_name( $key ); ?>" <?php echo $checked; ?> />
<label for="<?php echo $this->get_field_id( $key ); ?>">
<?php echo esc_html( $platform['name'] ); ?>
</label>
</p>
<?php endforeach; ?>
<?php
}
/**
* Get available social media platforms
*
* @since 1.0.0
*
* @return array Array of available platforms with their icons and names
*/
private function get_available_platforms() {
return array(
'facebook' => array(
'name' => 'Facebook',
'icon' => 'ti ti-brand-facebook'
),
'instagram' => array(
'name' => 'Instagram',
'icon' => 'ti ti-brand-instagram'
),
'behance' => array(
'name' => 'Behance',
'icon' => 'ti ti-brand-behance'
),
'twitter' => array(
'name' => 'Twitter',
'icon' => 'ti ti-brand-twitter'
),
'pinterest' => array(
'name' => 'Pinterest',
'icon' => 'ti ti-brand-pinterest'
),
'linkedin' => array(
'name' => 'LinkedIn',
'icon' => 'ti ti-brand-linkedin'
),
'whatsapp' => array(
'name' => 'WhatsApp',
'icon' => 'ti ti-brand-whatsapp'
),
'telegram' => array(
'name' => 'Telegram',
'icon' => 'ti ti-brand-telegram'
),
'reddit' => array(
'name' => 'Reddit',
'icon' => 'ti ti-brand-reddit'
),
);
}
/**
* Get share URL for specific platform
*
* @since 1.0.0
*
* @param string $platform Platform key
* @param string $url URL to share
* @param string $title Title to share
* @return string Share URL
*/
private function get_share_url( $platform, $url, $title ) {
$encoded_url = urlencode( $url );
$encoded_title = urlencode( $title );
switch ( $platform ) {
case 'facebook':
return "https://www.facebook.com/sharer/sharer.php?u={$encoded_url}";
case 'twitter':
return "https://twitter.com/intent/tweet?url={$encoded_url}&text={$encoded_title}";
case 'linkedin':
return "https://www.linkedin.com/sharing/share-offsite/?url={$encoded_url}";
case 'pinterest':
return "https://pinterest.com/pin/create/button/?url={$encoded_url}&description={$encoded_title}";
case 'whatsapp':
return "https://api.whatsapp.com/send?text={$encoded_title}%20{$encoded_url}";
case 'telegram':
return "https://t.me/share/url?url={$encoded_url}&text={$encoded_title}";
case 'reddit':
return "https://reddit.com/submit?url={$encoded_url}&title={$encoded_title}";
case 'behance':
return "#"; // Behance doesn't have a direct share URL
case 'instagram':
return "#"; // Instagram doesn't have a direct share URL
default:
return "#";
}
}
}
// Register the Share widget
function register_share_widget() {
register_widget( 'WP_Widget_Share' );
}
add_action( 'widgets_init', 'register_share_widget' );
// Custom Tag Cloud Widget
function custom_tag_cloud_widget() {
unregister_widget('WP_Widget_Tag_Cloud');
class Custom_WP_Widget_Tag_Cloud extends WP_Widget_Tag_Cloud {
public function widget($args, $instance) {
$current_taxonomy = $this->_get_current_taxonomy($instance);
if (!empty($instance['title'])) {
$title = $instance['title'];
} else {
if ('post_tag' === $current_taxonomy) {
$title = __('Tags');
} else {
$tax = get_taxonomy($current_taxonomy);
$title = $tax->labels->name;
}
}
$show_count = !empty($instance['count']);
$tags = get_terms(array(
'taxonomy' => $current_taxonomy,
'orderby' => 'count',
'order' => 'DESC',
'number' => 45,
'hide_empty' => true,
));
if (empty($tags) || is_wp_error($tags)) {
return;
}
echo '<div class="card sidebar-item">';
echo '<div class="card-header">';
echo '<h4 class="sidebar-widget-title">' . esc_html($title) . '</h4>';
echo '</div>';
echo '<div class="card-body">';
echo '<div class="post-tag d-flex align-items-center gap-1 flex-wrap">';
echo '<ul class="list-wrap p-0 mb-0 d-flex align-items-center gap-2 flex-wrap">';
foreach ($tags as $tag) {
$tag_link = get_term_link($tag);
$count_display = $show_count ? ' <span class="tag-count">(' . $tag->count . ')</span>' : '';
echo '<li>';
echo '<a href="' . esc_url($tag_link) . '" class="badge bg-light text-dark">';
echo esc_html($tag->name) . $count_display;
echo '</a>';
echo '</li>';
}
echo '</ul>';
echo '</div>';
echo '</div>';
echo '</div>';
}
}
register_widget('Custom_WP_Widget_Tag_Cloud');
}
add_action('widgets_init', 'custom_tag_cloud_widget', 11);
// Custom Recent Posts Widget
function custom_recent_posts_widget() {
unregister_widget('WP_Widget_Recent_Posts');
class Custom_WP_Widget_Recent_Posts extends WP_Widget_Recent_Posts {
public function widget($args, $instance) {
if (!isset($args['widget_id'])) {
$args['widget_id'] = $this->id;
}
$default_title = __('Recent Posts');
$title = (!empty($instance['title'])) ? $instance['title'] : $default_title;
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters('widget_title', $title, $instance, $this->id_base);
$number = (!empty($instance['number'])) ? absint($instance['number']) : 5;
if (!$number) {
$number = 5;
}
$show_date = isset($instance['show_date']) ? $instance['show_date'] : false;
$r = new WP_Query(
apply_filters(
'widget_posts_args',
array(
'posts_per_page' => $number,
'no_found_rows' => true,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
),
$instance
)
);
if (!$r->have_posts()) {
return;
}
// Custom HTML structure
echo '<div class="card sidebar-item">';
echo '<div class="card-header">';
echo '<h4 class="sidebar-widget-title">' . $title . '</h4>';
echo '</div>';
echo '<div class="card-body">';
echo '<ul class="recent-posts list-unstyled mb-0">';
foreach ($r->posts as $recent_post) {
$post_title = get_the_title($recent_post->ID);
$title = (!empty($post_title)) ? $post_title : __('(no title)');
$aria_label = sprintf(__('Post details page link: %s'), $title);
$post_date = get_the_date('d M Y', $recent_post->ID);
$post_link = get_permalink($recent_post->ID);
$post_thumb = get_the_post_thumbnail_url($recent_post->ID, 'thumbnail');
$default_thumb = get_template_directory_uri() . '/assets/img/blog/blog-sidebar-img-01.jpg';
echo '<li class="mb-3 pb-3 border-bottom">';
echo '<article class="post-style d-flex align-items-start gap-3">';
// Post thumbnail
echo '<a href="' . esc_url($post_link) . '" aria-label="' . esc_attr($aria_label) . '" class="post-thumbnail overflow-hidden flex-shrink-0">';
echo '<img src="' . esc_url($post_thumb ? $post_thumb : $default_thumb) . '" alt="' . esc_attr($title) . '" class="img-fluid rounded" width="80" height="80">';
echo '</a>';
// Post info
echo '<div class="post-info flex-grow-1">';
echo '<h3 class="post-title mb-2">';
echo '<a href="' . esc_url($post_link) . '" aria-label="' . esc_attr($aria_label) . '" class="text-dark text-decoration-none fw-semibold fs-6 lh-sm">';
echo esc_html($title);
echo '</a>';
echo '</h3>';
if ($show_date) {
echo '<div class="post-meta text-muted small">' . esc_html($post_date) . '</div>';
}
echo '</div>'; // .post-info
echo '</article>'; // .post-style
echo '</li>';
}
echo '</ul>'; // .recent-posts
echo '</div>'; // .card-body
echo '</div>'; // .card
}
}
register_widget('Custom_WP_Widget_Recent_Posts');
}
add_action('widgets_init', 'custom_recent_posts_widget', 11);
// Custom Archives Widget
function custom_archives_widget() {
unregister_widget('WP_Widget_Archives');
class Custom_WP_Widget_Archives extends WP_Widget_Archives {
public function widget($args, $instance) {
$default_title = __('Archives');
$title = !empty($instance['title']) ? $instance['title'] : $default_title;
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters('widget_title', $title, $instance, $this->id_base);
$count = !empty($instance['count']) ? '1' : '0';
$dropdown = !empty($instance['dropdown']) ? '1' : '0';
// Custom HTML structure
echo '<div class="card sidebar-item widget-archive">';
echo '<div class="card-header">';
echo '<h4 class="sidebar-widget-title">' . $title . '</h4>';
echo '</div>';
echo '<div class="card-body">';
if ($dropdown) {
$dropdown_id = "{$this->id_base}-dropdown-{$this->number}";
?>
<label class="screen-reader-text" for="<?php echo esc_attr($dropdown_id); ?>"><?php echo $title; ?></label>
<select id="<?php echo esc_attr($dropdown_id); ?>" name="archive-dropdown" class="form-select">
<?php
$dropdown_args = apply_filters(
'widget_archives_dropdown_args',
array(
'type' => 'monthly',
'format' => 'option',
'show_post_count' => $count,
),
$instance
);
switch ($dropdown_args['type']) {
case 'yearly':
$label = __('Select Year');
break;
case 'monthly':
$label = __('Select Month');
break;
case 'daily':
$label = __('Select Day');
break;
case 'weekly':
$label = __('Select Week');
break;
default:
$label = __('Select Post');
break;
}
?>
<option value=""><?php echo esc_html($label); ?></option>
<?php wp_get_archives($dropdown_args); ?>
</select>
<?php ob_start(); ?>
<script>
(function() {
var dropdown = document.getElementById("<?php echo esc_js($dropdown_id); ?>");
function onSelectChange() {
if (dropdown.options[dropdown.selectedIndex].value !== '') {
document.location.href = this.options[this.selectedIndex].value;
}
}
dropdown.onchange = onSelectChange;
})();
</script>
<?php
wp_print_inline_script_tag(wp_remove_surrounding_empty_script_tags(ob_get_clean()));
} else {
?>
<ul class="list-unstyled mb-0">
<?php
// Get archives with custom format
$archive_args = apply_filters(
'widget_archives_args',
array(
'type' => 'monthly',
'show_post_count' => $count,
'format' => 'custom',
'before' => '',
'after' => '',
),
$instance
);
// Get the archives as an array for better control
$archives = wp_get_archives(array_merge($archive_args, array('echo' => false)));
if ($archives) {
// Split the archives by line and wrap each in our custom HTML
$archive_items = explode("\n", trim($archives));
foreach ($archive_items as $item) {
if (!empty($item)) {
// Extract the link and text
preg_match('/<a\s+(?:[^>]*?\s+)?href=(["\'])(.*?)\1[^>]*>(.*?)<\/a>/', $item, $matches);
if (isset($matches[2]) && isset($matches[3])) {
$url = $matches[2];
$text = $matches[3];
// Format the date to match your desired format "8 Oct 2025" (no leading zero, no comma)
$formatted_text = $this->format_archive_date($text);
echo '<li>';
echo '<a href="' . esc_url($url) . '" aria-label="Archive link">';
echo '<i class="fa-solid fa-chevron-right"></i>' . esc_html($formatted_text);
// Show post count if enabled
if ($count) {
preg_match('/\((\d+)\)/', $item, $count_matches);
if (isset($count_matches[1])) {
echo ' <span class="post-count">(' . $count_matches[1] . ')</span>';
}
}
echo '</a>';
echo '</li>';
}
}
}
} else {
echo '<li><span class="text-muted">' . __('No archives found.') . '</span></li>';
}
?>
</ul>
<?php
}
// Close custom HTML structure
echo '</div>';
echo '</div>';
}
/**
* Format archive date to match desired format "8 Oct 2025" (no leading zero, no comma)
*
* @param string $date_string The original date string from WordPress
* @return string Formatted date string
*/
private function format_archive_date($date_string) {
// Remove post count if present
$date_string = preg_replace('/\s*\(\d+\)$/', '', $date_string);
// Try to parse the date string - common WordPress archive formats
$timestamp = false;
// Try different date formats that WordPress might use
$formats = [
'F Y', // "September 2025"
'Y F', // "2025 September"
'M Y', // "Sep 2025"
'Y M', // "2025 Sep"
'F j, Y', // "September 8, 2025"
'j F, Y', // "8 September, 2025"
];
foreach ($formats as $format) {
$timestamp = strtotime($date_string);
if ($timestamp !== false) {
break;
}
}
if ($timestamp) {
// Format as "j M Y" (e.g., "8 Oct 2025") - no leading zero, no comma
return date('F Y', $timestamp);
}
// If parsing fails, try to extract and reformat common patterns
if (preg_match('/(\w+)\s+(\d+),\s*(\d+)/', $date_string, $matches)) {
// Format like "September 8, 2025"
$timestamp = strtotime($matches[1] . ' ' . $matches[2] . ', ' . $matches[3]);
if ($timestamp) {
return date('F Y', $timestamp);
}
} elseif (preg_match('/(\w+)\s+(\d+)/', $date_string, $matches)) {
// Format like "September 2025" - assume first day of month
$timestamp = strtotime('1 ' . $matches[1] . ' ' . $matches[2]);
if ($timestamp) {
return date('F Y', $timestamp);
}
}
// If all parsing fails, return cleaned original string
return trim($date_string);
}
}
register_widget('Custom_WP_Widget_Archives');
}
add_action('widgets_init', 'custom_archives_widget', 11);
?>