Compare commits

..

13 Commits

Author SHA1 Message Date
ProgrammGamer
59e52faf1b test: node runner image
Some checks failed
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Failing after 12s
2026-01-30 18:10:23 +01:00
ProgrammGamer
61d2a0398e test: node runner image 2026-01-30 18:09:58 +01:00
ProgrammGamer
deab49ce94 test: runner persistence fixed
Some checks failed
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Failing after 1s
2026-01-30 18:06:48 +01:00
ProgrammGamer
f216c558c3 css
Some checks failed
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Failing after 12s
2026-01-30 17:51:13 +01:00
ProgrammGamer
6203a74a2d reorder css
Some checks failed
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Has been cancelled
2026-01-30 17:41:56 +01:00
ProgrammGamer
7e661c4a58 add deployment
Some checks failed
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Has been cancelled
2026-01-30 17:31:00 +01:00
ProgrammGamer
306868735c deleted 2026-01-30 17:27:43 +01:00
ProgrammGamer
e57ac1bd6d gesperte Wahl angepasst 2026-01-30 17:12:12 +01:00
ProgrammGamer
7a45a78753 Ich habe im Frondend die Ergebniss anzeifge verbessert 2026-01-30 17:08:58 +01:00
ProgrammGamer
440956320d adding encryption to form and addid form checks 2026-01-30 17:00:32 +01:00
ProgrammGamer
5942fe7e18 generated importent files 2026-01-30 16:33:09 +01:00
ProgrammGamer
80cf6539ed replacing of header 2026-01-30 15:54:15 +01:00
ProgrammGamer
0c35946b58 Adding plugin header for Workshop-Wahlen 2026-01-30 15:52:55 +01:00
12 changed files with 542 additions and 476 deletions

View File

@@ -0,0 +1,49 @@
name: Deploy Workshop-Wahlen (DEV / PROD)
on:
push:
branches:
- develop
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
# DEV
- name: Deploy to DEV
if: github.ref == 'refs/heads/develop'
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SFTP_HOST }}
port: ${{ secrets.SFTP_PORT }}
username: ${{ secrets.SFTP_USER }}
password: ${{ secrets.SFTP_PASS }}
source: |
assets
includes
*.php
README.md
target: "/dev.konfi-castle.com/wp-content/plugins/konficastle-workshopwahl/"
rm: true
# PROD
- name: Deploy to PROD
if: github.ref == 'refs/heads/main'
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SFTP_HOST }}
port: ${{ secrets.SFTP_PORT }}
username: ${{ secrets.SFTP_USER }}
password: ${{ secrets.SFTP_PASS }}
source: |
assets
includes
*.php
README.md
target: "/httpdocs/wp-content/plugins/konficastle-workshopwahl/"
rm: true

View File

@@ -1,37 +0,0 @@
# Copilot Instructions for Workshop-Wahlen (Production)
## Project Overview
This WordPress plugin manages workshop elections for Konfi-Castle events. It provides an admin backend (elections, workshops, participants, teamers, assignments) and a participant frontend.
## Architecture & Components
- **Main file:** `konficastle-workshopwahl.php` Initializes hooks, loads assets, admin menus.
- **Backend:**
- `includes/` with modules for elections, workshops, participants, teamers, assignments, data management, force assignment
- Core assignment logic: `includes/zuteilungslogik.php`
- **Frontend:**
- Shortcodes: `[konficastle_workshopwahl wahl=ID]`, `[konficastle_workshop_ergebnis wahl=ID]`
- **Database:** Tables are created via `install.php`, prefix: `kc_`
## Key Patterns & Workflows
- **Admin tabs:** Navigation via `kc_admin_tabs()`
- **Naming:** Functions and tables use `kc_` prefix
- **Force assignments:** Manual assignments take precedence
- **Test data:** Only user ID 1 can generate via admin (`admin-data.php`)
- **CSV export:** Possible via admin assignments
- **Teamer password:** Managed via admin, hash in WP options
## Examples & Entry Points
- **Admin menu:** `konficastle-workshopwahl.php`, `includes/admin-wahlen.php`
- **Assignment logic:** `includes/zuteilungslogik.php`
- **Frontend form:** `includes/frontend-form.php`
## Notes for AI Agents
- Always use `$wpdb->prefix` for DB tables
- Backend logic is modular, each entity has its own file
- No complex JS logic in frontend, validation is server-side
- For changes to assignment logic: use test scenarios via test data admin page
---
See README.md for further details.

View File

@@ -1,4 +1,4 @@
# Workshop-Wahlen # Workshop-Wahlen Entwickler-Übersicht
## Überblick ## Überblick

60
assets/frontend-form.js Normal file
View File

@@ -0,0 +1,60 @@
// Client-side validation for Workshopwahl frontend form
// This script validates required fields and email format before submission
document.addEventListener('DOMContentLoaded', function () {
var form = document.querySelector('.kc-workshopwahl-form');
if (!form) return;
form.addEventListener('submit', function (e) {
var valid = true;
var errorMessages = [];
// Example: Validate required text fields
var requiredFields = form.querySelectorAll('[required]');
requiredFields.forEach(function (field) {
if (!field.value.trim()) {
valid = false;
errorMessages.push(field.getAttribute('data-label') || field.name + ' ist erforderlich.');
field.classList.add('kc-field-error');
} else {
field.classList.remove('kc-field-error');
}
});
// Example: Validate email format
var emailField = form.querySelector('input[type="email"]');
if (emailField && emailField.value) {
var emailPattern = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
if (!emailPattern.test(emailField.value)) {
valid = false;
errorMessages.push('Bitte eine gültige E-Mail-Adresse eingeben.');
emailField.classList.add('kc-field-error');
} else {
emailField.classList.remove('kc-field-error');
}
}
// Example: Validate max workshop selections (if relevant)
var maxWorkshops = parseInt(form.getAttribute('data-max-workshops'), 10);
if (maxWorkshops) {
var checked = form.querySelectorAll('input[type="checkbox"][name^="workshop_"]:checked');
if (checked.length > maxWorkshops) {
valid = false;
errorMessages.push('Es dürfen maximal ' + maxWorkshops + ' Workshops gewählt werden.');
}
}
// Show error messages
var errorBox = form.querySelector('.kc-form-errors');
if (!errorBox) {
errorBox = document.createElement('div');
errorBox.className = 'kc-form-errors';
form.prepend(errorBox);
}
errorBox.innerHTML = errorMessages.length ? '<ul><li>' + errorMessages.join('</li><li>') + '</li></ul>' : '';
if (!valid) {
e.preventDefault();
}
});
});

View File

@@ -1,104 +1,121 @@
.kc-form-container { .kc-form-container {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
max-width: 680px; max-width: 680px;
margin: 28px auto; margin: 28px auto;
background: #f8fbe7; background: #f8fbe7;
border-left: 8px solid #b6d333; border-left: 8px solid #b6d333;
border-radius: 14px; border-radius: 14px;
box-shadow: 0 5px 22px #8eae291a; box-shadow: 0 5px 22px #8eae291a;
padding: 28px 22px; padding: 28px 22px;
font-family: 'Segoe UI', Arial, sans-serif; font-family: 'Segoe UI', Arial, sans-serif;
} }
.kc-form-container h2 { .kc-form-container h2 {
color: #3b5323; color: #3b5323;
font-family: 'Montserrat', Arial, sans-serif; font-family: 'Montserrat', Arial, sans-serif;
font-size: 2em; font-size: 2em;
margin-top: 0; margin-top: 0;
margin-bottom: 0.5em; margin-bottom: 0.5em;
letter-spacing: -1px; letter-spacing: -1px;
} }
.kc-form-row { .kc-form-row {
margin-bottom: 22px; margin-bottom: 22px;
} }
.kc-form-row label { .kc-form-row label {
display: block; display: block;
font-weight: 700; font-weight: 700;
color: #1c3866; color: #1c3866;
margin-bottom: 7px; margin-bottom: 7px;
font-size: 1.07em; font-size: 1.07em;
} }
.kc-form-row select, .kc-form-row select,
.kc-form-row input[type="text"], .kc-form-row input[type="text"],
.kc-form-row input[type="email"], .kc-form-row input[type="email"],
.kc-form-row input[type="number"] { .kc-form-row input[type="number"] {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
padding: 10px; padding: 10px;
border: 1.7px solid #d6e39f; border: 1.7px solid #d6e39f;
border-radius: 5px; border-radius: 5px;
background: #fcffe9; background: #fcffe9;
font-size: 1.09em; font-size: 1.09em;
margin-top: 3px; margin-top: 3px;
transition: border .2s; transition: border .2s;
} }
.kc-form-row input[type="text"]:focus, .kc-form-row input[type="text"]:focus,
.kc-form-row select:focus { .kc-form-row select:focus {
outline: none; outline: none;
border-color: #b6d333; border-color: #b6d333;
background: #fffde8; background: #fffde8;
} }
.kc-form-row input[type="submit"] { .kc-form-row input[type="submit"] {
background: #2f5393; background: #2f5393;
color: #fff; color: #fff;
padding: 13px 28px; padding: 13px 28px;
font-weight: bold; font-weight: bold;
font-size: 1.13em; font-size: 1.13em;
border: 0; border: 0;
border-radius: 7px; border-radius: 7px;
cursor: pointer; cursor: pointer;
margin-top: 6px; margin-top: 6px;
box-shadow: 0 2px 8px #1c38661a; box-shadow: 0 2px 8px #1c38661a;
transition: background .2s; transition: background .2s;
} }
.kc-form-row input[type="submit"]:hover { .kc-form-row input[type="submit"]:hover {
background: #1c3866; background: #1c3866;
} }
.kc-required { .kc-required {
color: #e42626; color: #e42626;
font-weight: bold; font-weight: bold;
} }
.kc-success-msg { .kc-success-msg {
color: #288830; color: #288830;
background: #f2fbe2; background: #f2fbe2;
border-left: 4px solid #b6d333; border-left: 4px solid #b6d333;
padding: 15px 15px 15px 22px; padding: 15px 15px 15px 22px;
margin-bottom: 25px; margin-bottom: 25px;
font-size: 1.1em; font-size: 1.1em;
border-radius: 7px; border-radius: 7px;
} }
.kc-error-msg { .kc-error-msg {
color: #a80000; color: #a80000;
background: #ffeaea; background: #ffeaea;
border-left: 4px solid #e12b2b; border-left: 4px solid #e12b2b;
padding: 15px 15px 15px 22px; padding: 15px 15px 15px 22px;
margin-bottom: 25px; margin-bottom: 25px;
font-size: 1.1em; font-size: 1.1em;
border-radius: 7px; border-radius: 7px;
} }
@media (max-width: 900px) { @media (max-width: 900px) {
.kc-form-container {padding:20px 14px;} .kc-form-container {padding:20px 14px;}
} }
@media (max-width: 520px) { @media (max-width: 520px) {
.kc-form-container {padding:14px 10px;border-radius:10px;margin:14px 10px;} .kc-form-container {padding:14px 10px;border-radius:10px;margin:14px 10px;}
.kc-form-container h2 {font-size:1.4em} .kc-form-container h2 {font-size:1.4em}
.kc-form-row {margin-bottom:14px} .kc-form-row {margin-bottom:14px}
} }
.kc-result{font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;color:#222;}
.kc-result h3{margin-top:0;text-align:center;color:#154a3b;}
.kc-phase{margin:18px 0;padding:12px;border-radius:12px;background:#fbfffe;border:1px solid #e6f3ee;}
.kc-result .kc-inner { max-width:1100px; margin:0 auto; padding:0 14px; box-sizing:border-box; }
.kc-workshops-grid{display:grid;grid-template-columns:repeat(auto-fit, minmax(260px, 1fr));gap:14px;margin-top:12px;align-items:start;}
.kc-workshop-card{background:#ffffff;border-radius:12px;overflow:hidden;border:1px solid #e9f4f0;box-shadow:0 2px 6px rgba(8,38,28,0.04);width:100%;}
.kc-workshop-card .title{background:linear-gradient(90deg, rgba(45,166,106,0.04), rgba(13,89,71,0.02));display:flex;flex-wrap:wrap;align-items:center;justify-content:center;padding:18px 12px;font-weight:800;color:#0d5947;font-size:1.06rem;letter-spacing:0.2px;border-bottom:1px solid rgba(229,244,240,0.8);gap:12px;}
.kc-workshop-card .title .count{color:#6b6b6b;font-weight:600;font-size:0.9rem;margin-left:6px;}
.kc-workshop-card .title .teamers{font-weight:600;color:#145a47;font-size:0.9rem;opacity:0.92;}
.kc-workshop-card .title .teamers small{font-weight:500;color:#4c7a6a;opacity:0.9;font-size:0.85rem;margin-left:6px;}
.kc-workshop-card .content{padding:12px 18px 18px 18px;}
.kc-participants{display:grid;grid-template-columns:1fr 1fr;gap:6px 12px;font-size:0.95rem;color:#2b2b2b;}
.kc-participant{padding:6px 8px;border-radius:6px;background:transparent;}
.kc-participant.me{background:#fffbe6;border:1px solid #ffeab2;}
.kc-notassigned{background:#fff6f6;border:1px solid #ffd2d2;padding:12px;border-radius:10px;margin-top:12px;}
@media(max-width:700px){ .kc-participants{grid-template-columns:1fr;} }

View File

@@ -1,203 +1,205 @@
.kc-admin-tabs { .kc-admin-tabs {
margin-bottom: 28px; margin-bottom: 28px;
border-bottom: 2px solid #e0e6ef; border-bottom: 2px solid #e0e6ef;
background: #f8fbe7; background: #f8fbe7;
border-radius: 18px 18px 0 0; border-radius: 18px 18px 0 0;
box-shadow: 0 1px 10px #b6d33321; box-shadow: 0 1px 10px #b6d33321;
padding: 8px 18px 0 18px; padding: 8px 18px 0 18px;
} }
.kc-tabnav { .kc-tabnav {
display: inline-block; display: inline-block;
padding: 12px 32px 11px 32px; padding: 12px 32px 11px 32px;
border-radius: 12px 12px 0 0; border-radius: 12px 12px 0 0;
font-weight: 700; font-weight: 700;
font-size: 1.12em; font-size: 1.12em;
margin-right: 7px; margin-right: 7px;
box-shadow: 0 2px 11px #b6d33318; box-shadow: 0 2px 11px #b6d33318;
text-decoration: none; text-decoration: none;
background: #f8fbe7; background: #f8fbe7;
color: #4176be; color: #4176be;
border: none; border: none;
outline: none; outline: none;
transition: all .18s; transition: all .18s;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
.kc-tabnav-active, .kc-tabnav-active,
.kc-tabnav:focus, .kc-tabnav:focus,
.kc-tabnav:hover { .kc-tabnav:hover {
background: linear-gradient(90deg, #326dd2 0%, #b6d333 100%); background: linear-gradient(90deg, #326dd2 0%, #b6d333 100%);
color: #fff !important; color: #fff !important;
box-shadow: 0 6px 24px #326dd241; box-shadow: 0 6px 24px #326dd241;
font-weight: 800; font-weight: 800;
letter-spacing: 1px; letter-spacing: 1px;
} }
.kc-admin-table-wrap { .kc-admin-table-wrap {
box-sizing: border-box; box-sizing: border-box;
background: #fff; background: #fff;
border-radius: 17px; border-radius: 17px;
box-shadow: 0 4px 28px #326dd21c, 0 1.5px 7px #b6d33324; box-shadow: 0 4px 28px #326dd21c, 0 1.5px 7px #b6d33324;
padding: 28px 22px 30px 22px; padding: 28px 22px 30px 22px;
margin: 28px 0; margin: 28px 0;
/* allow children to overflow (tables may scroll), don't clip action buttons */ /* allow children to overflow (tables may scroll), don't clip action buttons */
overflow: visible; overflow: visible;
} }
/* Collapsible details styling for admin Zuteilungen */ /* Collapsible details styling for admin Zuteilungen */
details.kc-wahl-details, details.kc-phase-details { details.kc-wahl-details, details.kc-phase-details {
background: #fff; background: #fff;
border: 1px solid #e9eef6; border: 1px solid #e9eef6;
border-radius: 10px; border-radius: 10px;
padding: 8px; padding: 8px;
margin-bottom: 12px; margin-bottom: 12px;
} }
details.kc-wahl-details > summary, details.kc-phase-details > summary { details.kc-wahl-details > summary, details.kc-phase-details > summary {
list-style: none; list-style: none;
cursor: pointer; cursor: pointer;
padding: 8px 10px; padding: 8px 10px;
} }
details.kc-wahl-details[open] > summary, details.kc-phase-details[open] > summary { details.kc-wahl-details[open] > summary, details.kc-phase-details[open] > summary {
background: linear-gradient(90deg,#f2f9ff 0%, #f6fff5 100%); background: linear-gradient(90deg,#f2f9ff 0%, #f6fff5 100%);
border-radius: 8px; border-radius: 8px;
} }
/* Wahl summary layout */ /* Wahl summary layout */
details.kc-wahl-details > summary { display: flex; align-items: center; justify-content: space-between; } details.kc-wahl-details > summary { display: flex; align-items: center; justify-content: space-between; }
details.kc-wahl-details > summary .kc-wahl-title { font-weight:700; color:#2b5f9a; } details.kc-wahl-details > summary .kc-wahl-title { font-weight:700; color:#2b5f9a; }
details.kc-wahl-details > summary .kc-wahl-actions { margin-left: 12px; } details.kc-wahl-details > summary .kc-wahl-actions { margin-left: 12px; }
details.kc-wahl-details .kc-wahl-actions .kc-btn { margin-left:8px; } details.kc-wahl-details .kc-wahl-actions .kc-btn { margin-left:8px; }
/* Workshop card inside phase */ /* Workshop card inside phase */
.kc-workshop-card { .kc-workshop-card {
background: #f9f9f9; background: #f9f9f9;
padding: 10px; padding: 10px;
margin: 8px 0; margin: 8px 0;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 1px 6px #00000012; box-shadow: 0 1px 6px #00000012;
} }
.kc-workshop-card table { margin-top:8px; } .kc-workshop-card table { margin-top:8px; }
.kc-workshop-card b { font-size: 1.05em; } .kc-workshop-card b { font-size: 1.05em; }
.kc-workshop-card .kc-count { color:#555; font-size:0.92em; } .kc-workshop-card .kc-count { color:#555; font-size:0.92em; }
.kc-unassigned { .kc-unassigned {
background: #fff6f6; background: #fff6f6;
border-left: 4px solid #f2b0b0; border-left: 4px solid #f2b0b0;
padding: 10px; padding: 10px;
margin-top: 8px; margin-top: 8px;
border-radius: 6px; border-radius: 6px;
} }
/* Smaller tweaks for details summaries inside admin area */ /* Smaller tweaks for details summaries inside admin area */
details summary { outline: none; } details summary { outline: none; }
details summary::-webkit-details-marker { display: none; } details summary::-webkit-details-marker { display: none; }
details summary:before { content: '\25B6'; display:inline-block; transform:rotate(90deg); margin-right:8px; } details summary:before { content: '\25B6'; display:inline-block; transform:rotate(90deg); margin-right:8px; }
details[open] summary:before { transform: rotate(0deg); } details[open] summary:before { transform: rotate(0deg); }
.kc-admin-table { .kc-admin-table {
width: 100%; width: 100%;
border-collapse: separate; border-collapse: separate;
border-spacing: 0; border-spacing: 0;
margin-bottom: 28px; margin-bottom: 28px;
background: #fafdff; background: #fafdff;
border-radius: 13px; border-radius: 13px;
overflow: auto; /* horizontal scroll on small screens */ overflow: auto; /* horizontal scroll on small screens */
box-shadow: 0 2px 12px #b6d33313; box-shadow: 0 2px 12px #b6d33313;
} }
.kc-admin-table th, .kc-admin-table td { .kc-admin-table th, .kc-admin-table td {
padding: 13px 18px; padding: 13px 18px;
text-align: left; text-align: left;
font-size: 1.07em; font-size: 1.07em;
vertical-align: middle; vertical-align: middle;
} }
.kc-admin-table thead { .kc-admin-table thead {
background: #eaf6ff; background: #eaf6ff;
color: #4176be; color: #4176be;
font-weight: 800; font-weight: 800;
} }
.kc-admin-table tbody tr { .kc-admin-table tbody tr {
border-bottom: 1px solid #eef3fa; border-bottom: 1px solid #eef3fa;
} }
.kc-admin-table tbody tr:nth-child(even) { .kc-admin-table tbody tr:nth-child(even) {
background: #f8fbe7; background: #f8fbe7;
} }
.kc-admin-table tbody tr:hover { .kc-admin-table tbody tr:hover {
background: #e0ebf6; background: #e0ebf6;
transition: background 0.2s; transition: background 0.2s;
} }
.kc-admin-table th { .kc-admin-table th {
font-weight: bold; font-weight: bold;
border-bottom: 2px solid #b6d33342; border-bottom: 2px solid #b6d33342;
} }
.kc-admin-table .kc-actions { .kc-admin-table .kc-actions {
white-space: nowrap; white-space: nowrap;
display: flex; display: flex;
gap: 8px; gap: 8px;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
flex-wrap: wrap; /* allow buttons to wrap on very small widths */ flex-wrap: wrap; /* allow buttons to wrap on very small widths */
} }
.kc-btn { .kc-btn {
background: linear-gradient(90deg,#4176be 40%, #b6d333 100%); background: linear-gradient(90deg,#4176be 40%, #b6d333 100%);
color: #fff; color: #fff;
padding: 10px 25px; padding: 10px 25px;
border-radius: 8px; border-radius: 8px;
border: 0; border: 0;
margin: 0 5px; margin: 0 5px;
font-weight: 700; font-weight: 700;
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
text-decoration: none; text-decoration: none;
font-size: 1.04em; font-size: 1.04em;
box-shadow: 0 1.5px 6px #b6d33321; box-shadow: 0 1.5px 6px #b6d33321;
transition: background .17s, box-shadow .19s; transition: background .17s, box-shadow .19s;
} }
.kc-btn.del { .kc-btn.del {
background: #e12b2b !important; background: #e12b2b !important;
color: #fff; color: #fff;
} }
.kc-btn.edit { .kc-btn.edit {
background: #ff9800 !important; background: #ff9800 !important;
color: #fff; color: #fff;
} }
.kc-btn:hover { .kc-btn:hover {
opacity: 0.91; opacity: 0.91;
background: linear-gradient(90deg,#26529e 40%, #97b321 100%); background: linear-gradient(90deg,#26529e 40%, #97b321 100%);
color: #fff; color: #fff;
box-shadow: 0 3px 10px #4176be29; box-shadow: 0 3px 10px #4176be29;
} }
.notice-success { .notice-success {
background: #f6ffed; background: #f6ffed;
border-left: 6px solid #b6d333; border-left: 6px solid #b6d333;
color: #1c5322; color: #1c5322;
padding: 13px 20px; padding: 13px 20px;
margin: 0 0 22px 0; margin: 0 0 22px 0;
border-radius: 9px; border-radius: 9px;
font-size: 1.08em; font-size: 1.08em;
font-weight: 500; font-weight: 500;
} }
.notice-error { .notice-error {
background: #fff3f3; background: #fff3f3;
border-left: 6px solid #e12b2b; border-left: 6px solid #e12b2b;
color: #9d1d2e; color: #9d1d2e;
padding: 13px 20px; padding: 13px 20px;
margin: 0 0 22px 0; margin: 0 0 22px 0;
border-radius: 9px; border-radius: 9px;
font-size: 1.08em; font-size: 1.08em;
font-weight: 500; font-weight: 500;
} }
.kc-required { .kc-required {
color: #e42626; color: #e42626;
font-weight: bold; font-weight: bold;
margin-left: 2px; margin-left: 2px;
} }
@media (max-width: 800px) { .kc-wahl-filter-btn.active{background:#4CAF50;color:#fff;}
.kc-admin-table-wrap {padding: 12px;} .kc-phase-filter-btn.active{background:#1976d2;color:#fff;}
.kc-admin-table th, .kc-admin-table td {padding: 8px 6px;} @media (max-width: 800px) {
.kc-btn {padding: 8px 13px;} .kc-admin-table-wrap {padding: 12px;}
} .kc-admin-table th, .kc-admin-table td {padding: 8px 6px;}
.kc-btn {padding: 8px 13px;}
@media (max-width: 600px) { }
/* Make tables readable on mobile by switching to block rows */
.kc-admin-table thead { display: none; } @media (max-width: 600px) {
.kc-admin-table, .kc-admin-table tbody, .kc-admin-table tr, .kc-admin-table td { display: block; width: 100%; } /* Make tables readable on mobile by switching to block rows */
.kc-admin-table tr { margin-bottom: 12px; border-bottom: 1px solid #eef3fa; } .kc-admin-table thead { display: none; }
.kc-admin-table td { text-align: left; padding: 10px 12px; white-space: normal; } .kc-admin-table, .kc-admin-table tbody, .kc-admin-table tr, .kc-admin-table td { display: block; width: 100%; }
.kc-admin-table td:before { content: attr(data-label); font-weight:700; display:block; margin-bottom:6px; color:#4176be; } .kc-admin-table tr { margin-bottom: 12px; border-bottom: 1px solid #eef3fa; }
} .kc-admin-table td { text-align: left; padding: 10px 12px; white-space: normal; }
.kc-admin-table td:before { content: attr(data-label); font-weight:700; display:block; margin-bottom:6px; color:#4176be; }
}

View File

@@ -14,8 +14,10 @@ function kc_teamer_page() {
delete_option('kc_teamer_password_hash'); delete_option('kc_teamer_password_hash');
echo '<div class="notice notice-success">Teamer-Passwort entfernt.</div>'; echo '<div class="notice notice-success">Teamer-Passwort entfernt.</div>';
} else { } else {
update_option('kc_teamer_password_hash', wp_hash_password($pw)); // Sichere Speicherung mit password_hash
echo '<div class="notice notice-success">Teamer-Passwort gespeichert.</div>'; $hash = password_hash($pw, PASSWORD_DEFAULT);
update_option('kc_teamer_password_hash', $hash);
echo '<div class="notice notice-success">Teamer-Passwort gespeichert.</div>';
} }
} }
} }

View File

@@ -309,7 +309,7 @@ function kc_teilnehmer_page() {
echo '</details>'; echo '</details>';
} }
// JS für Wahl- und Phasen-Filter // JS für Wahl- und Phasen-Filter
echo '<style>.kc-wahl-filter-btn.active{background:#4CAF50;color:#fff;} .kc-phase-filter-btn.active{background:#1976d2;color:#fff;}</style>'; // CSS moved to admin-teilnehmer.css
echo '<script> echo '<script>
(function() { (function() {
var btns = Array.prototype.slice.call(document.querySelectorAll(".kc-wahl-filter-btn")); var btns = Array.prototype.slice.call(document.querySelectorAll(".kc-wahl-filter-btn"));

View File

@@ -106,28 +106,7 @@ add_shortcode('konficastle_workshop_ergebnis', function($atts) {
ob_start(); ob_start();
// Inline styles, angepasst an konfi-castle.com Look (dezent, grün/türkis Akzent) // Inline styles, angepasst an konfi-castle.com Look (dezent, grün/türkis Akzent)
echo '<style>
.kc-result{font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;color:#222;}
.kc-result h3{margin-top:0;text-align:center;color:#154a3b;}
.kc-phase{margin:18px 0;padding:12px;border-radius:12px;background:#fbfffe;border:1px solid #e6f3ee;}
/* Responsive Kachel-Layout: auto-fit with minmax so cards wrap based on viewport */
.kc-result .kc-inner { max-width:1100px; margin:0 auto; padding:0 14px; box-sizing:border-box; }
.kc-workshops-grid{display:grid;grid-template-columns:repeat(auto-fit, minmax(260px, 1fr));gap:14px;margin-top:12px;align-items:start;}
.kc-workshop-card{background:#ffffff;border-radius:12px;overflow:hidden;border:1px solid #e9f4f0;box-shadow:0 2px 6px rgba(8,38,28,0.04);width:100%;}
/* Zentrierter, prominenter Titelbereich in der Mitte oben der Kachel */
.kc-workshop-card .title{background:linear-gradient(90deg, rgba(45,166,106,0.04), rgba(13,89,71,0.02));display:flex;flex-wrap:wrap;align-items:center;justify-content:center;padding:18px 12px;font-weight:800;color:#0d5947;font-size:1.06rem;letter-spacing:0.2px;border-bottom:1px solid rgba(229,244,240,0.8);gap:12px;}
.kc-workshop-card .title .count{color:#6b6b6b;font-weight:600;font-size:0.9rem;margin-left:6px;}
.kc-workshop-card .title .teamers{font-weight:600;color:#145a47;font-size:0.9rem;opacity:0.92;}
.kc-workshop-card .title .teamers small{font-weight:500;color:#4c7a6a;opacity:0.9;font-size:0.85rem;margin-left:6px;}
/* Content-Bereich unter dem Titel mit etwas mehr Luft */
.kc-workshop-card .content{padding:12px 18px 18px 18px;}
.kc-participants{display:grid;grid-template-columns:1fr 1fr;gap:6px 12px;font-size:0.95rem;color:#2b2b2b;}
.kc-participant{padding:6px 8px;border-radius:6px;background:transparent;}
.kc-participant.me{background:#fffbe6;border:1px solid #ffeab2;}
.kc-notassigned{background:#fff6f6;border:1px solid #ffd2d2;padding:12px;border-radius:10px;margin-top:12px;}
/* Auf sehr kleinen Bildschirmen die Teilnehmer ebenfalls einspaltig */
@media(max-width:700px){ .kc-participants{grid-template-columns:1fr;} }
</style>';
echo '<div class="kc-result">'; echo '<div class="kc-result">';
echo '<h3>Ergebnis für diese Wahl</h3>'; echo '<h3>Ergebnis für diese Wahl</h3>';
@@ -209,8 +188,8 @@ add_shortcode('konficastle_workshop_ergebnis', function($atts) {
foreach($teilnehmer as $t) { foreach($teilnehmer as $t) {
$is_me = in_array(intval($t->id), $my_ids); $is_me = in_array(intval($t->id), $my_ids);
$name = esc_html($t->vorname.' '.$t->nachname); $name = esc_html($t->vorname.' '.$t->nachname);
$label = $name . ' <span style="color:#6b6b6b;font-size:85%;">('.intval($t->phase).')</span>'; $label = $name . ' <span style="color:#6b6b6b;font-size:85%;white-space:nowrap;">' . intval($t->phase) . '</span>';
echo '<div class="kc-participant'.($is_me ? ' me' : '').'">'. $label .'</div>'; echo '<div class="kc-participant'.($is_me ? ' me' : '').'" style="white-space:nowrap;">'. $label .'</div>';
} }
echo '</div>'; // kc-participants echo '</div>'; // kc-participants
echo '</div>'; // content echo '</div>'; // content
@@ -225,11 +204,11 @@ add_shortcode('konficastle_workshop_ergebnis', function($atts) {
if (!empty($nicht_zugeteilt)) { if (!empty($nicht_zugeteilt)) {
echo '<div class="kc-notassigned">'; echo '<div class="kc-notassigned">';
echo '<b>Nicht zugeteilt:</b><br>'; echo '<b>Nicht zugeteilt:</b><br>';
echo '<ul style="margin:6px 0 0 18px;">'; echo '<div style="margin:6px 0 0 18px;">';
foreach($nicht_zugeteilt as $t) { foreach($nicht_zugeteilt as $t) {
echo '<li>'.esc_html($t->vorname.' '.$t->nachname).' (Phase '.intval($t->phase).')</li>'; echo '<span style="display:inline-block;white-space:nowrap;margin-right:12px;">'.esc_html($t->vorname.' '.$t->nachname).' <span style="color:#6b6b6b;font-size:85%;">'.intval($t->phase).'</span></span>';
} }
echo '</ul></div>'; echo '</div></div>';
} }
echo '</div>'; // kc-result echo '</div>'; // kc-result

View File

@@ -16,7 +16,7 @@ add_shortcode('konficastle_workshopwahl', function($atts) {
$wahl = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}kc_wahlen WHERE id=%d", $wahl_id)); $wahl = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}kc_wahlen WHERE id=%d", $wahl_id));
if(!$wahl || !$wahl->freigegeben) { if(!$wahl || !$wahl->freigegeben) {
return $debug_output . '<div class="kc-error-msg">Die Workshopwahl ist aktuell nicht freigeschaltet.</div>'; return $debug_output . '<div"></div>';
} }
// Ermittle erlaubte Workshops pro Phase für diese Wahl. // Ermittle erlaubte Workshops pro Phase für diese Wahl.
@@ -152,26 +152,7 @@ add_shortcode('konficastle_workshopwahl', function($atts) {
ob_start(); ob_start();
?> ?>
<style>
.kc-form-container {background:#f8fbe7; border-left:8px solid #b6d333; max-width:600px; margin:40px auto; padding:32px 28px; border-radius:14px; box-shadow:0 2px 8px #b6d33322;}
.kc-form-container h2 {margin-top:0; font-size:2em; font-weight:700;}
.kc-form-container label {font-weight:600;}
.kc-form-row {margin-bottom:20px;}
.kc-form-row input[type="text"], .kc-form-row select {
width:100%; padding:10px 12px; border-radius:7px; border:1.2px solid #aac484; background:#fafcf6; font-size:1.09em;
transition:border 0.17s;
}
.kc-form-row input[type="text"]:focus, .kc-form-row select:focus {border:1.8px solid #b6d333;}
.kc-form-row input[type="submit"] {
background:#326dd2; color:#fff; font-weight:600; font-size:1.15em;
padding:11px 30px; border:0; border-radius:8px; cursor:pointer; margin-top:5px; box-shadow:0 2px 6px #aac48422;
}
.kc-form-row input[type="submit"]:hover {background:#2559a2;}
.kc-required {color:#d82626; font-weight:bold;}
.kc-success-msg {color:#21952c; background:#e3f7e4; padding:16px 20px; border-radius:8px; font-weight:600; margin-bottom:15px; text-align:center;}
.kc-error-msg {color:#a80000; background:#ffeaea; padding:16px 20px; border-radius:8px; font-weight:600; margin-bottom:15px; text-align:center;}
@media (max-width: 700px) {.kc-form-container {padding:17px 7px;}}
</style>
<?php echo $debug_output; ?> <?php echo $debug_output; ?>

View File

@@ -8,12 +8,12 @@ function kc_install_tables() {
global $wpdb; global $wpdb;
$prefix = $wpdb->prefix; $prefix = $wpdb->prefix;
$charset_collate = $wpdb->get_charset_collate(); $charset_collate = $wpdb->get_charset_collate();
require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
// Tables definitions // --- Tabellen-Definitionen ---
$tables_sql = []; $tables_sql = [];
// Wahl-Tabelle
$tables_sql[] = "CREATE TABLE {$prefix}kc_wahlen ( $tables_sql[] = "CREATE TABLE {$prefix}kc_wahlen (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT, id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
name varchar(191) NOT NULL, name varchar(191) NOT NULL,
@@ -26,6 +26,7 @@ function kc_install_tables() {
PRIMARY KEY (id) PRIMARY KEY (id)
) $charset_collate"; ) $charset_collate";
// Workshop-Tabelle
$tables_sql[] = "CREATE TABLE {$prefix}kc_workshops ( $tables_sql[] = "CREATE TABLE {$prefix}kc_workshops (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT, id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
name varchar(191) NOT NULL, name varchar(191) NOT NULL,
@@ -35,6 +36,7 @@ function kc_install_tables() {
PRIMARY KEY (id) PRIMARY KEY (id)
) $charset_collate"; ) $charset_collate";
// Teamer-Tabelle
$tables_sql[] = "CREATE TABLE {$prefix}kc_teamer ( $tables_sql[] = "CREATE TABLE {$prefix}kc_teamer (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT, id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
vorname varchar(191) DEFAULT NULL, vorname varchar(191) DEFAULT NULL,
@@ -42,6 +44,7 @@ function kc_install_tables() {
PRIMARY KEY (id) PRIMARY KEY (id)
) $charset_collate"; ) $charset_collate";
// Teilnehmer-Tabelle
$tables_sql[] = "CREATE TABLE {$prefix}kc_teilnehmer ( $tables_sql[] = "CREATE TABLE {$prefix}kc_teilnehmer (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT, id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
vorname varchar(191) DEFAULT NULL, vorname varchar(191) DEFAULT NULL,
@@ -51,10 +54,11 @@ function kc_install_tables() {
wunsch1 bigint(20) unsigned DEFAULT NULL, wunsch1 bigint(20) unsigned DEFAULT NULL,
wunsch2 bigint(20) unsigned DEFAULT NULL, wunsch2 bigint(20) unsigned DEFAULT NULL,
wunsch3 bigint(20) unsigned DEFAULT NULL, wunsch3 bigint(20) unsigned DEFAULT NULL,
deleted tinyint(1) NOT NULL DEFAULT 0, deleted tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (id) PRIMARY KEY (id)
) $charset_collate"; ) $charset_collate";
// Zuordnungstabelle Wahl <-> Workshops
$tables_sql[] = "CREATE TABLE {$prefix}kc_wahl_workshops ( $tables_sql[] = "CREATE TABLE {$prefix}kc_wahl_workshops (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT, id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
wahl_id bigint(20) unsigned NOT NULL DEFAULT 0, wahl_id bigint(20) unsigned NOT NULL DEFAULT 0,
@@ -63,6 +67,7 @@ function kc_install_tables() {
PRIMARY KEY (id) PRIMARY KEY (id)
) $charset_collate"; ) $charset_collate";
// Manuelle (Force-)Zuteilungen
$tables_sql[] = "CREATE TABLE {$prefix}kc_force_zuteilung ( $tables_sql[] = "CREATE TABLE {$prefix}kc_force_zuteilung (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT, id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
teilnehmer_id bigint(20) unsigned NOT NULL DEFAULT 0, teilnehmer_id bigint(20) unsigned NOT NULL DEFAULT 0,
@@ -73,6 +78,7 @@ function kc_install_tables() {
PRIMARY KEY (id) PRIMARY KEY (id)
) $charset_collate"; ) $charset_collate";
// Ergebnis-Zuteilungen
$tables_sql[] = "CREATE TABLE {$prefix}kc_zuteilung ( $tables_sql[] = "CREATE TABLE {$prefix}kc_zuteilung (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT, id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
teilnehmer_id bigint(20) unsigned NOT NULL DEFAULT 0, teilnehmer_id bigint(20) unsigned NOT NULL DEFAULT 0,
@@ -84,26 +90,27 @@ function kc_install_tables() {
wunsch_rang tinyint DEFAULT NULL, wunsch_rang tinyint DEFAULT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
) $charset_collate"; ) $charset_collate";
$tables_sql[] = "CREATE TABLE {$prefix}kc_workshop_teamer (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
workshop_id bigint(20) unsigned DEFAULT NULL,
teamer_id bigint(20) unsigned DEFAULT NULL,
PRIMARY KEY (id)
) $charset_collate";
// Zuordnung Workshop <-> Teamer
$tables_sql[] = "CREATE TABLE {$prefix}kc_workshop_teamer (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
workshop_id bigint(20) unsigned DEFAULT NULL,
teamer_id bigint(20) unsigned DEFAULT NULL,
PRIMARY KEY (id)
) $charset_collate";
// Tabellen anlegen
foreach ($tables_sql as $sql) { foreach ($tables_sql as $sql) {
dbDelta($sql); dbDelta($sql);
} }
// Post-creation migration guard: ensure min_teilnehmer exists for older installs // Migration: min_teilnehmer nachziehen, falls bei Update nötig
$col = $wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$prefix}kc_workshops LIKE %s", 'min_teilnehmer')); $col = $wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$prefix}kc_workshops LIKE %s", 'min_teilnehmer'));
if (empty($col)) { if (empty($col)) {
// try to add the column (no-op on newer installs)
$wpdb->query("ALTER TABLE {$prefix}kc_workshops ADD COLUMN min_teilnehmer INT NOT NULL DEFAULT 0"); $wpdb->query("ALTER TABLE {$prefix}kc_workshops ADD COLUMN min_teilnehmer INT NOT NULL DEFAULT 0");
} }
// Optionally store plugin version // Plugin-Version speichern
add_option('kc_workshopwahl_db_version', '1.0'); add_option('kc_workshopwahl_db_version', '1.0');
} }

View File

@@ -1,68 +1,74 @@
<?php <?php
/** /**
* Plugin Name: Workshop-Wahlen * Plugin Name: Workshop-Wahlen
* Description: Workshop-Wahl-System für Konfi-Castle.com * Description: Workshop-Wahl-System für Konfi-Castle.com
* Version: 1.0 * Version: 1.1 - dev
* Author: Linus Maximilian Nilson * Author: Linus Maximilian Nilson
*/ */
if (!defined('ABSPATH')) exit;
if (!defined('ABSPATH')) exit;
// Stylesheet einbinden
add_action('admin_enqueue_scripts', function($hook) { // Stylesheet einbinden
// Nur auf den Plugin-Seiten laden (optional: prüfe $hook!)
if (strpos($hook, 'kc_') !== false) { add_action('admin_enqueue_scripts', function($hook) {
wp_enqueue_style( // Nur auf den Plugin-Seiten laden (optional: prüfe $hook!)
'kc-admin-style', if (strpos($hook, 'kc_') !== false) {
plugin_dir_url(__FILE__) . 'assets/kc-admin-style.css', wp_enqueue_style(
[], 'kc-admin-style',
filemtime(plugin_dir_path(__FILE__) . 'assets/kc-admin-style.css') plugin_dir_url(__FILE__) . 'assets/kc-admin.css',
); [],
} filemtime(plugin_dir_path(__FILE__) . 'assets/kc-admin.css')
}); );
}
});
add_action('admin_enqueue_scripts', function($hook) {
// Nur für unser Plugin-Menü!
if (strpos($hook, 'kc_') === false) return; add_action('admin_enqueue_scripts', function($hook) {
wp_enqueue_script('select2', 'https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js', ['jquery'], null, true); // Nur für unser Plugin-Menü!
wp_enqueue_style('select2', 'https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css'); if (strpos($hook, 'kc_') === false) return;
}); wp_enqueue_script('select2', 'https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js', ['jquery'], null, true);
wp_enqueue_style('select2', 'https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css');
});
add_action('wp_enqueue_scripts', function() {
wp_enqueue_style('kc-workshopwahl-form', plugins_url('assets/frontend-form.css', __FILE__));
});
// Zentrale Admin-Menüstruktur add_action('wp_enqueue_scripts', function() {
add_action('admin_menu', function() { wp_enqueue_style('kc-workshopwahl-frontend', plugins_url('assets/frontend.css', __FILE__));
add_menu_page('Wahlen', 'Wahlen', 'manage_options', 'kc_wahlen', 'kc_wahlen_page'); });
add_submenu_page('kc_wahlen', 'Teamer', 'Teamer', 'manage_options', 'kc_teamer', 'kc_teamer_page');
add_submenu_page('kc_wahlen', 'Workshops', 'Workshops', 'manage_options', 'kc_workshops', 'kc_workshops_page'); // Zentrale Admin-Menüstruktur
add_action('admin_menu', function() {
add_submenu_page('kc_wahlen', 'Teilnehmer', 'Teilnehmer', 'manage_options', 'kc_teilnehmer', 'kc_teilnehmer_page'); add_menu_page('Wahlen', 'Wahlen', 'manage_options', 'kc_wahlen', 'kc_wahlen_page');
add_submenu_page('kc_wahlen', 'Force-Zuteilung', 'Force-Zuteilung', 'manage_options', 'kc_force_zuteilung', 'kc_force_zuteilung_page'); add_submenu_page('kc_wahlen', 'Teamer', 'Teamer', 'manage_options', 'kc_teamer', 'kc_teamer_page');
add_submenu_page('kc_wahlen', 'Zuteilungen', 'Zuteilungen', 'manage_options', 'kc_zuteilungen', 'kc_zuteilungen_page'); add_submenu_page('kc_wahlen', 'Workshops', 'Workshops', 'manage_options', 'kc_workshops', 'kc_workshops_page');
// Data management (test data) - visible only to super-admin (we'll check inside page) add_submenu_page('kc_wahlen', 'Teilnehmer', 'Teilnehmer', 'manage_options', 'kc_teilnehmer', 'kc_teilnehmer_page');
add_submenu_page('kc_wahlen', 'Datenverwaltung', 'Datenverwaltung', 'manage_options', 'kc_data', 'kc_data_page');
add_submenu_page('kc_wahlen', 'Force-Zuteilung', 'Force-Zuteilung', 'manage_options', 'kc_force_zuteilung', 'kc_force_zuteilung_page');
});
add_submenu_page('kc_wahlen', 'Zuteilungen', 'Zuteilungen', 'manage_options', 'kc_zuteilungen', 'kc_zuteilungen_page');
// Includes  jede Admin-Seite ruft oben kc_admin_tabs() auf!
require_once plugin_dir_path(__FILE__).'includes/admin-wahlen.php'; // Data management (test data) - visible only to super-admin (we'll check inside page)
require_once plugin_dir_path(__FILE__).'includes/admin-workshops.php'; add_submenu_page('kc_wahlen', 'Datenverwaltung', 'Datenverwaltung', 'manage_options', 'kc_data', 'kc_data_page');
require_once plugin_dir_path(__FILE__).'includes/admin-teilnehmer.php';
require_once plugin_dir_path(__FILE__).'includes/admin-teamer.php'; });
require_once plugin_dir_path(__FILE__).'includes/force-zuteilung.php';
require_once plugin_dir_path(__FILE__).'includes/admin-zuteilungen.php'; // Includes  jede Admin-Seite ruft oben kc_admin_tabs() auf!
require_once plugin_dir_path(__FILE__).'includes/frontend-form.php'; require_once plugin_dir_path(__FILE__).'includes/admin-wahlen.php';
require_once plugin_dir_path(__FILE__).'includes/frontend-ergebnis.php'; require_once plugin_dir_path(__FILE__).'includes/admin-workshops.php';
require_once plugin_dir_path(__FILE__).'includes/zuteilungslogik.php'; require_once plugin_dir_path(__FILE__).'includes/admin-teilnehmer.php';
require_once plugin_dir_path(__FILE__).'includes/admin-data.php'; require_once plugin_dir_path(__FILE__).'includes/admin-teamer.php';
require_once plugin_dir_path(__FILE__).'includes/force-zuteilung.php';
require_once plugin_dir_path(__FILE__).'includes/admin-zuteilungen.php';
require_once plugin_dir_path(__FILE__).'includes/frontend-form.php';
require_once plugin_dir_path(__FILE__).'includes/frontend-ergebnis.php';
require_once plugin_dir_path(__FILE__).'includes/zuteilungslogik.php';
require_once plugin_dir_path(__FILE__).'includes/admin-data.php';
require_once plugin_dir_path(__FILE__).'install.php'; require_once plugin_dir_path(__FILE__).'install.php';