Let's assume we have a post type employee
and some categories. We want to get all employees, who are assigned to a specific category to add them via a shortcode. The shortcode should have two attributes: category
and layout
. The category
attribute should accept a comma-separated list of category slugs or IDs. The layout
attribute should define the output layout: grid
or slider
.
Here is an example of how to create a shortcode to list employees by category:
/**
* Listing of employees by category
*
* Example: [employee category="Physiotherapie" layout="grid"]
* - layout="grid": Displays the employees in a grid (default)
* - layout="slider": Displays the employees in a rotating gallery (slider)
*/
function employee_by_category($atts) {
// Attributes with default values
$atts = shortcode_atts(array(
'category' => '', // Slugs or IDs of categories, separated by commas
'layout' => 'grid', // Layout type: grid (default) or slider
), $atts);
// Extract category IDs
$categories = array_map('trim', explode(',', $atts['category']));
// Prepare query arguments
$args = array(
'post_type' => 'employee', // Custom Post Type
'post_status' => 'publish',
'orderby' => 'rand',
'order' => 'ASC',
'posts_per_page'=> -1,
);
// Add taxonomy only if categories are specified
if (!empty($atts['category'])) {
$args['tax_query'] = array(
array(
'taxonomy' => 'category', // Taxonomy of categories
'field' => 'slug', // Categories as slug (can be changed to 'term_id')
'terms' => $categories,
),
);
}
$output = ''; // Output string
$query = new WP_Query($args);
// No posts found
if (!$query->have_posts()) {
return '<p>No entries found.</p>';
}
// Wrapper based on layout
$class = ($atts['layout'] === 'slider') ? 'employee-slider' : 'employee-grid';
$output .= '<div class="' . esc_attr($class) . '">';
// Loop through posts
while ($query->have_posts()) {
$query->the_post();
// Generate post HTML
$output .= '<div class="employee-wrapper">';
$output .= '<div class="employee-image">';
$output .= '<a href="' . esc_url(get_permalink()) . '">';
// Fallback for images
if (has_post_thumbnail()) {
$output .= get_the_post_thumbnail(get_the_ID(), 'medium'); // Thumbnail
} else {
$output .= '<img src="' . esc_url(get_template_directory_uri() . '/images/placeholder.png') . '" alt="' . esc_attr(get_the_title()) . '">';
}
$output .= '</a>';
$output .= '</div>';
if ($atts['layout'] === 'grid') {
$output .= '<div class="employee-name">';
$output .= '<h3>' . esc_html(get_the_title()) . '</h3>'; // Title
$output .= '</div>';
}
$output .= '</div>';
}
$output .= '</div>'; // Close wrapper
wp_reset_postdata(); // Reset query
return $output;
}
add_shortcode('employee', 'employee_by_category');
Add this CSS to your Customizer or theme stylesheet to style the output:
/* Grid-Layout */
.employee-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px; /* Abstand zwischen den Karten */
margin: 0 auto; /* Zentriert die Grid-Komponente */
padding: 20px;
}
@media screen and (max-width: 1024px) {
.employee-grid {
grid-template-columns: repeat(2, 1fr); /* 2 Spalten auf Tablets */
}
}
@media screen and (max-width: 768px) {
.employee-grid {
grid-template-columns: 1fr; /* 1 Spalte auf Mobile */
}
}
/* Slider-Layout */
.employee-slider {
display: flex;
overflow: hidden; /* Versteckt den Überlauf */
gap: 20px;
padding: 40px;
scroll-behavior: smooth; /* Sanftes Scrollen */
scroll-snap-type: x mandatory; /* Erzwingt exakte Positionierung */
position: relative; /* Für zukünftige Steuerung */
}
.employee-slider .employee-wrapper {
flex: 0 0 auto;
transition: transform 0.5s ease-in-out;
scroll-snap-align: start; /* Jedes Element wird genau positioniert */
}
/* Animation für Rotation */
@keyframes slide {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}
.employee-slider:hover .employee-wrapper {
animation-play-state: paused; /* Stoppe Rotation beim Hover */
}
/* Globale Styles */
.employee-wrapper {
border: 0px solid #ddd; /* Leichter Rahmen */
border-radius: 2px; /* Abgerundete Ecken */
overflow: hidden; /* Überlauf verstecken */
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* Schatten */
text-align: center; /* Zentrierter Inhalt */
background: #fff; /* Hintergrundfarbe */
transition: transform 0.3s ease, box-shadow 0.3s ease; /* Animation bei Hover */
}
.employee-wrapper:hover {
transform: translateY(-5px); /* Leichter Hover-Effekt */
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15); /* Stärkere Schatten bei Hover */
}
.employee-image img {
width: 100%; /* Bild füllt den Container */
height: auto; /* Proportionale Höhe */
display: block;
}
.employee-name {
padding: 10px; /* Innenabstand */
font-size: 1.2rem; /* Textgröße */
font-weight: bold;
color: #333; /* Textfarbe */
}
If you want to add the slider functionality, you need to add some JavaScript to let it automatically slide and pause on hover:
document.addEventListener("DOMContentLoaded", () => {
const slider = document.querySelector(".employee-slider");
if (!slider) return;
const items = slider.querySelectorAll(".employee-wrapper");
if (items.length === 0) return;
// Calculate the exact width of an item including margin
const itemStyle = getComputedStyle(items[0]);
const itemWidth =
items[0].offsetWidth +
parseFloat(itemStyle.marginLeft) +
parseFloat(itemStyle.marginRight);
let currentIndex = 0;
let interval;
const startSlider = () => {
interval = setInterval(() => {
currentIndex++;
// Return to the beginning if the end is reached
if (currentIndex >= items.length) {
currentIndex = 0;
slider.scrollTo({
left: 0,
behavior: "smooth",
});
} else {
slider.scrollTo({
left: currentIndex * itemWidth,
behavior: "smooth",
});
}
}, 5000); // Scroll every 5 seconds
};
const stopSlider = () => clearInterval(interval);
// Start the slider
startSlider();
// Stop the slider on hover
slider.addEventListener("mouseover", stopSlider);
// Restart the slider when the mouse leaves the area
slider.addEventListener("mouseout", startSlider);
});