10 Commits
Author SHA1 Message Date
M_Viper 14bd0bfc68 README.md aktualisiert 2025-11-26 16:43:00 +00:00
M_Viper 47543ed98d README.md aktualisiert 2025-11-26 16:42:36 +00:00
M_Viper aa58ae479c Dateien nach "assets/js" hochladen 2025-11-26 16:37:33 +00:00
M_Viper a815fe7c7b Dateien nach "assets/css" hochladen 2025-11-26 16:37:18 +00:00
M_Viper 525616391a Dateien nach "includes" hochladen 2025-11-26 16:36:49 +00:00
M_Viper 8f82a72ea3 Dateien nach "templates" hochladen 2025-11-26 16:36:26 +00:00
M_Viper 2318594ea9 Dateien nach "/" hochladen 2025-11-26 16:35:57 +00:00
M_Viper b934c94765 wp-multi-team-card.php gelöscht 2025-11-26 16:35:14 +00:00
M_Viper 023a2818cb teamcard-admin.js gelöscht 2025-11-26 16:35:11 +00:00
M_Viper b67644318e teamcard-admin.css gelöscht 2025-11-26 16:35:06 +00:00
17 changed files with 1185 additions and 807 deletions
+2 -3
View File
@@ -2,8 +2,8 @@
**Erstellt Teamkarten mit Name, Funktion, Zuständigkeit, Bild und Kategorie. Ausgabe per Shortcode `[teamcards]`.**
[![Letzte Version](https://img.shields.io/badge/Version-1.0-blue)](https://git.viper.ipv64.net/M_Viper/wp-multi-teamcard/releases)
[Microsoft Teams Support](https://teams.live.com/l/community/FEAzokphpZTJ2u6OgI) • [Telegram Support](https://t.me/M_Viper04)
[![Letzte Version](https://img.shields.io/badge/Version-2.0-blue)](https://git.viper.ipv64.net/M_Viper/wp-multi-teamcard/releases)
[Telegram Support](https://t.me/M_Viper04)
---
@@ -84,7 +84,6 @@ Das Plugin prüft automatisch, ob eine neue Version auf Gitea verfügbar ist, un
## Support
- [Microsoft Teams Community](https://teams.live.com/l/community/FEAzokphpZTJ2u6OgI)
- [Telegram Support](https://t.me/M_Viper04)
---
+102
View File
@@ -0,0 +1,102 @@
/* Allgemeine Admin-Stile */
.teamcard-admin .nav-tab-wrapper {
margin-bottom: 20px;
}
.teamcard-admin .tab-content {
background: #fff;
padding: 20px;
border: 1px solid #ccd0d4;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
}
.teamcard-add-new-form {
background: #f9f9f9;
border: 1px solid #e5e5e5;
padding: 20px;
margin-bottom: 20px;
}
.form-fields {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
.form-field label {
display: block;
margin-bottom: 5px;
font-weight: 600;
}
.form-field input[type="text"],
.form-field select {
width: 100%;
padding: 8px;
}
.teamcard-table .column-thumbnail {
width: 120px;
}
.teamcard-table td {
vertical-align: middle;
}
.image-preview-container {
margin-bottom: 10px;
min-height: 50px;
}
.teamcard-bild-vorschau {
max-width: 80px;
max-height: 80px;
border-radius: 4px;
border: 1px solid #ddd;
}
.editable {
padding: 8px;
border: 1px solid transparent;
border-radius: 4px;
transition: all 0.2s ease-in-out;
min-height: 18px; /* Verhindert Sprünge */
}
.editable:hover {
border-color: #0073aa;
background-color: #f3f3f3;
cursor: pointer;
}
.inline-edit {
width: 100%;
padding: 6px;
box-sizing: border-box;
}
.ui-sortable-helper {
background-color: #fff;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
.ui-state-highlight {
height: 80px;
background-color: #f0f0f0;
border: 1px dashed #ccc;
display: table-cell;
vertical-align: middle;
text-align: center;
color: #999;
}
.ui-state-highlight::before {
content: "Hier ablegen";
}
#teamcard-message {
position: fixed;
top: 50px;
right: 20px;
z-index: 9999;
max-width: 300px;
}
+233
View File
@@ -0,0 +1,233 @@
/* Grid-Container für die Teamkarten */
.teamcard-grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: flex-start;
margin: 30px 0;
}
/* Basis-Stile für alle Teamkarten */
.teamcard {
background-color: #fff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
transition: transform 0.3s ease, box-shadow 0.3s ease;
overflow: hidden; /* Verhindert, dass abgerundete Ecken vom Bild abgeschnitten werden */
}
.teamcard:hover {
transform: translateY(-5px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
.teamcard-image {
text-align: center;
margin-bottom: 15px;
}
.teamcard-image img {
max-width: 120px;
height: 120px;
object-fit: cover; /* Schneidet Bilder zu, ohne sie zu verzerren */
border-radius: 50%;
border: 3px solid #f0f0f0;
}
.teamcard-content {
text-align: center;
}
.teamcard-name {
font-size: 1.2em;
font-weight: 600;
margin: 0 0 10px 0;
color: #333;
}
.teamcard-function {
font-size: 1em;
font-weight: 500;
color: #0073aa;
margin: 0 0 5px 0;
}
.teamcard-responsibility {
font-size: 0.9em;
color: #666;
margin: 0;
}
/* Spezifische Stile für die Card-Typen */
/* Standard Card */
.teamcard-standard {
display: flex;
flex-direction: column;
align-items: center;
}
/* Compact Card */
.teamcard-compact {
display: flex;
flex-direction: row;
align-items: center;
text-align: left;
}
.teamcard-compact .teamcard-image {
margin-bottom: 0;
margin-right: 15px;
flex-shrink: 0;
}
.teamcard-compact .teamcard-image img {
width: 60px;
height: 60px;
}
.teamcard-compact .teamcard-content {
flex-grow: 1;
}
/* Featured Card */
.teamcard-featured {
border: 2px solid #0073aa;
background: linear-gradient(145deg, #ffffff, #f9fbff);
}
.teamcard-featured .teamcard-image img {
border-color: #0073aa;
}
.teamcard-featured .teamcard-name {
color: #0073aa;
}
/* --- NEUE STILE FÜR DIE KARTENTYPEN --- */
/* Flip Card */
.teamcard-flip-container {
perspective: 1000px; /* Entfernung zum 3D-Effekt */
}
.teamcard-flipper {
position: relative;
width: 100%;
height: 320px; /* Feste Höhe, wichtig für den Flip-Effekt */
transition: transform 0.8s;
transform-style: preserve-3d;
}
.teamcard-flip-container:hover .teamcard-flipper {
transform: rotateY(180deg);
}
.teamcard-flip {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden; /* Rückseite der Elemente verbergen */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 8px;
border: 1px solid #eee;
}
.teamcard-front {
background-color: #fff;
}
.teamcard-back {
background-color: #f8f9fa;
color: #333;
transform: rotateY(180deg);
}
.teamcard-back .teamcard-content {
padding: 20px;
}
.teamcard-back .teamcard-responsibility {
font-size: 0.9em;
line-height: 1.6;
text-align: left;
}
/* Profile Card */
.teamcard-profile {
border-radius: 0;
overflow: hidden;
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
color: #fff;
display: flex;
flex-direction: column;
}
.teamcard-profile-header {
height: 180px;
background-size: cover;
background-position: center;
position: relative;
display: flex;
align-items: flex-end;
}
.teamcard-profile-header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to top, rgba(0,0,0,0.7), rgba(0,0,0,0.1));
}
.teamcard-profile-content {
position: relative;
z-index: 2;
padding: 20px;
width: 100%;
box-sizing: border-box;
}
.teamcard-profile .teamcard-name {
margin: 0;
color: #fff;
font-size: 1.4em;
}
.teamcard-profile .teamcard-function {
margin: 5px 0 0 0;
color: #f0f0f0;
font-weight: 400;
}
.teamcard-profile-body {
padding: 20px;
background-color: #fff;
color: #333;
flex-grow: 1;
}
.teamcard-profile-body .teamcard-responsibility {
margin: 0;
font-size: 0.9em;
line-height: 1.6;
}
/* Responsive Anpassungen */
@media (max-width: 768px) {
.teamcard-grid {
justify-content: center;
}
.teamcard {
flex-basis: 100% !important;
max-width: 320px;
}
/* Anpassung der Höhe für Flip-Cards auf kleinen Bildschirmen */
.teamcard-flipper {
height: 280px;
}
}
+171
View File
@@ -0,0 +1,171 @@
jQuery(document).ready(function($) {
var newTeamcardFrame;
var teamcardFrame;
// Medienbibliothek für neues Teammitglied
$('#new-teamcard-bild-button').on('click', function(e) {
e.preventDefault();
if (newTeamcardFrame) { newTeamcardFrame.open(); return; }
newTeamcardFrame = wp.media({ title: 'Bild auswählen', button: { text: 'Verwenden' }, multiple: false });
newTeamcardFrame.on('select', function() {
var attachment = newTeamcardFrame.state().get('selection').first().toJSON();
$('#new-teamcard-bild-id').val(attachment.id);
$('#new-teamcard-bild-vorschau').attr('src', attachment.url).show();
});
newTeamcardFrame.open();
});
// Medienbibliothek für vorhandene Teammitglieder
$(document).on('click', '.teamcard-bild-button', function(e) {
e.preventDefault();
var button = $(this);
var teamcardId = button.data('id');
if (teamcardFrame) { teamcardFrame.open(); return; }
teamcardFrame = wp.media({ title: 'Bild ändern', button: { text: 'Verwenden' }, multiple: false });
teamcardFrame.on('select', function() {
var attachment = teamcardFrame.state().get('selection').first().toJSON();
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: { action: 'update_teamcard_image', id: teamcardId, bild_id: attachment.id, nonce: teamcard_data.nonce },
success: function(response) {
if (response.success) {
var container = button.siblings('.image-preview-container');
container.html('<img src="' + response.data.bild_url + '" class="teamcard-bild-vorschau">');
showMessage('Bild erfolgreich aktualisiert.', 'success');
}
}
});
});
teamcardFrame.open();
});
// Neues Teammitglied hinzufügen
$('#add-teamcard-button').on('click', function() {
var name = $('#new-teamcard-name').val();
if (!name) { showMessage('Bitte gib einen Namen ein.', 'error'); return; }
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: {
action: 'add_teamcard',
name: name,
funktion: $('#new-teamcard-funktion').val(),
zustaendigkeit: $('#new-teamcard-zustaendigkeit').val(),
card_type: $('#new-teamcard-card-type').val(),
bild_id: $('#new-teamcard-bild-id').val(),
nonce: teamcard_data.nonce
},
success: function(response) {
if (response.success) {
var bildHtml = response.data.bild_url ? '<img src="' + response.data.bild_url + '" class="teamcard-bild-vorschau">' : '';
var newRow = `
<tr data-id="${response.data.id}" class="teamcard-item">
<td class="teamcard-bild-column"><div class="image-preview-container">${bildHtml}</div><button type="button" class="button teamcard-bild-button" data-id="${response.data.id}">Ändern</button></td>
<td><div class="editable" data-field="title" data-id="${response.data.id}">${name}</div></td>
<td><div class="editable" data-field="funktion" data-id="${response.data.id}">${$('#new-teamcard-funktion').val()}</div></td>
<td><div class="editable" data-field="zustaendigkeit" data-id="${response.data.id}">${$('#new-teamcard-zustaendigkeit').val()}</div></td>
<td>${$('#new-teamcard-card-type option:selected').text()}</td>
<td><button type="button" class="button button-small teamcard-delete" data-id="${response.data.id}">Löschen</button></td>
</tr>`;
$('#teamcard-list').append(newRow);
// Formular zurücksetzen
$('#new-teamcard-name, #new-teamcard-funktion, #new-teamcard-zustaendigkeit, #new-teamcard-bild-id').val('');
$('#new-teamcard-bild-vorschau').hide();
$('#new-teamcard-card-type').prop('selectedIndex',0);
showMessage('Teammitglied erfolgreich hinzugefügt.', 'success');
} else {
showMessage(response.data.message || 'Ein unbekannter Fehler ist aufgetreten.', 'error');
}
}
});
});
// Inline-Bearbeitung
$(document).on('click', '.editable', function() {
var element = $(this);
var currentText = element.text().trim();
element.html('<input type="text" class="inline-edit" value="' + currentText + '">');
element.find('input').focus().select();
});
$(document).on('blur keypress', '.inline-edit', function(e) {
if (e.type === 'keypress' && e.which !== 13) return;
if (e.type === 'keypress') { e.preventDefault(); }
var input = $(this);
var element = input.parent();
var newValue = input.val().trim();
var field = element.data('field');
var id = element.data('id');
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: { action: 'update_teamcard', id: id, field: field, value: newValue, nonce: teamcard_data.nonce },
success: function(response) {
if (response.success) {
element.text(newValue);
showMessage('Erfolgreich aktualisiert.', 'success');
} else {
element.text(newValue); // Text trotzdem aktualisieren, auch wenn der Request fehlschlägt
showMessage('Fehler beim Speichern.', 'error');
}
}
});
});
// Teammitglied löschen
$(document).on('click', '.teamcard-delete', function() {
if (!confirm('Möchtest du dieses Teammitglied wirklich löschen?')) { return; }
var button = $(this);
var id = button.data('id');
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: { action: 'delete_teamcard', id: id, nonce: teamcard_data.nonce },
success: function(response) {
if (response.success) {
button.closest('tr').fadeOut(400, function() { $(this).remove(); });
showMessage('Teammitglied erfolgreich gelöscht.', 'success');
} else {
showMessage('Fehler beim Löschen.', 'error');
}
}
});
});
// Drag & Drop Sortierung
$('#teamcard-list').sortable({
handle: 'td:first', // Nur die erste Spalte als Handle
placeholder: 'ui-state-highlight',
tolerance: 'pointer',
update: function(event, ui) {
var order = $(this).sortable('toArray', {attribute: 'data-id'});
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: { action: 'update_teamcard_order', order: order, nonce: teamcard_data.nonce },
success: function(response) {
if (response.success) {
showMessage('Reihenfolge aktualisiert.', 'success');
}
}
});
}
});
function showMessage(message, type) {
var messageElement = $('#teamcard-message');
messageElement.removeClass('notice-success notice-error').addClass('notice-' + type);
messageElement.html('<p>' + message + '</p>').show().delay(3000).fadeOut();
}
});
+40
View File
@@ -0,0 +1,40 @@
<?php
// Diese Datei wird in der Haupt-Admin-Datei included.
?>
<div class="teamcard-tab-content">
<h2>Hilfe & Dokumentation</h2>
<div class="help-section">
<h3>Shortcode verwenden</h3>
<p>Um alle Teammitglieder anzuzeigen, verwenden Sie:</p>
<code>[teamcards]</code>
<p>Um nur eine bestimmte Kategorie anzuzeigen:</p>
<code>[teamcards kategorie="management"]</code>
<p>Um einen bestimmten Card-Typ zu erzwingen (überschreibt die Einstellung des Mitglieds):</p>
<code>[teamcards type="featured"]</code>
<p>Um die Anzahl der Spalten zu ändern (überschreibt die globale Einstellung):</p>
<code>[teamcards columns="3"]</code>
</div>
<div class="help-section">
<h3>Card-Typen</h3>
<ul>
<li><strong>Standard Card:</strong> Die klassische Card mit Bild oben und Text darunter.</li>
<li><strong>Compact Card:</strong> Eine platzsparende Version, ideal für lange Listen.</li>
<li><strong>Featured Card:</strong> Eine hervorgehobene Card mit zentriertem Layout und besonderem Styling.</li>
<li><strong>Flip Card:</strong> Eine interaktive Card, die beim Hover gedreht wird, um zusätzliche Informationen (z.B. "Über mich") auf der Rückseite zu zeigen.</li>
<li><strong>Profile Card:</strong> Eine Card mit dem Bild als Hintergrund, ideal für ein modernes, visuelles Profil.</li>
</ul>
</div>
<div class="help-section">
<h3>Support</h3>
<p>Für Support und Fragen kontaktieren Sie uns bitte über:</p>
<ul>
<li><a href="https://discord.com/invite/FdRs4BRd8D" target="_blank">Discord Support</a></li>
<li><a href="https://t.me/M_Viper04" target="_blank">Telegram Support</a></li>
</ul>
</div>
</div>
+12
View File
@@ -0,0 +1,12 @@
<?php
// Diese Datei wird in der Haupt-Admin-Datei included.
?>
<div class="teamcard-tab-content">
<form action="options.php" method="post">
<?php
settings_fields('teamcard_settings_group');
do_settings_sections('teamcard_settings');
submit_button('Einstellungen speichern');
?>
</form>
</div>
+93
View File
@@ -0,0 +1,93 @@
<?php
// Diese Datei wird in der Haupt-Admin-Datei included.
?>
<div class="teamcard-tab-content">
<p><strong>Hinweis:</strong> Beim Löschen des Plugins werden alle Teammitglieder und zugehörigen Daten unwiderruflich aus der Datenbank entfernt. Bitte erstellen Sie ein Backup, falls Sie die Daten behalten möchten.</p>
<div class="teamcard-add-new-form">
<h2>Neues Teammitglied hinzufügen</h2>
<div class="form-fields">
<div class="form-field">
<label for="new-teamcard-name">Name:</label>
<input type="text" id="new-teamcard-name" placeholder="Name eingeben" required>
</div>
<div class="form-field">
<label for="new-teamcard-funktion">Funktion:</label>
<input type="text" id="new-teamcard-funktion" placeholder="Funktion eingeben">
</div>
<div class="form-field">
<label for="new-teamcard-zustaendigkeit">Zuständigkeit / Über mich:</label>
<textarea id="new-teamcard-zustaendigkeit" placeholder="Zuständigkeit oder Text für die Rückseite der Flip-Card eingeben"></textarea>
</div>
<div class="form-field">
<label for="new-teamcard-card-type">Card-Typ:</label>
<select id="new-teamcard-card-type">
<option value="standard">Standard Card</option>
<option value="compact">Compact Card</option>
<option value="featured">Featured Card</option>
<!-- NEUE OPTIONEN -->
<option value="flip">Flip Card</option>
<option value="profile">Profile Card</option>
</select>
</div>
<div class="form-field">
<label>Bild:</label>
<div class="image-preview-container">
<img id="new-teamcard-bild-vorschau" src="" style="display:none; max-width:100px;">
</div>
<input type="hidden" id="new-teamcard-bild-id" value="">
<button type="button" class="button" id="new-teamcard-bild-button">Bild auswählen</button>
</div>
<div class="form-field">
<button type="button" id="add-teamcard-button" class="button button-primary">Teammitglied hinzufügen</button>
</div>
</div>
</div>
<h2>Vorhandene Teammitglieder</h2>
<p>Ziehe die Zeilen, um die Reihenfolge zu ändern. Klicke auf die Felder, um sie zu bearbeiten.</p>
<table class="wp-list-table widefat fixed striped teamcard-table">
<thead>
<tr>
<th class="column-thumbnail">Bild</th>
<th>Name</th>
<th>Funktion</th>
<th>Zuständigkeit</th>
<th>Typ</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody id="teamcard-list">
<?php
$teamcards = get_posts(['post_type' => 'teamcard', 'posts_per_page' => -1, 'orderby' => 'menu_order', 'order' => 'ASC']);
foreach ($teamcards as $teamcard) {
$funktion = get_post_meta($teamcard->ID, '_teamcard_funktion', true);
$zustaendigkeit = get_post_meta($teamcard->ID, '_teamcard_zustaendigkeit', true);
$bild_id = get_post_meta($teamcard->ID, '_teamcard_bild_id', true);
$card_type = get_post_meta($teamcard->ID, '_teamcard_card_type', true);
$bild_url = $bild_id ? wp_get_attachment_image_url($bild_id, 'thumbnail') : '';
?>
<tr data-id="<?php echo $teamcard->ID; ?>" class="teamcard-item">
<td class="teamcard-bild-column">
<div class="image-preview-container">
<?php if ($bild_url): ?>
<img src="<?php echo esc_url($bild_url); ?>" class="teamcard-bild-vorschau">
<?php endif; ?>
</div>
<button type="button" class="button teamcard-bild-button" data-id="<?php echo $teamcard->ID; ?>">Ändern</button>
</td>
<td><div class="editable" data-field="title" data-id="<?php echo $teamcard->ID; ?>"><?php echo esc_html($teamcard->post_title); ?></div></td>
<td><div class="editable" data-field="funktion" data-id="<?php echo $teamcard->ID; ?>"><?php echo esc_html($funktion); ?></div></td>
<td><div class="editable" data-field="zustaendigkeit" data-id="<?php echo $teamcard->ID; ?>"><?php echo esc_html($zustaendigkeit); ?></div></td>
<td><?php echo esc_html(ucfirst($card_type ?: 'standard')); ?></td>
<td><button type="button" class="button button-small teamcard-delete" data-id="<?php echo $teamcard->ID; ?>">Löschen</button></td>
</tr>
<?php
}
?>
</tbody>
</table>
<div id="teamcard-message" class="notice" style="display:none;"></div>
</div>
+376
View File
@@ -0,0 +1,376 @@
<?php
/**
* Plugin Name: Multi Team-Card
* Plugin URI: https://git.viper.ipv64.net/M_Viper/wp-multi-teamcard
* Description: Erstellt Teamkarten mit Name, Funktion, Zuständigkeit, Bild und Kategorie. Ausgabe per Shortcode [teamcards].
* Version: 2.0
* Author: M_Viper
* Author URI: https://m-viper.de
* Requires at least: 6.8
* Tested up to: 6.8
* PHP Version: 7.4
* License: GPL2
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: multi-team-card
* Tags: team, card, shortcodes, team-management, customizable, responsive
* Support: [Discord Support](https://discord.com/invite/FdRs4BRd8D)
* Support: [Telegram Support](https://t.me/M_Viper04)
*/
if (!defined('ABSPATH')) exit;
// Check if the PHP version is sufficient
if (version_compare(PHP_VERSION, '7.2', '<')) {
die('This plugin requires PHP 7.2 or higher.');
}
// Get the current version of the plugin from the plugin header dynamically
function get_current_plugin_version() {
if (!function_exists('get_plugin_data')) {
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
}
$plugin_data = get_plugin_data(__FILE__);
return $plugin_data['Version'];
}
$gitea_api_url = 'https://git.viper.ipv64.net/api/v1/repos/M_Viper/wp-multi-teamcard/releases/latest';
function check_for_new_release() {
global $gitea_api_url;
$current_version = get_current_plugin_version();
$response = wp_remote_get($gitea_api_url);
if (is_wp_error($response)) {
return;
}
$body = wp_remote_retrieve_body($response);
$release_data = json_decode($body);
if (isset($release_data->tag_name)) {
$latest_version = ltrim($release_data->tag_name, 'v'); // Entfernt 'v' falls vorhanden
if (version_compare($latest_version, $current_version, '>')) {
add_action('admin_notices', function() use ($latest_version) {
echo '<div class="notice notice-info is-dismissible">
<p><strong>⚠️ Neue Version von WP Multi Teamcard verfügbar:</strong> Version ' . esc_html($latest_version) . ' ist jetzt auf Gitea verfügbar. <a href="https://git.viper.ipv64.net/M_Viper/wp-multi-teamcard/releases" target="_blank">Hier klicken, um die neue Version herunterzuladen. ⚠️</a></p>
</div>';
});
}
}
}
add_action('admin_init', 'check_for_new_release');
// CPT registrieren
function teamcard_register_post_type() {
register_post_type('teamcard', [
'labels' => [
'name' => 'Teammitglieder',
'singular_name' => 'Teammitglied',
'add_new' => 'Neues Teammitglied',
'add_new_item' => 'Teammitglied hinzufügen',
'edit_item' => 'Teammitglied bearbeiten',
],
'public' => true,
'show_ui' => false, // Wir nutzen eine eigene Admin-Seite
'show_in_menu' => false,
'menu_icon' => 'dashicons-groups',
'supports' => ['title'],
'has_archive' => false,
'show_in_admin_bar' => false,
]);
register_taxonomy('teamcard_kategorie', 'teamcard', [
'labels' => [
'name' => 'Kategorien',
'singular_name' => 'Kategorie',
],
'hierarchical' => true,
'public' => true,
'show_admin_column' => true,
'show_ui' => true, // Kategorien im Admin-Menü anzeigen
]);
}
add_action('init', 'teamcard_register_post_type');
// Admin-Menü hinzufügen
function teamcard_add_admin_menu() {
add_menu_page(
'Team-Cards verwalten',
'Team-Cards',
'manage_options',
'teamcard_management',
'teamcard_render_admin_page',
'dashicons-groups',
30
);
}
add_action('admin_menu', 'teamcard_add_admin_menu');
// Die Hauptverwaltungsseite mit Tabs
function teamcard_render_admin_page() {
$active_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'team_members';
?>
<div class="wrap teamcard-admin">
<h1>Team-Cards verwalten</h1>
<nav class="nav-tab-wrapper">
<a href="?page=teamcard_management&tab=team_members" class="nav-tab <?php echo $active_tab === 'team_members' ? 'nav-tab-active' : ''; ?>">Teammitglieder</a>
<a href="?page=teamcard_management&tab=settings" class="nav-tab <?php echo $active_tab === 'settings' ? 'nav-tab-active' : ''; ?>">Einstellungen</a>
<a href="?page=teamcard_management&tab=help" class="nav-tab <?php echo $active_tab === 'help' ? 'nav-tab-active' : ''; ?>">Hilfe</a>
</nav>
<div class="tab-content">
<?php
switch ($active_tab) {
case 'team_members':
require_once plugin_dir_path(__FILE__) . 'includes/team-members-tab.php';
break;
case 'settings':
require_once plugin_dir_path(__FILE__) . 'includes/settings-tab.php';
break;
case 'help':
require_once plugin_dir_path(__FILE__) . 'includes/help-tab.php';
break;
}
?>
</div>
</div>
<?php
}
// AJAX-Handler zum Speichern der Teammitglieder
function teamcard_ajax_handlers() {
add_action('wp_ajax_add_teamcard', function() {
check_ajax_referer('teamcard_nonce', 'nonce');
$name = sanitize_text_field($_POST['name']);
$funktion = sanitize_text_field($_POST['funktion']);
$zustaendigkeit = sanitize_textarea_field($_POST['zustaendigkeit']); // Textarea erlauben
$bild_id = intval($_POST['bild_id']);
$card_type = sanitize_text_field($_POST['card_type']);
if (empty($name)) {
wp_send_json_error(['message' => 'Bitte gib einen Namen ein.']);
}
$max_order = 0;
$posts = get_posts(['post_type' => 'teamcard', 'posts_per_page' => 1, 'orderby' => 'menu_order', 'order' => 'DESC']);
if (!empty($posts)) {
$max_order = $posts[0]->menu_order;
}
$post_id = wp_insert_post([
'post_type' => 'teamcard',
'post_title' => $name,
'post_status' => 'publish',
'menu_order' => $max_order + 1
]);
if ($post_id) {
update_post_meta($post_id, '_teamcard_funktion', $funktion);
update_post_meta($post_id, '_teamcard_zustaendigkeit', $zustaendigkeit);
update_post_meta($post_id, '_teamcard_card_type', $card_type);
if ($bild_id > 0) {
update_post_meta($post_id, '_teamcard_bild_id', $bild_id);
}
$bild_url = $bild_id ? wp_get_attachment_image_url($bild_id, 'thumbnail') : '';
wp_send_json_success(['id' => $post_id, 'bild_url' => $bild_url]);
} else {
wp_send_json_error(['message' => 'Fehler beim Erstellen des Teammitglieds.']);
}
});
add_action('wp_ajax_update_teamcard', function() {
check_ajax_referer('teamcard_nonce', 'nonce');
$post_id = intval($_POST['id']);
$field = sanitize_text_field($_POST['field']);
$value = sanitize_textarea_field($_POST['value']); // Textarea erlauben
if ($field === 'title') {
wp_update_post(['ID' => $post_id, 'post_title' => $value]);
} else {
update_post_meta($post_id, '_teamcard_' . $field, $value);
}
wp_send_json_success();
});
add_action('wp_ajax_delete_teamcard', function() {
check_ajax_referer('teamcard_nonce', 'nonce');
$post_id = intval($_POST['id']);
if (wp_delete_post($post_id, true)) {
wp_send_json_success();
} else {
wp_send_json_error(['message' => 'Fehler beim Löschen.']);
}
});
add_action('wp_ajax_update_teamcard_image', function() {
check_ajax_referer('teamcard_nonce', 'nonce');
$post_id = intval($_POST['id']);
$bild_id = intval($_POST['bild_id']);
update_post_meta($post_id, '_teamcard_bild_id', $bild_id);
$bild_url = wp_get_attachment_image_url($bild_id, 'thumbnail');
wp_send_json_success(['bild_url' => $bild_url]);
});
add_action('wp_ajax_update_teamcard_order', function() {
check_ajax_referer('teamcard_nonce', 'nonce');
$order = $_POST['order']; // This is an array of IDs
foreach ($order as $position => $post_id) {
wp_update_post(['ID' => intval($post_id), 'menu_order' => $position]);
}
wp_send_json_success();
});
}
add_action('init', 'teamcard_ajax_handlers');
// Admin-Skripte und Styles laden
function teamcard_admin_scripts($hook) {
if ($hook !== 'toplevel_page_teamcard_management') return;
wp_enqueue_media();
wp_enqueue_script('jquery-ui-sortable');
wp_enqueue_style('teamcard-admin-style', plugin_dir_url(__FILE__) . 'assets/css/teamcard-admin.css', [], '2.1');
wp_enqueue_script('teamcard-admin-script', plugin_dir_url(__FILE__) . 'assets/js/teamcard-admin.js', ['jquery', 'jquery-ui-sortable'], '2.1', true);
wp_localize_script('teamcard-admin-script', 'teamcard_data', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('teamcard_nonce')
]);
}
add_action('admin_enqueue_scripts', 'teamcard_admin_scripts');
// Frontend-Styles laden
function teamcard_frontend_styles() {
// Nur laden, wenn der Shortcode auf der Seite ist
global $post;
if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'teamcards')) {
wp_enqueue_style('teamcard-frontend-style', plugin_dir_url(__FILE__) . 'assets/css/teamcard-frontend.css', [], '2.1');
}
}
add_action('wp_enqueue_scripts', 'teamcard_frontend_styles');
// Shortcode für die Frontend-Anzeige
function teamcard_shortcode($atts) {
$atts = shortcode_atts([
'kategorie' => '',
'type' => get_option('teamcard_default_card_type', 'standard'),
'columns' => get_option('teamcard_columns', 2),
], $atts, 'teamcards');
$args = [
'post_type' => 'teamcard',
'posts_per_page' => -1,
'orderby' => 'menu_order',
'order' => 'ASC',
];
if (!empty($atts['kategorie'])) {
$args['tax_query'] = [[
'taxonomy' => 'teamcard_kategorie',
'field' => 'slug',
'terms' => sanitize_text_field($atts['kategorie']),
]];
}
$query = new WP_Query($args);
if (!$query->have_posts()) {
return '<p>Keine Teammitglieder gefunden.</p>';
}
// Spaltenbreite für das Grid berechnen
$column_style = '';
if ($atts['columns'] > 1) {
$column_width = (100 / $atts['columns']) - 2; // 2% für den gap
$column_style = "style='flex-basis: calc({$column_width}% - 20px);'";
} else {
$column_style = "style='flex-basis: 100%;'";
}
ob_start();
echo '<div class="teamcard-grid teamcard-grid-' . esc_attr($atts['columns']) . '-cols">';
while ($query->have_posts()) {
$query->the_post();
$post_id = get_the_ID();
$meta = [
'funktion' => get_post_meta($post_id, '_teamcard_funktion', true),
'zustaendigkeit' => get_post_meta($post_id, '_teamcard_zustaendigkeit', true),
'bild_id' => get_post_meta($post_id, '_teamcard_bild_id', true),
'card_type' => get_post_meta($post_id, '_teamcard_card_type', true),
];
$meta['bild_url'] = $meta['bild_id'] ? wp_get_attachment_url($meta['bild_id']) : '';
// Card-Typ aus dem Meta-Feld verwenden, falls vorhanden, sonst den aus dem Shortcode
$card_type_to_render = !empty($meta['card_type']) ? $meta['card_type'] : $atts['type'];
// Sicherstellen, dass die Template-Datei existiert
$template_file = plugin_dir_path(__FILE__) . "templates/card-{$card_type_to_render}.php";
if (file_exists($template_file)) {
include $template_file;
} else {
// Fallback auf Standard-Template, falls spezifisches nicht existiert
include plugin_dir_path(__FILE__) . 'templates/card-standard.php';
}
}
echo '</div>';
wp_reset_postdata();
return ob_get_clean();
}
add_shortcode('teamcards', 'teamcard_shortcode');
// Einstellungs-API registrieren
function teamcard_register_settings() {
register_setting('teamcard_settings_group', 'teamcard_default_card_type', ['sanitize_callback' => 'sanitize_text_field']);
register_setting('teamcard_settings_group', 'teamcard_columns', ['sanitize_callback' => 'absint']);
add_settings_section(
'teamcard_settings_section',
'Anzeige-Einstellungen',
'__return_false', // Keine Beschreibung nötig
'teamcard_settings'
);
add_settings_field(
'teamcard_default_card_type',
'Standard Card-Typ',
'teamcard_default_card_type_callback',
'teamcard_settings',
'teamcard_settings_section'
);
add_settings_field(
'teamcard_columns',
'Anzahl der Spalten',
'teamcard_columns_callback',
'teamcard_settings',
'teamcard_settings_section'
);
}
add_action('admin_init', 'teamcard_register_settings');
function teamcard_default_card_type_callback() {
$default_card_type = get_option('teamcard_default_card_type', 'standard');
?>
<select name="teamcard_default_card_type">
<option value="standard" <?php selected($default_card_type, 'standard'); ?>>Standard Card</option>
<option value="compact" <?php selected($default_card_type, 'compact'); ?>>Compact Card</option>
<option value="featured" <?php selected($default_card_type, 'featured'); ?>>Featured Card</option>
<!-- NEUE OPTIONEN -->
<option value="flip" <?php selected($default_card_type, 'flip'); ?>>Flip Card</option>
<option value="profile" <?php selected($default_card_type, 'profile'); ?>>Profile Card</option>
</select>
<p class="description">Dieser Typ wird verwendet, wenn für ein Mitglied kein spezifischer Typ festgelegt ist.</p>
<?php
}
function teamcard_columns_callback() {
$columns = get_option('teamcard_columns', 2);
?>
<input type="number" name="teamcard_columns" value="<?php echo esc_attr($columns); ?>" min="1" max="4" step="1">
<p class="description">Anzahl der Spalten für die Teammitglieder-Anzeige (1-4).</p>
<?php
}
-157
View File
@@ -1,157 +0,0 @@
.teamcard-admin {
margin: 20px 0;
}
.teamcard-add-new-form {
background: #fff;
border: 1px solid #ccd0d4;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
padding: 20px;
margin-bottom: 20px;
}
.form-fields {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.form-field {
flex: 1 0 200px;
}
.form-field label {
display: block;
margin-bottom: 5px;
font-weight: 600;
}
.form-field input[type="text"] {
width: 100%;
padding: 8px;
}
.teamcard-item td {
vertical-align: middle;
}
.teamcard-bild {
cursor: move;
}
.image-preview-container {
margin-bottom: 10px;
min-height: 50px;
}
.teamcard-bild-vorschau {
max-width: 80px;
max-height: 80px;
border-radius: 4px;
}
.editable {
padding: 8px;
border: 1px solid transparent;
border-radius: 4px;
transition: all 0.2s;
}
.editable:hover {
border-color: #ddd;
background-color: #f9f9f9;
cursor: pointer;
}
.inline-edit {
width: 100%;
padding: 6px;
}
.ui-state-highlight {
height: 80px;
background-color: #f0f0f0;
border: 1px dashed #ccc;
}
#teamcard-message {
position: fixed;
top: 50px;
right: 20px;
z-index: 9999;
max-width: 300px;
}
/* Container für das Teamkarten-Grid */
.teamcard-grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: center;
margin-top: 30px;
}
/* Stil für jedes Teammitglied */
.teamcard {
border: 2px solid #e0e0e0;
border-radius: 10px;
padding: 20px;
width: 280px;
text-align: center;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
background-color: #fff;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
/* Hover-Effekte */
.teamcard:hover {
transform: translateY(-10px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
/* Bild des Teammitglieds */
.teamcard img {
max-width: 100px;
height: 100px;
border-radius: 50%;
margin-bottom: 15px;
transition: transform 0.3s ease;
}
/* Hover-Effekt für das Bild */
.teamcard:hover img {
transform: scale(1.1);
}
/* Name des Teammitglieds */
.teamcard h3 {
font-size: 1.2em;
font-weight: 600;
margin: 10px 0;
color: #333;
}
/* Funktion und Zuständigkeit des Teammitglieds */
.teamcard p {
font-size: 0.95em;
color: #666;
margin-bottom: 10px;
}
/* Stil für den Hover-Effekt beim Teammitglied */
.teamcard:hover h3,
.teamcard:hover p {
color: #0073e6;
}
/* Stil für den Container der Teamkarten auf mobilen Geräten */
@media (max-width: 768px) {
.teamcard-grid {
justify-content: space-evenly;
}
.teamcard {
width: 100%;
max-width: 320px;
}
}
-237
View File
@@ -1,237 +0,0 @@
jQuery(document).ready(function($) {
// Medienbibliothek für neues Teammitglied
var newTeamcardFrame;
$('#new-teamcard-bild-button').on('click', function(e) {
e.preventDefault();
if (newTeamcardFrame) {
newTeamcardFrame.open();
return;
}
newTeamcardFrame = wp.media({
title: 'Bild auswählen',
button: { text: 'Verwenden' },
multiple: false
});
newTeamcardFrame.on('select', function() {
var attachment = newTeamcardFrame.state().get('selection').first().toJSON();
$('#new-teamcard-bild-id').val(attachment.id);
$('#new-teamcard-bild-vorschau').attr('src', attachment.url).show();
});
newTeamcardFrame.open();
});
// Medienbibliothek für vorhandene Teammitglieder
var teamcardFrame;
$(document).on('click', '.teamcard-bild-button', function(e) {
e.preventDefault();
var button = $(this);
var teamcardId = button.data('id');
if (teamcardFrame) {
teamcardFrame.open();
return;
}
teamcardFrame = wp.media({
title: 'Bild auswählen',
button: { text: 'Verwenden' },
multiple: false
});
teamcardFrame.on('select', function() {
var attachment = teamcardFrame.state().get('selection').first().toJSON();
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: {
action: 'update_teamcard_image',
id: teamcardId,
bild_id: attachment.id,
nonce: teamcard_data.nonce
},
success: function(response) {
if (response.success) {
var container = button.siblings('.image-preview-container');
container.html('<img src="' + response.data.bild_url + '" class="teamcard-bild-vorschau">');
showMessage('Bild erfolgreich aktualisiert', 'success');
}
}
});
});
teamcardFrame.open();
});
// Neues Teammitglied hinzufügen
$('#add-teamcard-button').on('click', function() {
var name = $('#new-teamcard-name').val();
var funktion = $('#new-teamcard-funktion').val();
var zustaendigkeit = $('#new-teamcard-zustaendigkeit').val();
var bildId = $('#new-teamcard-bild-id').val();
if (!name) {
showMessage('Bitte gib einen Namen ein', 'error');
return;
}
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: {
action: 'add_teamcard',
name: name,
funktion: funktion,
zustaendigkeit: zustaendigkeit,
bild_id: bildId,
nonce: teamcard_data.nonce
},
success: function(response) {
if (response.success) {
var bildHtml = '';
if (response.data.bild_url) {
bildHtml = '<img src="' + response.data.bild_url + '" class="teamcard-bild-vorschau">';
}
var newRow = '<tr data-id="' + response.data.id + '" class="teamcard-item">' +
'<td class="teamcard-bild">' +
'<div class="image-preview-container">' + bildHtml + '</div>' +
'<button type="button" class="button teamcard-bild-button" data-id="' + response.data.id + '">Bild ändern</button>' +
'</td>' +
'<td><div class="editable" data-field="title" data-id="' + response.data.id + '">' + name + '</div></td>' +
'<td><div class="editable" data-field="funktion" data-id="' + response.data.id + '">' + funktion + '</div></td>' +
'<td><div class="editable" data-field="zustaendigkeit" data-id="' + response.data.id + '">' + zustaendigkeit + '</div></td>' +
'<td><button type="button" class="button button-small teamcard-delete" data-id="' + response.data.id + '">Löschen</button></td>' +
'</tr>';
$('#teamcard-list').append(newRow);
// Formular zurücksetzen
$('#new-teamcard-name').val('');
$('#new-teamcard-funktion').val('');
$('#new-teamcard-zustaendigkeit').val('');
$('#new-teamcard-bild-id').val('');
$('#new-teamcard-bild-vorschau').attr('src', '').hide();
showMessage('Teammitglied erfolgreich hinzugefügt', 'success');
} else {
showMessage(response.data.message, 'error');
}
}
});
});
// Inline-Bearbeitung
$(document).on('click', '.editable', function() {
var element = $(this);
var currentText = element.text();
element.html('<input type="text" class="inline-edit" value="' + currentText + '">');
element.find('input').focus().select();
});
$(document).on('blur', '.inline-edit', function() {
var input = $(this);
var element = input.parent();
var newValue = input.val();
var field = element.data('field');
var id = element.data('id');
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: {
action: 'update_teamcard',
id: id,
field: field,
value: newValue,
nonce: teamcard_data.nonce
},
success: function(response) {
if (response.success) {
element.text(newValue);
showMessage('Erfolgreich aktualisiert', 'success');
}
}
});
});
$(document).on('keypress', '.inline-edit', function(e) {
if (e.which === 13) {
$(this).blur();
}
});
// Teammitglied löschen
$(document).on('click', '.teamcard-delete', function() {
if (!confirm('Möchtest du dieses Teammitglied wirklich löschen?')) {
return;
}
var button = $(this);
var id = button.data('id');
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: {
action: 'delete_teamcard',
id: id,
nonce: teamcard_data.nonce
},
success: function(response) {
if (response.success) {
button.closest('tr').remove();
showMessage('Teammitglied erfolgreich gelöscht', 'success');
} else {
showMessage(response.data.message, 'error');
}
}
});
});
// Drag & Drop Sortierung
$('#teamcard-list').sortable({
handle: 'td:first',
placeholder: 'ui-state-highlight',
update: function(event, ui) {
var order = [];
$('.teamcard-item').each(function() {
order.push($(this).data('id'));
});
$.ajax({
url: teamcard_data.ajax_url,
type: 'POST',
data: {
action: 'update_teamcard_order',
order: order,
nonce: teamcard_data.nonce
},
success: function(response) {
if (response.success) {
showMessage('Reihenfolge erfolgreich aktualisiert', 'success');
}
}
});
}
});
// Hilfsfunktion für Nachrichten
function showMessage(message, type) {
var messageElement = $('#teamcard-message');
messageElement.removeClass('notice-success notice-error').addClass('notice-' + type);
messageElement.html('<p>' + message + '</p>').show();
setTimeout(function() {
messageElement.fadeOut();
}, 3000);
}
});
+18
View File
@@ -0,0 +1,18 @@
<?php
/**
* @var array $meta Enthält alle Metadaten des Teammitglieds
* @var string $column_style Der Inline-Style für die Spaltenbreite
*/
?>
<div class="teamcard teamcard-compact" <?php echo $column_style; ?>>
<?php if ($meta['bild_url']): ?>
<div class="teamcard-image">
<img src="<?php echo esc_url($meta['bild_url']); ?>" alt="<?php echo esc_attr(get_the_title()); ?>">
</div>
<?php endif; ?>
<div class="teamcard-content">
<h3 class="teamcard-name"><?php the_title(); ?></h3>
<p class="teamcard-function"><?php echo esc_html($meta['funktion']); ?></p>
</div>
</div>
+19
View File
@@ -0,0 +1,19 @@
<?php
/**
* @var array $meta Enthält alle Metadaten des Teammitglieds
* @var string $column_style Der Inline-Style für die Spaltenbreite
*/
?>
<div class="teamcard teamcard-featured" <?php echo $column_style; ?>>
<?php if ($meta['bild_url']): ?>
<div class="teamcard-image">
<img src="<?php echo esc_url($meta['bild_url']); ?>" alt="<?php echo esc_attr(get_the_title()); ?>">
</div>
<?php endif; ?>
<div class="teamcard-content">
<h3 class="teamcard-name"><?php the_title(); ?></h3>
<p class="teamcard-function"><?php echo esc_html($meta['funktion']); ?></p>
<p class="teamcard-responsibility"><?php echo esc_html($meta['zustaendigkeit']); ?></p>
</div>
</div>
+35
View File
@@ -0,0 +1,35 @@
<?php
/**
* @var array $meta Enthält alle Metadaten des Teammitglieds
* @var string $column_style Der Inline-Style für die Spaltenbreite
*/
?>
<div class="teamcard-flip-container" <?php echo $column_style; ?>>
<div class="teamcard-flipper">
<!-- Vorderseite der Karte -->
<div class="teamcard teamcard-flip teamcard-front">
<?php if ($meta['bild_url']): ?>
<div class="teamcard-image">
<img src="<?php echo esc_url($meta['bild_url']); ?>" alt="<?php echo esc_attr(get_the_title()); ?>">
</div>
<?php endif; ?>
<div class="teamcard-content">
<h3 class="teamcard-name"><?php the_title(); ?></h3>
<p class="teamcard-function"><?php echo esc_html($meta['funktion']); ?></p>
</div>
</div>
<!-- Rückseite der Karte -->
<div class="teamcard teamcard-flip teamcard-back">
<div class="teamcard-content">
<h3 class="teamcard-name"><?php the_title(); ?></h3>
<div class="teamcard-responsibility">
<?php
// nl2br() wandelt Zeilenumbrüche in <br>-Tags um
echo wp_kses_post(nl2br($meta['zustaendigkeit']));
?>
</div>
</div>
</div>
</div>
</div>
+17
View File
@@ -0,0 +1,17 @@
<?php
/**
* @var array $meta Enthält alle Metadaten des Teammitglieds
* @var string $column_style Der Inline-Style für die Spaltenbreite
*/
?>
<div class="teamcard teamcard-profile" <?php echo $column_style; ?>>
<div class="teamcard-profile-header" <?php echo $meta['bild_url'] ? 'style="background-image: url(' . esc_url($meta['bild_url']) . ');"' : ''; ?>>
<div class="teamcard-profile-content">
<h3 class="teamcard-name"><?php the_title(); ?></h3>
<p class="teamcard-function"><?php echo esc_html($meta['funktion']); ?></p>
</div>
</div>
<div class="teamcard-profile-body">
<p class="teamcard-responsibility"><?php echo esc_html($meta['zustaendigkeit']); ?></p>
</div>
</div>
+19
View File
@@ -0,0 +1,19 @@
<?php
/**
* @var array $meta Enthält alle Metadaten des Teammitglieds
* @var string $column_style Der Inline-Style für die Spaltenbreite
*/
?>
<div class="teamcard teamcard-standard" <?php echo $column_style; ?>>
<?php if ($meta['bild_url']): ?>
<div class="teamcard-image">
<img src="<?php echo esc_url($meta['bild_url']); ?>" alt="<?php echo esc_attr(get_the_title()); ?>">
</div>
<?php endif; ?>
<div class="teamcard-content">
<h3 class="teamcard-name"><?php the_title(); ?></h3>
<p class="teamcard-function"><?php echo esc_html($meta['funktion']); ?></p>
<p class="teamcard-responsibility"><?php echo esc_html($meta['zustaendigkeit']); ?></p>
</div>
</div>
+48
View File
@@ -0,0 +1,48 @@
<?php
// Sicherstellen, dass die Datei nur bei Plugin-Deinstallation direkt von WordPress aufgerufen wird
if (!defined('WP_UNINSTALL_PLUGIN')) {
exit;
}
// Funktion zum Löschen aller Plugin-Daten
function delete_teamcard_data() {
// Alle Teamcard-Posts abrufen
$teamcards = get_posts([
'post_type' => 'teamcard',
'posts_per_page' => -1,
'post_status' => 'any',
]);
// Jeden Post und zugehörige Bilder löschen
foreach ($teamcards as $teamcard) {
// Bild aus der Mediathek löschen, falls vorhanden
$bild_id = get_post_meta($teamcard->ID, '_teamcard_bild_id', true);
if ($bild_id) {
wp_delete_attachment($bild_id, true);
}
// Post und Metadaten löschen
wp_delete_post($teamcard->ID, true);
}
// Taxonomie 'teamcard_kategorie' und ihre Begriffe löschen
$terms = get_terms([
'taxonomy' => 'teamcard_kategorie',
'hide_empty' => false,
]);
if (!is_wp_error($terms)) {
foreach ($terms as $term) {
wp_delete_term($term->term_id, 'teamcard_kategorie');
}
}
// Alle Metadaten löschen, die mit dem Plugin verknüpft sind
global $wpdb;
$wpdb->query("DELETE FROM $wpdb->postmeta WHERE meta_key LIKE '_teamcard_%'");
// Rewrite Rules zurücksetzen
flush_rewrite_rules();
}
// Funktion ausführen
delete_teamcard_data();
-410
View File
@@ -1,410 +0,0 @@
<?php
/**
* Plugin Name: WP Multi Team-Card
* Plugin URI: https://git.viper.ipv64.net/M_Viper/wp-multi-teamcard
* Description: Erstellt Teamkarten mit Name, Funktion, Zuständigkeit, Bild und Kategorie. Ausgabe per Shortcode [teamcards].
* Version: 1.0
* Author: M_Viper
* Author URI: https://m-viper.de
* Requires at least: 6.7.2
* Tested up to: 6.7.2
* PHP Version: 7.2
* License: GPL2
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: wp-multi-team-card
* Tags: team, card, shortcodes, team-management, customizable, responsive
* Support: [Microsoft Teams Support](https://teams.live.com/l/community/FEAzokphpZTJ2u6OgI)
* Support: [Telegram Support](https://t.me/M_Viper04)
*/
if (!defined('ABSPATH')) exit;
// Check if the PHP version is sufficient
if (version_compare(PHP_VERSION, '7.2', '<')) {
die('This plugin requires PHP 7.2 or higher.');
}
// Get the current version of the plugin from the plugin header dynamically
function get_current_plugin_version() {
// Get the plugin data
$plugin_data = get_plugin_data(__FILE__);
return $plugin_data['Version']; // Return the version from the plugin header
}
$gitea_api_url = 'https://git.viper.ipv64.net/api/v1/repos/M_Viper/wp-multi-teamcard/releases/latest'; // Gitea API URL
function check_for_new_release() {
global $gitea_api_url;
// Get the current version dynamically from the plugin header
$current_version = get_current_plugin_version();
// Fetch the latest release data from Gitea
$response = wp_remote_get($gitea_api_url);
// Check if there was an error with the API request
if (is_wp_error($response)) {
return;
}
$body = wp_remote_retrieve_body($response);
$release_data = json_decode($body);
// If release data is valid
if (isset($release_data->tag_name)) {
$latest_version = $release_data->tag_name;
// If the latest version differs from the current version, show the banner
if ($latest_version !== $current_version) {
// Display the banner in the admin area
add_action('admin_notices', function() use ($latest_version) {
echo '<div class="notice notice-info is-dismissible">
<p><strong>⚠️ Neue Version von WP Multi Teamcard verfügbar:</strong> Version ' . esc_html($latest_version) . ' ist jetzt auf Gitea verfügbar. <a href="https://git.viper.ipv64.net/M_Viper/wp-multi-teamcard/releases" target="_blank">Hier klicken, um die neue Version herunterzuladen. ⚠️</a></p>
</div>';
});
}
}
}
// Hook into the admin init to check for updates
add_action('admin_init', 'check_for_new_release');
// CPT registrieren
function teamcard_register_post_type() {
register_post_type('teamcard', [
'labels' => [
'name' => 'Teammitglieder',
'singular_name' => 'Teammitglied',
'add_new' => 'Neues Teammitglied',
'add_new_item' => 'Teammitglied hinzufügen',
'edit_item' => 'Teammitglied bearbeiten',
],
'public' => true,
'show_ui' => false, // Standard-UI ausblenden
'show_in_menu' => false, // Nicht im Hauptmenü anzeigen
'menu_icon' => 'dashicons-groups',
'supports' => ['title'],
'has_archive' => false,
'show_in_admin_bar' => false,
]);
register_taxonomy('teamcard_kategorie', 'teamcard', [
'labels' => [
'name' => 'Kategorien',
'singular_name' => 'Kategorie',
],
'hierarchical' => true,
'public' => true,
'show_admin_column' => true,
]);
}
add_action('init', 'teamcard_register_post_type');
// Admin-Menü hinzufügen
function teamcard_add_admin_menu() {
add_menu_page(
'Teammitglieder verwalten',
'Teamkarten',
'manage_options',
'teamcard_management',
'teamcard_admin_page',
'dashicons-groups',
30
);
}
add_action('admin_menu', 'teamcard_add_admin_menu');
// Die Hauptverwaltungsseite
function teamcard_admin_page() {
?>
<div class="wrap teamcard-admin">
<h1>Teammitglieder verwalten</h1>
<!-- Formular zum Hinzufügen neuer Teammitglieder -->
<div class="teamcard-add-new-form">
<h2>Neues Teammitglied hinzufügen</h2>
<div class="form-fields">
<div class="form-field">
<label for="new-teamcard-name">Name:</label>
<input type="text" id="new-teamcard-name" placeholder="Name eingeben">
</div>
<div class="form-field">
<label for="new-teamcard-funktion">Funktion:</label>
<input type="text" id="new-teamcard-funktion" placeholder="Funktion eingeben">
</div>
<div class="form-field">
<label for="new-teamcard-zustaendigkeit">Zuständigkeit:</label>
<input type="text" id="new-teamcard-zustaendigkeit" placeholder="Zuständigkeit eingeben">
</div>
<div class="form-field">
<label>Bild:</label>
<div class="image-preview-container">
<img id="new-teamcard-bild-vorschau" src="" style="display:none; max-width:100px;">
</div>
<input type="hidden" id="new-teamcard-bild-id" value="">
<button type="button" class="button" id="new-teamcard-bild-button">Bild auswählen</button>
</div>
<div class="form-field">
<button type="button" id="add-teamcard-button" class="button button-primary">Teammitglied hinzufügen</button>
</div>
</div>
</div>
<h2>Vorhandene Teammitglieder</h2>
<p>Ziehe die Zeilen, um die Reihenfolge zu ändern. Klicke auf die Felder, um sie zu bearbeiten.</p>
<!-- Liste der vorhandenen Teammitglieder -->
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th width="10%">Bild</th>
<th width="20%">Name</th>
<th width="20%">Funktion</th>
<th width="30%">Zuständigkeit</th>
<th width="20%">Aktionen</th>
</tr>
</thead>
<tbody id="teamcard-list">
<?php
$teamcards = get_posts([
'post_type' => 'teamcard',
'posts_per_page' => -1,
'orderby' => 'menu_order',
'order' => 'ASC'
]);
foreach ($teamcards as $teamcard) {
$funktion = get_post_meta($teamcard->ID, '_teamcard_funktion', true);
$zustaendigkeit = get_post_meta($teamcard->ID, '_teamcard_zustaendigkeit', true);
$bild_id = get_post_meta($teamcard->ID, '_teamcard_bild_id', true);
$bild_url = $bild_id ? wp_get_attachment_image_url($bild_id, 'thumbnail') : '';
?>
<tr data-id="<?php echo $teamcard->ID; ?>" class="teamcard-item">
<td class="teamcard-bild">
<div class="image-preview-container">
<?php if ($bild_url): ?>
<img src="<?php echo esc_url($bild_url); ?>" class="teamcard-bild-vorschau">
<?php endif; ?>
</div>
<button type="button" class="button teamcard-bild-button" data-id="<?php echo $teamcard->ID; ?>">Bild ändern</button>
</td>
<td>
<div class="editable" data-field="title" data-id="<?php echo $teamcard->ID; ?>"><?php echo esc_html($teamcard->post_title); ?></div>
</td>
<td>
<div class="editable" data-field="funktion" data-id="<?php echo $teamcard->ID; ?>"><?php echo esc_html($funktion); ?></div>
</td>
<td>
<div class="editable" data-field="zustaendigkeit" data-id="<?php echo $teamcard->ID; ?>"><?php echo esc_html($zustaendigkeit); ?></div>
</td>
<td>
<button type="button" class="button button-small teamcard-delete" data-id="<?php echo $teamcard->ID; ?>">Löschen</button>
</td>
</tr>
<?php
}
?>
</tbody>
</table>
<div id="teamcard-message" class="notice" style="display:none;"></div>
</div>
<?php
}
// AJAX-Handler zum Speichern der Teammitglieder
function teamcard_ajax_handlers() {
// Neues Teammitglied hinzufügen
add_action('wp_ajax_add_teamcard', function() {
$name = sanitize_text_field($_POST['name']);
$funktion = sanitize_text_field($_POST['funktion']);
$zustaendigkeit = sanitize_text_field($_POST['zustaendigkeit']);
$bild_id = intval($_POST['bild_id']);
// Höchste menu_order finden
$max_order = 0;
$posts = get_posts([
'post_type' => 'teamcard',
'posts_per_page' => 1,
'orderby' => 'menu_order',
'order' => 'DESC'
]);
if (!empty($posts)) {
$max_order = $posts[0]->menu_order;
}
// Neuen Post erstellen
$post_id = wp_insert_post([
'post_type' => 'teamcard',
'post_title' => $name,
'post_status' => 'publish',
'menu_order' => $max_order + 1
]);
if ($post_id) {
update_post_meta($post_id, '_teamcard_funktion', $funktion);
update_post_meta($post_id, '_teamcard_zustaendigkeit', $zustaendigkeit);
if ($bild_id > 0) {
update_post_meta($post_id, '_teamcard_bild_id', $bild_id);
}
$bild_url = $bild_id ? wp_get_attachment_image_url($bild_id, 'thumbnail') : '';
wp_send_json_success([
'id' => $post_id,
'bild_url' => $bild_url
]);
} else {
wp_send_json_error(['message' => 'Fehler beim Erstellen des Teammitglieds']);
}
});
// Teammitglied aktualisieren
add_action('wp_ajax_update_teamcard', function() {
$post_id = intval($_POST['id']);
$field = sanitize_text_field($_POST['field']);
$value = sanitize_text_field($_POST['value']);
if ($field === 'title') {
wp_update_post([
'ID' => $post_id,
'post_title' => $value
]);
} else {
update_post_meta($post_id, '_teamcard_' . $field, $value);
}
wp_send_json_success();
});
// Teammitglied löschen
add_action('wp_ajax_delete_teamcard', function() {
$post_id = intval($_POST['id']);
if (wp_delete_post($post_id, true)) {
wp_send_json_success();
} else {
wp_send_json_error(['message' => 'Fehler beim Löschen des Teammitglieds']);
}
});
// Bild aktualisieren
add_action('wp_ajax_update_teamcard_image', function() {
$post_id = intval($_POST['id']);
$bild_id = intval($_POST['bild_id']);
update_post_meta($post_id, '_teamcard_bild_id', $bild_id);
$bild_url = wp_get_attachment_image_url($bild_id, 'thumbnail');
wp_send_json_success(['bild_url' => $bild_url]);
});
// Reihenfolge aktualisieren
add_action('wp_ajax_update_teamcard_order', function() {
$order = $_POST['order'];
foreach ($order as $position => $post_id) {
wp_update_post([
'ID' => intval($post_id),
'menu_order' => $position
]);
}
wp_send_json_success();
});
}
add_action('init', 'teamcard_ajax_handlers');
// Admin-Skripte und Styles laden
function teamcard_admin_scripts($hook) {
if ($hook !== 'toplevel_page_teamcard_management') return;
wp_enqueue_media();
wp_enqueue_script('jquery-ui-sortable');
wp_enqueue_style(
'teamcard-admin-style',
plugin_dir_url(__FILE__) . 'teamcard-admin.css',
[],
'1.0'
);
wp_enqueue_script(
'teamcard-admin-script',
plugin_dir_url(__FILE__) . 'teamcard-admin.js',
['jquery', 'jquery-ui-sortable'],
'1.0',
true
);
wp_localize_script('teamcard-admin-script', 'teamcard_data', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('teamcard_nonce')
]);
}
add_action('admin_enqueue_scripts', 'teamcard_admin_scripts');
// Shortcode für die Frontend-Anzeige
function teamcard_shortcode($atts) {
$atts = shortcode_atts([
'kategorie' => '',
], $atts);
$args = [
'post_type' => 'teamcard',
'posts_per_page' => -1,
'orderby' => 'menu_order',
'order' => 'ASC',
];
if ($atts['kategorie']) {
$args['tax_query'] = [[
'taxonomy' => 'teamcard_kategorie',
'field' => 'slug',
'terms' => $atts['kategorie'],
]];
}
$query = new WP_Query($args);
if (!$query->have_posts()) return '<p>Keine Teammitglieder gefunden.</p>';
ob_start();
echo '<div class="teamcard-grid" style="display: flex; flex-wrap: wrap; gap: 20px;">';
while ($query->have_posts()) {
$query->the_post();
$funktion = get_post_meta(get_the_ID(), '_teamcard_funktion', true);
$zustaendigkeit = get_post_meta(get_the_ID(), '_teamcard_zustaendigkeit', true);
$bild_id = get_post_meta(get_the_ID(), '_teamcard_bild_id', true);
$bild_url = $bild_id ? wp_get_attachment_url($bild_id) : '';
echo '<div class="teamcard" style="display: flex; flex-wrap: wrap; border:1px solid #ccc; border-radius:10px; padding:15px; width:48%; align-items: center;">';
// Bild links
if ($bild_url) {
echo '<div style="flex: 1; text-align: center; display: flex; justify-content: center; align-items: center; margin-right: 10px;">';
echo '<img src="' . esc_url($bild_url) . '" style="max-width:100px; border-radius:50%; margin-bottom:0;">';
echo '</div>';
}
// Text rechts
echo '<div style="flex: 2; padding-left: 10px;">';
echo '<h3>' . get_the_title() . '</h3>';
echo '<p><strong>' . esc_html($funktion) . '</strong></p>';
echo '<p>' . esc_html($zustaendigkeit) . '</p>';
echo '</div>';
echo '</div>'; // Schließt die Teamcard-Div
}
echo '</div>'; // Schließt die Teamcard-Grid-Div
wp_reset_postdata();
return ob_get_clean();
}
add_shortcode('teamcards', 'teamcard_shortcode');