Dropdown image load fix
August 7, 2025 · AI Conversations
{
global $product;
if (!$product || !is_a($product, 'WC_Product')) {
return;
}
$similar_products = prof_get_similar_products_from_subcategory($product->get_id());
if (empty($similar_products)) {
return; // No similar products found
}
//$max_display = 4; // Limit for displayed products
$product_count = count($similar_products);
// Function to fetch Linguise translated URLs
function prf_get_linguise_translated_url($source_link) {
global $wpdb;
$source_path = rtrim(str_replace(wp_parse_url(site_url(), PHP_URL_PATH), '', parse_url($source_link, PHP_URL_PATH)), '/');
return $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}linguise_urls WHERE source = %s",
$source_path
));
}
// Generate product title with fallback
function prf_get_product_title($product_id) {
$title = get_post_meta($product_id, '_alternative_name', true);
if (empty($title)) {
$product_obj = wc_get_product($product_id);
$title = $product_obj ? $product_obj->get_name() : '';
}
return esc_html($title);
}
// Generate language attributes for a product link
function prf_generate_language_attrs($product_link) {
$attrs = '';
$translated_urls = prf_get_linguise_translated_url($product_link);
if (!empty($translated_urls)) {
foreach ($translated_urls as $url) {
$tr_url = site_url() . $url->translation;
$attrs .= ' data-lang-' . esc_attr($url->language) . '="' . esc_url($tr_url) . '"';
}
}
return $attrs;
}
// Start building HTML
$section_html = '';
if ($product_count > 4) {
$extra_products = $similar_products;
$first_extra_product = $extra_products[0];
$first_product_obj = wc_get_product($first_extra_product->ID);
$first_product_title = get_post_meta($first_extra_product->ID, '_alternative_name', true);
// If _alternative_name meta field is empty, fallback to the product name
if (empty($first_product_title)) {
$first_product_title = $first_product_obj->get_name();
}
// Dropdown toggle with first product's title
$section_html .= '';
$section_html .= '';
$section_html .= '' . esc_html($first_product_title) . '';
$section_html .= '';
$section_html .= '';
$section_html .= '';
foreach ($extra_products as $extra_product) {
$extra_product_obj = wc_get_product($extra_product->ID);
$product_link = get_permalink($extra_product->ID);
$product_title = $extra_product_obj->get_name();
$product_image = wp_get_attachment_image_src(get_post_thumbnail_id($extra_product->ID), 'thumbnail')[0];
$lang_attrs_extra = '';
$translated_urls_extra = prf_get_linguise_translated_url( $product_link );
if( $translated_urls_extra ) {
foreach( $translated_urls_extra as $url ) {
$tr_url = site_url() . $url->translation;
$lang_attrs_extra .= ' data-lang-'.$url->language.'="'.$tr_url.'"';
}
}
$product_title = get_post_meta($extra_product->ID, '_alternative_name', true);
// If _alternative_name meta field is empty, fallback to the product name
if (empty($product_title)) {
$product_title = $extra_product_obj->get_name();
}
$section_html .= '';
// $section_html .= '';
$section_html .= '';
$section_html .= '' . esc_html($product_title) . '';
// $section_html .= '';
$section_html .= '';
}
$section_html .= '';
$section_html .= '';
}else{
$section_html .= '';
// Display the first 4 products
$displayed_products = $similar_products;
foreach ($displayed_products as $similar_product) {
$similar_product_obj = wc_get_product($similar_product->ID);
$product_link = get_permalink($similar_product->ID);
$lang_attrs = '';
$translated_urls = prf_get_linguise_translated_url( $product_link );
if( $translated_urls ) {
foreach( $translated_urls as $url ) {
$tr_url = site_url() . $url->translation;
$lang_attrs .= ' data-lang-'.$url->language.'="'.$tr_url.'"';
}
}
$product_title = get_post_meta($similar_product->ID, '_alternative_name', true);
// If _alternative_name meta field is empty, fallback to the product name
if (empty($product_title)) {
$product_title = $similar_product_obj->get_name();
}
$product_image = wp_get_attachment_image_src(get_post_thumbnail_id($similar_product->ID), 'thumbnail')[0];
$item_class = 'similar-product-item';
$item_class .= $product->get_id() == $similar_product->ID ? ' similar-product-current-item' : '';
$section_html .= '';
// $section_html .= '';
$section_html .= '';
$section_html .= '' . esc_html($product_title) . '';
// $section_html .= '';
$section_html .= '';
}
$section_html .= '';
}
// Add custom dropdown for extra products
$section_html .= ''; ?>
<style>
.prf-spd-arrow {
border: solid #1ebcbe;
border-width: 0 3px 3px 0;
display: inline-block;
padding: 3px;
}
.prf-spd-arrow.right {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.prf-spd-arrow.left {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
}
.prf-spd-arrow.up {
transform: rotate(-135deg);
-webkit-transform: rotate(-135deg);
}
.prf-spd-arrow.down {
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
}
.similar-products-container {
margin: 20px 0;
}
.similar-products-list {
list-style: none;
display: flex;
gap: 15px;
margin: 0;
padding: 0;
}
.similar-product-item {
text-align: center;
}
.similar-product-item img {
width: 80px;
height: auto;
margin-bottom: 5px;
}
/* Dropdown container */
.similar-products-dropdown {
position: relative;
margin-top: 10px;
margin-bottom: 20px;
}
.similar-products-dropdown .dropdown-toggle {
color: #fff;
padding: 10px 15px;
cursor: pointer;
text-align: center;
border-radius: 4px;
}
.similar-products-dropdown .dropdown-content {
display: none;
position: absolute;
background-color: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
width: 100%;
max-height: 200px;
overflow-y: auto;
z-index: 10;
padding: 0;
margin: 0;
list-style: none;
border-radius: 4px;
border: 1px solid #ddd;
}
.similar-products-dropdown .dropdown-item:last-child {
border-bottom: none!important;
}
.similar-products-dropdown .dropdown-content.show {
display: block;
}
.similar-products-dropdown .dropdown-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
border-bottom: 1px solid #eee;
}
.similar-products-dropdown .dropdown-item a {
display: flex;
align-items: center;
text-decoration: none;
color: #333;
width: 100%;
gap: 12px;
}
.similar-products-dropdown li.dropdown-item {
margin-left: 0px !important;
cursor: pointer;
}
.similar-products-dropdown .dropdown-item-image {
width: 50px;
height: auto;
border-radius: 4px;
}
.similar-products-dropdown .dropdown-item-title {
font-size: 14px;
line-height: 1.5;
}
.similar-products-dropdown .dropdown-item:hover {
background-color: #f9f9f9;
}
.similar-products-dropdown .dropdown-toggle {
display: flex;
justify-content: space-between;
align-items: center;
color: black;
padding: 10px 15px;
cursor: pointer;
border-radius: 4px;
font-size: 14px;
border: 1px solid #ddd;
}
.similar-products-dropdown .dropdown-arrow {
transition: transform 0.3s ease;
font-size: 12px;
color: #1ebcbe;
}
.similar-products-dropdown .dropdown-content.show + .dropdown-toggle .dropdown-arrow {
transform: rotate(180deg);
}
@media (max-width: 767px) {
.similar-products-list {
gap: 8px;
}
.similar-product-item {
width: 87px;
}
.similar-product-item img {
width: 81px;
height: 73px;
}
}
@media (max-width: 1050px) and (min-width: 850px) {
.similar-products-list {
gap: 0px;
}
.similar-product-item {
width: 97px;
}
}
/* Style for similiar product */
.prof-similar-prds-heading {
text-transform: uppercase;
margin-bottom: 15px;
}
.similar-products-list {
list-style-type: none;
display: flex;
gap: 10px;
padding: 0;
}
.similar-product-item {
width: 116px;
text-align: center;
cursor: pointer;
margin-left: 0px !important;
padding: 10px;
}
.similar-product-item img {
max-width: 100%;
object-fit: cover;
border-radius: 8px;
opacity: 0.9;
/* Make the image look dull */
transition: opacity 0.3s ease;
/* Smooth transition for hover effect */
}
.similar-product-item:hover img {
opacity: 1;
/* Restore image to full visibility on hover */
}
.similar-product-item .product-title {
font-size: 13px;
margin-bottom: 5px;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
li.similar-product-item:hover {
background-color: #f9f9f9;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
color: black;
}
.similar-product-current-item {
pointer-events: none;
}
li.similar-product-item.similar-product-current-item {
background-color: #f4f4f4;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
color: black;
}
.similar-product-image {
background-color: #ececec;
margin-bottom: 7px;
margin-top: 3px;
}
@media (max-width: 767px) {
.similar-products-list {
gap: 8px;
}
.similar-product-item {
width: 87px;
}
.similar-product-item img {
width: 81px;
height: 73px;
}
}
@media (max-width: 1050px) and (min-width: 850px) {
.similar-products-list {
gap: 0px;
}
.similar-product-item {
width: 97px;
}
}
</style>
<script>
document.addEventListener('click', function (event) {
const dropdown = document.getElementById('similar-products-dropdown');
const toggleButton = document.querySelector('.dropdown-toggle');
// Ensure dropdown and toggleButton exist
if (!dropdown || !toggleButton) return;
// Check if the click is on the toggle button or dropdown content
const isClickInsideToggle = toggleButton.contains(event.target);
const isClickInsideDropdown = dropdown.contains(event.target);
if (!isClickInsideDropdown && !isClickInsideToggle) {
// Hide the dropdown if clicked outside
dropdown.classList.remove('show');
// Update arrow direction
const arrow = toggleButton.querySelector('.dropdown-arrow i');
if (arrow) {
arrow.className = 'arrow down';
}
}
});
function toggleDropdown() {
const dropdown = document.getElementById('similar-products-dropdown');
const toggleButton = document.querySelector('.dropdown-toggle');
// Ensure dropdown exists
if (!dropdown) return;
const arrow = toggleButton.querySelector('.dropdown-arrow i');
if (dropdown.classList.contains('show')) {
dropdown.classList.remove('show');
if (arrow) arrow.className = 'arrow down';
} else {
dropdown.classList.add('show');
if (arrow) arrow.className = 'arrow up';
}
}
// Attach the toggle function to the dropdown toggle button
const toggleButton = document.querySelector('.dropdown-toggle');
if (toggleButton) {
toggleButton.addEventListener('click', function (event) {
event.stopPropagation(); // Prevent bubbling to document click
toggleDropdown();
});
}
(function($) {
$(document).ready(function() { console.log( location.href );
let currLang = '';
let currUrl = location.href;
let siteUrl = '<?php echo site_url(); ?>'
if( currUrl.indexOf( '/en/product/' ) > -1 ) {
currLang = 'en';
}
else if( currUrl.indexOf( '/es/producto/' ) > -1 ) {
currLang = 'es';
}
else if( currUrl.indexOf( '/fr/produit/' ) > -1 ) {
currLang = 'fr';
}
else if( currUrl.indexOf( '/it/prodotto/' ) > -1 ) {
currLang = 'it';
}
else if( currUrl.indexOf( '/de/produkt/' ) > -1 ) {
currLang = 'de';
}
else if( currUrl.indexOf( '/cs/produkt/' ) > -1 ) {
currLang = 'cs';
}
else if( currUrl.indexOf( '/sk/produkt/' ) > -1 ) {
currLang = 'sk';
}
else if( currUrl.indexOf( '/pt/produtos/' ) > -1 ) {
currLang = 'pt';
}
let hrefDataAttr = currLang ? 'lang-'+currLang : 'href';
if ($('.similar-products-list').length) {
$('.similar-products-list').insertAfter('.woocommerce-product-rating');
$('.similar-product-item').on('click', function() {
window.location = $(this).data(hrefDataAttr);
});
}
if ($('.similar-products-dropdown').length) {
$('.similar-products-dropdown').insertAfter('.similar-products-list');
$('.dropdown-item').on('click', function() {
window.location = $(this).data(hrefDataAttr);
});
}
});
})(jQuery);
</script>
### ✅ Problem Summary:
– Dropdown is placed properly initially.
– On image load, dropdown shifts due to dynamic height/width or positioning issues.
– Possibly related to `position: absolute` without containing context, or unaccounted image sizes.
—
### ✅ Fixes You Can Apply
#### **1. Set a fixed width on dropdown container**
This ensures the dropdown doesn’t resize based on image content:
.similar-products-dropdown .dropdown-content {
width: 300px; /* adjust to fit your layout */
left: 0; /* or set exact alignment */
right: auto;
}
#### **2. Force image dimensions to prevent layout shift**
Ensure all images in the dropdown have fixed dimensions from the start:
.dropdown-item-image {
width: 50px;
height: 50px;
object-fit: cover;
display: block;
}
You **already have width set**, but **height is `auto`** – that's usually the issue. Change to `height: 50px` (or preferred size).
#### **3. Add image container to isolate shifts**
Wrap images in a container and fix their size:
<div class="dropdown-item-image-wrapper">
<img src="..." class="dropdown-item-image" />
</div>
.dropdown-item-image-wrapper {
width: 50px;
height: 50px;
flex-shrink: 0;
}
#### **4. Avoid content reflow by pre-setting dropdown height**
If image count is high and causes scroll, define a max height (you already have this):
.similar-products-dropdown .dropdown-content {
max-height: 200px;
overflow-y: auto;
}
Make sure this stays **consistent** and doesn’t grow when images are larger than expected.
#### **5. Add a wrapper with `position: relative`**
Ensure that `.similar-products-dropdown` (parent of `dropdown-content`) has:
.similar-products-dropdown {
position: relative;
}
This ensures `position: absolute` of the `.dropdown-content` is scoped correctly.
—
### ✅ JavaScript Improvement (Optional)
Add an event to ensure dropdown doesn't shift when images load:
document.querySelectorAll('.dropdown-item img').forEach(function(img) {
img.addEventListener('load', function() {
const dropdown = document.getElementById('similar-products-dropdown');
if (dropdown) {
dropdown.classList.add('show'); // Reapply class or force redraw
}
});
});
—
### ✅ Final Tip:
If you have **dynamic content injection** or **delayed loading** (e.g., AJAX or lazyload), make sure to trigger layout updates or transition fixes after rendering.
Let me know if you want help applying this fix directly in your output HTML and CSS.
{
global $product;
if (!$product || !is_a($product, 'WC_Product')) {
return;
}
$similar_products = prof_get_similar_products_from_subcategory($product->get_id());
if (empty($similar_products)) {
return; // No similar products found
}
//$max_display = 4; // Limit for displayed products
$product_count = count($similar_products);
// Function to fetch Linguise translated URLs
function prf_get_linguise_translated_url($source_link) {
global $wpdb;
$source_path = rtrim(str_replace(wp_parse_url(site_url(), PHP_URL_PATH), '', parse_url($source_link, PHP_URL_PATH)), '/');
return $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}linguise_urls WHERE source = %s",
$source_path
));
}
// Generate product title with fallback
function prf_get_product_title($product_id) {
$title = get_post_meta($product_id, '_alternative_name', true);
if (empty($title)) {
$product_obj = wc_get_product($product_id);
$title = $product_obj ? $product_obj->get_name() : '';
}
return esc_html($title);
}
// Generate language attributes for a product link
function prf_generate_language_attrs($product_link) {
$attrs = '';
$translated_urls = prf_get_linguise_translated_url($product_link);
if (!empty($translated_urls)) {
foreach ($translated_urls as $url) {
$tr_url = site_url() . $url->translation;
$attrs .= ' data-lang-' . esc_attr($url->language) . '="' . esc_url($tr_url) . '"';
}
}
return $attrs;
}
// Start building HTML
$section_html = '';
if ($product_count > 4) {
$extra_products = $similar_products;
$first_extra_product = $extra_products[0];
$first_product_obj = wc_get_product($first_extra_product->ID);
$first_product_title = get_post_meta($first_extra_product->ID, '_alternative_name', true);
// If _alternative_name meta field is empty, fallback to the product name
if (empty($first_product_title)) {
$first_product_title = $first_product_obj->get_name();
}
// Dropdown toggle with first product's title
$section_html .= '';
$section_html .= '';
$section_html .= '' . esc_html($first_product_title) . '';
$section_html .= '';
$section_html .= '';
$section_html .= '';
foreach ($extra_products as $extra_product) {
$extra_product_obj = wc_get_product($extra_product->ID);
$product_link = get_permalink($extra_product->ID);
$product_title = $extra_product_obj->get_name();
$product_image = wp_get_attachment_image_src(get_post_thumbnail_id($extra_product->ID), 'thumbnail')[0];
$lang_attrs_extra = '';
$translated_urls_extra = prf_get_linguise_translated_url( $product_link );
if( $translated_urls_extra ) {
foreach( $translated_urls_extra as $url ) {
$tr_url = site_url() . $url->translation;
$lang_attrs_extra .= ' data-lang-'.$url->language.'="'.$tr_url.'"';
}
}
$product_title = get_post_meta($extra_product->ID, '_alternative_name', true);
// If _alternative_name meta field is empty, fallback to the product name
if (empty($product_title)) {
$product_title = $extra_product_obj->get_name();
}
$section_html .= '';
// $section_html .= '';
$section_html .= '';
$section_html .= '' . esc_html($product_title) . '';
// $section_html .= '';
$section_html .= '';
}
$section_html .= '';
$section_html .= '';
}else{
$section_html .= '';
// Display the first 4 products
$displayed_products = $similar_products;
foreach ($displayed_products as $similar_product) {
$similar_product_obj = wc_get_product($similar_product->ID);
$product_link = get_permalink($similar_product->ID);
$lang_attrs = '';
$translated_urls = prf_get_linguise_translated_url( $product_link );
if( $translated_urls ) {
foreach( $translated_urls as $url ) {
$tr_url = site_url() . $url->translation;
$lang_attrs .= ' data-lang-'.$url->language.'="'.$tr_url.'"';
}
}
$product_title = get_post_meta($similar_product->ID, '_alternative_name', true);
// If _alternative_name meta field is empty, fallback to the product name
if (empty($product_title)) {
$product_title = $similar_product_obj->get_name();
}
$product_image = wp_get_attachment_image_src(get_post_thumbnail_id($similar_product->ID), 'thumbnail')[0];
$item_class = 'similar-product-item';
$item_class .= $product->get_id() == $similar_product->ID ? ' similar-product-current-item' : '';
$section_html .= '';
// $section_html .= '';
$section_html .= '';
$section_html .= '' . esc_html($product_title) . '';
// $section_html .= '';
$section_html .= '';
}
$section_html .= '';
}
// Add custom dropdown for extra products
$section_html .= ''; ?>
<style>
.prf-spd-arrow {
border: solid #1ebcbe;
border-width: 0 3px 3px 0;
display: inline-block;
padding: 3px;
}
.prf-spd-arrow.right {
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.prf-spd-arrow.left {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
}
.prf-spd-arrow.up {
transform: rotate(-135deg);
-webkit-transform: rotate(-135deg);
}
.prf-spd-arrow.down {
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
}
.similar-products-container {
margin: 20px 0;
}
.similar-products-list {
list-style: none;
display: flex;
gap: 15px;
margin: 0;
padding: 0;
}
.similar-product-item {
text-align: center;
}
.similar-product-item img {
width: 80px;
height: auto;
margin-bottom: 5px;
}
/* Dropdown container */
.similar-products-dropdown {
position: relative;
margin-top: 10px;
margin-bottom: 20px;
}
.similar-products-dropdown .dropdown-toggle {
color: #fff;
padding: 10px 15px;
cursor: pointer;
text-align: center;
border-radius: 4px;
}
.similar-products-dropdown .dropdown-content {
display: none;
position: absolute;
background-color: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
width: 100%;
max-height: 200px;
overflow-y: auto;
z-index: 10;
padding: 0;
margin: 0;
list-style: none;
border-radius: 4px;
border: 1px solid #ddd;
}
.similar-products-dropdown .dropdown-item:last-child {
border-bottom: none!important;
}
.similar-products-dropdown .dropdown-content.show {
display: block;
}
.similar-products-dropdown .dropdown-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
border-bottom: 1px solid #eee;
}
.similar-products-dropdown .dropdown-item a {
display: flex;
align-items: center;
text-decoration: none;
color: #333;
width: 100%;
gap: 12px;
}
.similar-products-dropdown li.dropdown-item {
margin-left: 0px !important;
cursor: pointer;
}
.similar-products-dropdown .dropdown-item-image {
width: 50px;
height: auto;
border-radius: 4px;
}
.similar-products-dropdown .dropdown-item-title {
font-size: 14px;
line-height: 1.5;
}
.similar-products-dropdown .dropdown-item:hover {
background-color: #f9f9f9;
}
.similar-products-dropdown .dropdown-toggle {
display: flex;
justify-content: space-between;
align-items: center;
color: black;
padding: 10px 15px;
cursor: pointer;
border-radius: 4px;
font-size: 14px;
border: 1px solid #ddd;
}
.similar-products-dropdown .dropdown-arrow {
transition: transform 0.3s ease;
font-size: 12px;
color: #1ebcbe;
}
.similar-products-dropdown .dropdown-content.show + .dropdown-toggle .dropdown-arrow {
transform: rotate(180deg);
}
@media (max-width: 767px) {
.similar-products-list {
gap: 8px;
}
.similar-product-item {
width: 87px;
}
.similar-product-item img {
width: 81px;
height: 73px;
}
}
@media (max-width: 1050px) and (min-width: 850px) {
.similar-products-list {
gap: 0px;
}
.similar-product-item {
width: 97px;
}
}
/* Style for similiar product */
.prof-similar-prds-heading {
text-transform: uppercase;
margin-bottom: 15px;
}
.similar-products-list {
list-style-type: none;
display: flex;
gap: 10px;
padding: 0;
}
.similar-product-item {
width: 116px;
text-align: center;
cursor: pointer;
margin-left: 0px !important;
padding: 10px;
}
.similar-product-item img {
max-width: 100%;
object-fit: cover;
border-radius: 8px;
opacity: 0.9;
/* Make the image look dull */
transition: opacity 0.3s ease;
/* Smooth transition for hover effect */
}
.similar-product-item:hover img {
opacity: 1;
/* Restore image to full visibility on hover */
}
.similar-product-item .product-title {
font-size: 13px;
margin-bottom: 5px;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
li.similar-product-item:hover {
background-color: #f9f9f9;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
color: black;
}
.similar-product-current-item {
pointer-events: none;
}
li.similar-product-item.similar-product-current-item {
background-color: #f4f4f4;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
color: black;
}
.similar-product-image {
background-color: #ececec;
margin-bottom: 7px;
margin-top: 3px;
}
@media (max-width: 767px) {
.similar-products-list {
gap: 8px;
}
.similar-product-item {
width: 87px;
}
.similar-product-item img {
width: 81px;
height: 73px;
}
}
@media (max-width: 1050px) and (min-width: 850px) {
.similar-products-list {
gap: 0px;
}
.similar-product-item {
width: 97px;
}
}
</style>
<script>
document.addEventListener('click', function (event) {
const dropdown = document.getElementById('similar-products-dropdown');
const toggleButton = document.querySelector('.dropdown-toggle');
// Ensure dropdown and toggleButton exist
if (!dropdown || !toggleButton) return;
// Check if the click is on the toggle button or dropdown content
const isClickInsideToggle = toggleButton.contains(event.target);
const isClickInsideDropdown = dropdown.contains(event.target);
if (!isClickInsideDropdown && !isClickInsideToggle) {
// Hide the dropdown if clicked outside
dropdown.classList.remove('show');
// Update arrow direction
const arrow = toggleButton.querySelector('.dropdown-arrow i');
if (arrow) {
arrow.className = 'arrow down';
}
}
});
function toggleDropdown() {
const dropdown = document.getElementById('similar-products-dropdown');
const toggleButton = document.querySelector('.dropdown-toggle');
// Ensure dropdown exists
if (!dropdown) return;
const arrow = toggleButton.querySelector('.dropdown-arrow i');
if (dropdown.classList.contains('show')) {
dropdown.classList.remove('show');
if (arrow) arrow.className = 'arrow down';
} else {
dropdown.classList.add('show');
if (arrow) arrow.className = 'arrow up';
}
}
// Attach the toggle function to the dropdown toggle button
const toggleButton = document.querySelector('.dropdown-toggle');
if (toggleButton) {
toggleButton.addEventListener('click', function (event) {
event.stopPropagation(); // Prevent bubbling to document click
toggleDropdown();
});
}
(function($) {
$(document).ready(function() { console.log( location.href );
let currLang = '';
let currUrl = location.href;
let siteUrl = '<?php echo site_url(); ?>'
if( currUrl.indexOf( '/en/product/' ) > -1 ) {
currLang = 'en';
}
else if( currUrl.indexOf( '/es/producto/' ) > -1 ) {
currLang = 'es';
}
else if( currUrl.indexOf( '/fr/produit/' ) > -1 ) {
currLang = 'fr';
}
else if( currUrl.indexOf( '/it/prodotto/' ) > -1 ) {
currLang = 'it';
}
else if( currUrl.indexOf( '/de/produkt/' ) > -1 ) {
currLang = 'de';
}
else if( currUrl.indexOf( '/cs/produkt/' ) > -1 ) {
currLang = 'cs';
}
else if( currUrl.indexOf( '/sk/produkt/' ) > -1 ) {
currLang = 'sk';
}
else if( currUrl.indexOf( '/pt/produtos/' ) > -1 ) {
currLang = 'pt';
}
let hrefDataAttr = currLang ? 'lang-'+currLang : 'href';
if ($('.similar-products-list').length) {
$('.similar-products-list').insertAfter('.woocommerce-product-rating');
$('.similar-product-item').on('click', function() {
window.location = $(this).data(hrefDataAttr);
});
}
if ($('.similar-products-dropdown').length) {
$('.similar-products-dropdown').insertAfter('.similar-products-list');
$('.dropdown-item').on('click', function() {
window.location = $(this).data(hrefDataAttr);
});
}
});
})(jQuery);
</script>
1. Wrap the entire function output using `ob_start()` and `ob_get_clean()`.
2. Return the generated HTML instead of echoing it.
3. Register the shortcode using `add_shortcode()`.
—
### ✅ Here's the shortcode-converted version of your function:
function prof_similar_products_shortcode($atts) {
global $product;
if (!$product || !is_a($product, 'WC_Product')) {
return '';
}
$similar_products = prof_get_similar_products_from_subcategory($product->get_id());
if (empty($similar_products)) {
return '';
}
ob_start(); // Start capturing output
$product_count = count($similar_products);
// Define helper functions inside the shortcode
if (!function_exists('prf_get_linguise_translated_url')) {
function prf_get_linguise_translated_url($source_link) {
global $wpdb;
$source_path = rtrim(str_replace(wp_parse_url(site_url(), PHP_URL_PATH), '', parse_url($source_link, PHP_URL_PATH)), '/');
return $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}linguise_urls WHERE source = %s",
$source_path
));
}
}
if (!function_exists('prf_get_product_title')) {
function prf_get_product_title($product_id) {
$title = get_post_meta($product_id, '_alternative_name', true);
if (empty($title)) {
$product_obj = wc_get_product($product_id);
$title = $product_obj ? $product_obj->get_name() : '';
}
return esc_html($title);
}
}
if (!function_exists('prf_generate_language_attrs')) {
function prf_generate_language_attrs($product_link) {
$attrs = '';
$translated_urls = prf_get_linguise_translated_url($product_link);
if (!empty($translated_urls)) {
foreach ($translated_urls as $url) {
$tr_url = site_url() . $url->translation;
$attrs .= ' data-lang-' . esc_attr($url->language) . '="' . esc_url($tr_url) . '"';
}
}
return $attrs;
}
}
// Output starts here
?>
<div class="similar-products-container">
<?php if ($product_count > 4): ?>
<?php
$first = $similar_products[0];
$first_title = prf_get_product_title($first->ID);
?>
<div class="similar-products-dropdown">
<div class="dropdown-toggle" onclick="toggleDropdown()">
<span><?php echo $first_title; ?></span>
<span class="dropdown-arrow"><i class="prf-spd-arrow down"></i></span>
</div>
<ul class="dropdown-content" id="similar-products-dropdown">
<?php foreach ($similar_products as $p): ?>
<?php
$link = get_permalink($p->ID);
$title = prf_get_product_title($p->ID);
$image = wp_get_attachment_image_src(get_post_thumbnail_id($p->ID), 'thumbnail')[0];
$lang_attrs = prf_generate_language_attrs($link);
?>
<li class="dropdown-item" data-href="<?php echo esc_url($link); ?>" data-slug="<?php echo esc_attr($p->post_name); ?>" <?php echo $lang_attrs; ?>>
<img src="<?php echo esc_url($image); ?>" alt="<?php echo esc_attr($title); ?>" class="dropdown-item-image">
<span class="dropdown-item-title"><?php echo esc_html($title); ?></span>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php else: ?>
<ul class="similar-products-list">
<?php foreach ($similar_products as $p): ?>
<?php
$link = get_permalink($p->ID);
$title = prf_get_product_title($p->ID);
$image = wp_get_attachment_image_src(get_post_thumbnail_id($p->ID), 'thumbnail')[0];
$lang_attrs = prf_generate_language_attrs($link);
$item_class = 'similar-product-item';
if ($product->get_id() == $p->ID) {
$item_class .= ' similar-product-current-item';
}
?>
<li class="<?php echo esc_attr($item_class); ?>" data-href="<?php echo esc_url($link); ?>" data-slug="<?php echo esc_attr($p->post_name); ?>" <?php echo $lang_attrs; ?>>
<img src="<?php echo esc_url($image); ?>" alt="<?php echo esc_attr($title); ?>">
<span class="product-title"><?php echo esc_html($title); ?></span>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<!-- Add your <style> and <script> below or enqueue externally if preferred -->
<style>
/* your CSS styles from the original function go here */
</style>
<script>
// your JavaScript code from the original function goes here
</script>
<?php
return ob_get_clean(); // Return captured output
}
add_shortcode('similar_products_subcategory', 'prof_similar_products_shortcode');
—
### ✅ Usage in a Product Page:
Once the shortcode is registered, just use this inside your product description or any content field:
[similar_products_subcategory]
—
### ✅ Recommended Improvements:
– **Move the CSS and JS to enqueued files** instead of inline (performance + cache benefit).
– Add a check to run the shortcode **only on single product pages** (use `is_product()` inside the shortcode if needed).
Let me know if you'd like a version with enqueued scripts/styles!