1. YoureCom
    1. Über mich
  2. Lösungen
    1. Tipprunde
    2. Aufgaben & Support
    3. Mitglieder-Netzwerk
    4. Online-Shop
    5. Alle Lösungen & Preise
  3. Für Admins
    1. Plugins
    2. ByteMon
    3. ByteMon: Community verwalten
    4. ByteMon: Portalidentität
    5. Individuelle Entwicklung
    6. WSC 6.3 Alpha
    7. GitHub
  4. Neuigkeiten
    1. Kurzmeldungen
  5. Support
  6. Mein Konto
  7. Lösungen testen
  • Anmelden
  • Registrieren
  • Warenkorb 0
  • Suche
Alles
  • Alles
  • Artikel
  • Seiten
  • Aufgaben
  • Produkte
  • Pulse-Beiträge
  • Erweiterte Suche
  1. YoureCom – Software für Vereine, Teams & Communities
  2. Repository-Liste
  3. de.yourecom.wcf.api.mpdf

43 Dateien geändert: tests (22), (Hauptordner) (15), .github (5), files (1)

  • Marcel Beckers
  • -4 Löschungen
  • +3.340 Hinzufügungen
  • 3.344 Gesamt
  • 43 Dateien
  • 14. Oktober 2026 um 08:08
  • .github/dependabot.yml
    <pre>@@ -0,0 +1,26 @@
    +# YoureCom Standard: managed by _dev/standard (apply.php), do not edit here.
    +# Major updates of the npm tools are skipped here, they are raised once for all plugins in _dev/standard
    +# (initial/package.json) and the shared ../node_modules. Updates of the GitHub Actions belong into
    +# _dev/standard/managed/.github/workflows as well, a pull request here shows that a new version exists.
    +version: 2
    +updates:
    + - package-ecosystem: github-actions
    + directory: /
    + schedule:
    + interval: monthly
    + groups:
    + actions:
    + patterns:
    + - "*"
    +
    + - package-ecosystem: npm
    + directory: /
    + schedule:
    + interval: monthly
    + ignore:
    + - dependency-name: "*"
    + update-types: ["version-update:semver-major"]
    + groups:
    + dev-tools:
    + patterns:
    + - "*"
  • .github/scripts/build-package.sh
    <pre>@@ -0,0 +1,110 @@
    +#!/usr/bin/env bash
    +# YoureCom Standard: managed by _dev/standard (apply.php), do not edit here.
    +# Builds the installable package (WoltLab format) into the given directory, default: var/package.
    +# Used by the release workflow and locally. Uploading stays a manual step that needs Marcel's approval.
    +#
    +# Usage: bash .github/scripts/build-package.sh [output dir]
    +# Prints the path of the created archive. Locally the archive is also copied to C:\laragon\www\archive\<package>.tar.gz
    +# (override the folder with ARCHIVE_DIR).
    +set -euo pipefail
    +
    +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
    +OUT="${1:-$ROOT/var/package}"
    +STAGE="$OUT/stage"
    +
    +PACKAGE="$(sed -n 's:.*<package name="\([^"]*\)".*:\1:p' "$ROOT/package.xml" | head -1)"
    +VERSION="$(sed -n 's:.*<version>\(.*\)</version>.*:\1:p' "$ROOT/package.xml" | head -1)"
    +[[ -n "$PACKAGE" && -n "$VERSION" ]] || { echo "package.xml has no name or version" >&2; exit 1; }
    +
    +# the package ships the committed JavaScript, nothing compiles it here: a stale or missing build would load fine locally
    +# (deploy.sh compiles into the dev system) and fail on the live site, so stop before packing
    +if [[ -f "$ROOT/tests/lint/check-js-build.mjs" ]]; then
    + (cd "$ROOT" && node tests/lint/check-js-build.mjs) || { echo "the committed JavaScript is out of date, run: npm run build" >&2; exit 1; }
    +fi
    +
    +rm -rf "$STAGE"
    +mkdir -p "$STAGE"
    +
    +# the archives of the file and template PIPs, named as in package.xml (the default names when no name is given)
    +pack() { # pack <source dir> <archive>
    + [[ -d "$ROOT/$1" ]] || return 0
    + (cd "$ROOT/$1" && tar --format=ustar -cf "$STAGE/$2" --exclude='.DS_Store' --exclude='*.orig' --exclude='*.bak' -- *)
    +}
    +pack files files.tar
    +pack files_wcf files_wcf.tar
    +pack templates templates.tar
    +pack acptemplates acptemplates.tar
    +
    +# package.xml, the PIP files and the language files; development files stay outside
    +for FILE in "$ROOT"/*.xml; do
    + case "$(basename "$FILE")" in
    + phpunit*.xml) ;;
    + *) cp "$FILE" "$STAGE/" ;;
    + esac
    +done
    +# packages without phrases (e.g. branding free) have no language folder
    +if [[ -d "$ROOT/language" ]]; then
    + cp -r "$ROOT/language" "$STAGE/language"
    +fi
    +# packages delivered with the plugin (<requiredpackage file="requirements/...">)
    +if [[ -d "$ROOT/requirements" ]]; then
    + cp -r "$ROOT/requirements" "$STAGE/requirements"
    +fi
    +
    +ARCHIVE="$OUT/${PACKAGE}_$(echo "$VERSION" | tr ' ' '_').tar.gz"
    +rm -f "$ARCHIVE"
    +(cd "$STAGE" && tar --format=ustar -czf "$ARCHIVE" -- *)
    +rm -rf "$STAGE"
    +
    +# the archive contains everything package.xml refers to: the named files of the instructions and required packages,
    +# the default files of instructions without a name (file -> files.tar, language -> language/*.xml, <pip> -> <pip>.xml)
    +# and no pax headers (WoltLab reads ustar)
    +CONTENTS="$(tar -tzf "$ARCHIVE")"
    +if grep -q 'PaxHeader' <<< "$CONTENTS"; then
    + echo "the archive contains pax headers" >&2
    + exit 1
    +fi
    +php -r '
    + $contents = array_flip(explode("\n", $argv[2]));
    + $xml = new DOMDocument();
    + $xml->load($argv[1]);
    + $xpath = new DOMXPath($xml);
    + $xpath->registerNamespace("w", "http://www.woltlab.com");
    + $defaults = ["file" => "files.tar", "template" => "templates.tar", "acpTemplate" => "acptemplates.tar"];
    + $missing = [];
    + foreach ($xpath->query("//w:requiredpackage[@file]") as $node) {
    + $missing[] = $node->getAttribute("file");
    + }
    + foreach ($xpath->query("//w:instruction") as $node) {
    + $type = $node->getAttribute("type");
    + $name = trim($node->textContent);
    + if ($name === "") {
    + if ($type === "language") {
    + if (!preg_grep("~^language/\w+\.xml$~", array_keys($contents))) {
    + $missing[] = "language/*.xml";
    + }
    + continue;
    + }
    + $name = $defaults[$type] ?? "{$type}.xml";
    + } elseif (in_array($type, ["script", "database", "sql"], true)) {
    + // these refer to files inside files.tar
    + continue;
    + }
    + $missing[] = $name;
    + }
    + $missing = array_values(array_unique(array_filter($missing, static fn (string $file): bool => !isset($contents[$file]))));
    + if ($missing !== []) {
    + fwrite(STDERR, "package.xml refers to files the archive does not contain: " . implode(", ", $missing) . "\n");
    + exit(1);
    + }
    +' -- "$ROOT/package.xml" "$CONTENTS" || exit 1
    +
    +# local builds: the finished package is also put into the archive folder as <package>.tar.gz, an existing file is
    +# overwritten (the folder does not exist on the CI runner, there the step is skipped)
    +ARCHIVE_DIR="${ARCHIVE_DIR:-/c/laragon/www/archive}"
    +if [[ -d "$ARCHIVE_DIR" ]]; then
    + cp -f "$ARCHIVE" "$ARCHIVE_DIR/$PACKAGE.tar.gz"
    + echo "copied to $ARCHIVE_DIR/$PACKAGE.tar.gz" >&2
    +fi
    +
    +echo "$ARCHIVE"
  • .github/scripts/checkout-dependencies.sh
    <pre>@@ -0,0 +1,28 @@
    +#!/usr/bin/env bash
    +# YoureCom Standard: clones the required YoureCom packages of package.xml next to the plugin (CI only), so PHPStan
    +# finds their classes like in the local plugins folder. Managed by _dev/standard (apply.php), do not edit here.
    +#
    +# Usage: TOKEN=<token> bash .github/scripts/checkout-dependencies.sh <plugin dir>
    +set -euo pipefail
    +
    +PLUGIN="${1:-.}"
    +BRANCH="${DEPENDENCY_BRANCH:-6.2}"
    +mapfile -t PACKAGES < <(sed -n 's:.*<requiredpackage[^>]*>\(de\.yourecom\.[^<]*\)</requiredpackage>.*:\1:p' "$PLUGIN/package.xml")
    +
    +if [[ ${#PACKAGES[@]} -eq 0 ]]; then
    + echo "No required YoureCom packages."
    + exit 0
    +fi
    +
    +if [[ -z "${TOKEN:-}" ]]; then
    + echo "::warning::YOURECOM_DEPENDENCY_TOKEN is not set, PHPStan runs without: ${PACKAGES[*]}"
    + exit 0
    +fi
    +
    +for PACKAGE in "${PACKAGES[@]}"; do
    + # the repositories keep the camel case of the plugin folders, GitHub resolves the name case-insensitively
    + git clone --quiet --depth 1 --branch "$BRANCH" "https://x-access-token:${TOKEN}@github.com/YoureCom/${PACKAGE}.git" "$PACKAGE" \
    + || git clone --quiet --depth 1 "https://x-access-token:${TOKEN}@github.com/YoureCom/${PACKAGE}.git" "$PACKAGE" \
    + || { echo "::warning::$PACKAGE could not be cloned, PHPStan runs without it"; continue; }
    + echo "Cloned $PACKAGE"
    +done
  • .github/workflows/ci.yml
    <pre>@@ -0,0 +1,180 @@
    +# YoureCom Standard: checks of every plugin. Managed by _dev/standard (apply.php), do not edit here.
    +# One job instead of one per check: GitHub bills every job rounded up to whole minutes, nine small jobs cost nine minutes
    +# even when each takes seconds. All steps run even if an earlier one fails (`!cancelled()`), the job is red if any is.
    +# Locally `bash _dev/standard/check.sh <plugin>` runs the same checks and more (dev system, browser).
    +name: CI
    +
    +on:
    + push:
    + branches: ['6.2']
    + paths-ignore: ['**.md', 'docs/**']
    + pull_request:
    + paths-ignore: ['**.md', 'docs/**']
    + # the release workflow runs the same checks first, with PHP 8.4 in addition
    + workflow_call:
    +
    +permissions:
    + contents: read
    +
    +concurrency:
    + group: ci-${{ github.ref }}
    + cancel-in-progress: true
    +
    +jobs:
    + checks:
    + name: Checks
    + runs-on: ubuntu-latest
    + # Dependabot pull requests only signal new versions, the update itself happens once in _dev/standard
    + if: github.actor != 'dependabot[bot]'
    + defaults:
    + run:
    + working-directory: plugin
    + steps:
    + # the whole history: check-deletes.php compares with the released versions
    + - uses: actions/checkout@v7
    + with:
    + path: plugin
    + fetch-depth: 0
    +
    + # the WoltLab Suite Core: the classes for PHPStan and the XSDs of the PIP files
    + - uses: actions/checkout@v7
    + with:
    + repository: WoltLab/WCF
    + ref: '6.2'
    + path: wcf
    +
    + # required YoureCom packages (package.xml) next to the plugin, as in the local plugins folder; needs the
    + # organization secret YOURECOM_DEPENDENCY_TOKEN (read access to the private repositories)
    + - name: Required YoureCom packages
    + working-directory: .
    + env:
    + TOKEN: ${{ secrets.YOURECOM_DEPENDENCY_TOKEN }}
    + run: bash plugin/.github/scripts/checkout-dependencies.sh plugin
    +
    + - uses: shivammathur/setup-php@v2
    + with:
    + php-version: '8.2'
    + tools: composer
    + coverage: pcov
    + extensions: dom, libxml
    +
    + # a plugin without PHP classes (files*/lib) has nothing for PHPStan and PHPUnit, like in check.sh
    + - id: detect
    + name: Detect PHP classes and TypeScript
    + run: |
    + echo "php=$(find files*/lib -name '*.php' -print -quit 2>/dev/null | grep -q . && echo true || echo false)" >> "$GITHUB_OUTPUT"
    + echo "typescript=$([ -f tsconfig.json ] && echo true || echo false)" >> "$GITHUB_OUTPUT"
    +
    + - name: PHP syntax
    + run: find . -path ./vendor -prune -o -path ./node_modules -prune -o -name '*.php' -print0 | xargs -0 -n1 -P4 php -l > /dev/null
    +
    + # the versions of PHPStan, PHPUnit and PHP-CS-Fixer are pinned in composer.json, locally and in the CI the same
    + - run: composer install --no-interaction --no-progress
    +
    + - name: Code style (PHP-CS-Fixer, the rules of WoltLab Suite)
    + if: ${{ !cancelled() }}
    + run: vendor/bin/php-cs-fixer check --diff
    +
    + - name: PHPStan
    + if: ${{ !cancelled() && steps.detect.outputs.php == 'true' }}
    + run: vendor/bin/phpstan analyse -c phpstan.ci.neon --memory-limit=2G --no-progress
    +
    + - name: PHPUnit with coverage floor
    + if: ${{ !cancelled() && steps.detect.outputs.php == 'true' }}
    + run: |
    + vendor/bin/phpunit --testsuite unit --coverage-clover=var/coverage.xml
    + php tests/lint/check-coverage.php var/coverage.xml
    +
    + - name: PIP files match the XSDs of WoltLab Suite 6.2
    + if: ${{ !cancelled() }}
    + run: php tests/lint/check-xsd.php
    + env:
    + WCF_XSD: ${{ github.workspace }}/wcf/XSD
    +
    + - name: package.xml and constants.php
    + if: ${{ !cancelled() }}
    + run: php tests/lint/check-package.php
    +
    + - name: Removed files and language items of released versions are deleted on update
    + if: ${{ !cancelled() }}
    + run: php tests/lint/check-deletes.php
    +
    + - name: Language files
    + if: ${{ !cancelled() }}
    + run: php tests/lint/check-language.php
    +
    + - name: PHP rules (debug output, WCF_N, json_decode, trim, docblocks)
    + if: ${{ !cancelled() }}
    + run: php tests/lint/check-php.php
    +
    + - name: Phrases of the TypeScript modules exist and are preloaded
    + if: ${{ !cancelled() }}
    + run: php tests/lint/check-js-phrases.php
    +
    + - name: RPC endpoints are registered
    + if: ${{ !cancelled() }}
    + run: php tests/lint/check-endpoints.php
    +
    + - name: Templates and TypeScript (no jQuery, no legacy AJAX, strict comparisons, labels, ids, buttons)
    + if: ${{ !cancelled() }}
    + run: php tests/lint/check-templates.php
    +
    + - name: Architecture (grid/list views, interactions, RPC endpoints instead of legacy lists and AJAX actions)
    + if: ${{ !cancelled() }}
    + run: php tests/lint/check-architecture.php
    +
    + - uses: actions/setup-node@v7
    + if: ${{ !cancelled() && steps.detect.outputs.typescript == 'true' }}
    + with:
    + node-version: 22
    +
    + # the WoltLab packages come from GitHub, the lock file names them by SSH
    + - name: npm install
    + if: ${{ !cancelled() && steps.detect.outputs.typescript == 'true' }}
    + run: |
    + git config --global url."https://github.com/".insteadOf ssh://git@github.com/
    + if [ -f package-lock.json ]; then npm ci --no-audit --no-fund; else npm install --no-audit --no-fund; fi
    +
    + - name: TypeScript (strict)
    + if: ${{ !cancelled() && steps.detect.outputs.typescript == 'true' }}
    + run: npx tsc -p tsconfig.ci.json
    +
    + - name: ESLint
    + if: ${{ !cancelled() && steps.detect.outputs.typescript == 'true' }}
    + run: npm run lint
    +
    + - name: Prettier
    + if: ${{ !cancelled() && steps.detect.outputs.typescript == 'true' }}
    + run: npm run format:check
    +
    + - name: The committed JavaScript is the build of ts/
    + if: ${{ !cancelled() && steps.detect.outputs.typescript == 'true' }}
    + run: node tests/lint/check-js-build.mjs
    +
    + - name: Vitest with coverage
    + if: ${{ !cancelled() && steps.detect.outputs.typescript == 'true' }}
    + run: npm run test:coverage
    +
    + # the newest PHP only before a release (tags), not on every push
    + php84:
    + name: PHP 8.4 (release)
    + runs-on: ubuntu-latest
    + if: startsWith(github.ref, 'refs/tags/')
    + steps:
    + - uses: actions/checkout@v7
    +
    + - uses: shivammathur/setup-php@v2
    + with:
    + php-version: '8.4'
    + tools: composer
    +
    + - name: PHP syntax
    + run: find . -path ./vendor -prune -o -path ./node_modules -prune -o -name '*.php' -print0 | xargs -0 -n1 -P4 php -l > /dev/null
    +
    + - run: composer install --no-interaction --no-progress
    +
    + - name: PHPUnit
    + run: |
    + if find files*/lib -name '*.php' -print -quit 2>/dev/null | grep -q .; then
    + vendor/bin/phpunit --testsuite unit
    + fi
  • .github/workflows/release.yml
    <pre>@@ -0,0 +1,54 @@
    +# YoureCom Standard: managed by _dev/standard (apply.php), do not edit here.
    +name: Release
    +
    +# Builds the package for a tag like v6.2.14 or v6.2.14-beta.2 and attaches it to a GitHub release.
    +# Nothing is deployed: uploading to yourecom.de stays a manual step that needs Marcel's approval
    +# (before that: bash ../_dev/release-check.sh <plugin>, it needs SSH access to the live server).
    +
    +on:
    + push:
    + tags: ['v*']
    +
    +permissions:
    + contents: read
    +
    +jobs:
    + checks:
    + uses: ./.github/workflows/ci.yml
    +
    + release:
    + name: Build and publish
    + needs: checks
    + runs-on: ubuntu-latest
    + permissions:
    + contents: write
    + steps:
    + - uses: actions/checkout@v7
    +
    + - name: The tag matches the version in package.xml
    + id: version
    + run: |
    + version="$(sed -n 's:.*<version>\(.*\)</version>.*:\1:p' package.xml | head -1)"
    + # "6.2.14 Beta 2" and "v6.2.14-beta.2" both become "6.2.14.beta.2"
    + normalize() { echo "$1" | tr '[:upper:]' '[:lower:]' | sed -e 's/^v//' -e 's/[ -]/./g'; }
    + if [ "$(normalize "$version")" != "$(normalize "$GITHUB_REF_NAME")" ]; then
    + echo "::error::The tag $GITHUB_REF_NAME does not match the version '$version' in package.xml"
    + exit 1
    + fi
    + echo "version=$version" >> "$GITHUB_OUTPUT"
    + if echo "$version" | grep -qiE 'alpha|beta|rc'; then
    + echo "prerelease=--prerelease" >> "$GITHUB_OUTPUT"
    + fi
    +
    + - name: Build the package
    + id: build
    + run: echo "archive=$(bash .github/scripts/build-package.sh "$RUNNER_TEMP/package")" >> "$GITHUB_OUTPUT"
    +
    + - name: Publish the release
    + env:
    + GH_TOKEN: ${{ github.token }}
    + run: |
    + gh release create "$GITHUB_REF_NAME" "${{ steps.build.outputs.archive }}" \
    + --title "${{ steps.version.outputs.version }}" \
    + --generate-notes \
    + ${{ steps.version.outputs.prerelease }}
  • .php-cs-fixer.dist.php
    <pre>@@ -0,0 +1,126 @@
    +<?php
    +
    +/**
    + * YoureCom Standard (managed by _dev/standard, do not edit here). Code style of the plugin: the rules of WoltLab Suite (https://github.com/WoltLab/WCF/blob/6.2/.php-cs-fixer.dist.php).
    + * Check: vendor/bin/php-cs-fixer check --diff Fix: vendor/bin/php-cs-fixer fix
    + */
    +
    +$finder = PhpCsFixer\Finder::create()
    + ->in(array_values(array_filter([__DIR__ . "/files", __DIR__ . "/files_wcf", __DIR__ . "/tests"], "is_dir")))
    + ->name('*.php');
    +
    +return (new PhpCsFixer\Config())
    + ->setRiskyAllowed(true)
    + ->setRules([
    + '@PSR1' => true,
    + '@PSR2' => true,
    +
    + 'array_push' => true,
    + 'backtick_to_shell_exec' => true,
    + 'no_alias_language_construct_call' => true,
    + 'no_mixed_echo_print' => true,
    + 'pow_to_exponentiation' => true,
    + 'random_api_migration' => true,
    +
    + 'array_syntax' => ['syntax' => 'short'],
    + 'no_multiline_whitespace_around_double_arrow' => true,
    + 'no_trailing_comma_in_singleline_array' => true,
    + 'no_whitespace_before_comma_in_array' => true,
    + 'normalize_index_brace' => true,
    + 'whitespace_after_comma_in_array' => true,
    +
    + 'non_printable_character' => ['use_escape_sequences_in_strings' => true],
    +
    + 'lowercase_static_reference' => true,
    + 'magic_constant_casing' => true,
    + 'magic_method_casing' => true,
    + 'native_function_casing' => true,
    + 'native_function_type_declaration_casing' => true,
    +
    + 'cast_spaces' => ['space' => 'none'],
    + 'lowercase_cast' => true,
    + 'no_unset_cast' => true,
    + 'short_scalar_cast' => true,
    +
    + 'class_attributes_separation' => true,
    + 'no_blank_lines_after_class_opening' => true,
    + 'no_null_property_initialization' => true,
    + // 'self_accessor' would turn `Class::method()` in an anonymous class into `self::method()` of the anonymous class
    + 'single_class_element_per_statement' => true,
    + 'single_trait_insert_per_statement' => true,
    +
    + 'no_empty_comment' => true,
    + 'single_line_comment_style' => ['comment_types' => ['hash']],
    +
    + 'native_constant_invocation' => ['strict' => false],
    +
    + 'no_alternative_syntax' => true,
    + 'no_trailing_comma_in_list_call' => true,
    + 'no_unneeded_control_parentheses' => ['statements' => ['break', 'clone', 'continue', 'echo_print', 'return', 'switch_case', 'yield', 'yield_from']],
    + 'no_unneeded_curly_braces' => ['namespaces' => true],
    + 'switch_continue_to_break' => true,
    + 'trailing_comma_in_multiline' => ['elements' => ['arrays']],
    +
    + 'function_typehint_space' => true,
    + 'lambda_not_used_import' => true,
    + 'native_function_invocation' => ['include' => ['@internal']],
    + 'no_unreachable_default_argument_value' => true,
    + 'nullable_type_declaration_for_default_null_value' => true,
    + 'return_type_declaration' => true,
    + 'static_lambda' => true,
    +
    + 'fully_qualified_strict_types' => ['leading_backslash_in_global_namespace' => true],
    + 'no_leading_import_slash' => true,
    + 'no_unused_imports' => true,
    + 'ordered_imports' => true,
    +
    + 'declare_equal_normalize' => true,
    + 'dir_constant' => true,
    + 'explicit_indirect_variable' => true,
    + 'function_to_constant' => true,
    + 'is_null' => true,
    + 'no_unset_on_property' => true,
    +
    + 'list_syntax' => ['syntax' => 'short'],
    +
    + 'clean_namespace' => true,
    + 'no_leading_namespace_whitespace' => true,
    + 'single_blank_line_before_namespace' => true,
    +
    + 'no_homoglyph_names' => true,
    +
    + 'binary_operator_spaces' => true,
    + 'concat_space' => ['spacing' => 'one'],
    + 'increment_style' => ['style' => 'post'],
    + 'logical_operators' => true,
    + 'object_operator_without_whitespace' => true,
    + 'operator_linebreak' => true,
    + 'standardize_increment' => true,
    + 'standardize_not_equals' => true,
    + 'ternary_operator_spaces' => true,
    + 'ternary_to_elvis_operator' => true,
    + 'ternary_to_null_coalescing' => true,
    + 'unary_operator_spaces' => true,
    +
    + 'no_useless_return' => true,
    + // 'return_assignment' would drop the variable of a `@var T $x` annotated assignment that is returned
    +
    + 'multiline_whitespace_before_semicolons' => true,
    + 'no_empty_statement' => true,
    + 'no_singleline_whitespace_before_semicolons' => true,
    + 'space_after_semicolon' => ['remove_in_empty_for_expressions' => true],
    +
    + 'escape_implicit_backslashes' => true,
    + 'explicit_string_variable' => true,
    + 'heredoc_to_nowdoc' => true,
    + 'no_binary_string' => true,
    + 'simple_to_complex_string_variable' => true,
    +
    + 'array_indentation' => true,
    + 'blank_line_before_statement' => ['statements' => ['return', 'exit']],
    + 'compact_nullable_typehint' => true,
    + 'method_chaining_indentation' => true,
    + 'no_extra_blank_lines' => ['tokens' => ['case', 'continue', 'curly_brace_block', 'default', 'extra', 'parenthesis_brace_block', 'square_brace_block', 'switch', 'throw', 'use']],
    + 'no_spaces_around_offset' => true,
    + ])
    + ->setFinder($finder);
  • .prettierignore
    <pre>@@ -0,0 +1,7 @@
    +files/
    +files_wcf/
    +node_modules/
    +vendor/
    +var/
    +snapshots/
    +tests/ts/mocks/
  • .prettierrc.json
    <pre>@@ -0,0 +1,4 @@
    +{
    + "printWidth": 140,
    + "trailingComma": "all"
    +}
  • README.md
    <pre>@@ -0,0 +1,9 @@
    +# de.yourecom.wcf.api.mpdf
    +
    +WoltLab Suite 6.2 plugin of YoureCom.
    +
    +- Rules, standard and tests: [`../CLAUDE.md`](../CLAUDE.md) and [`../_dev/standard/README.md`](../_dev/standard/README.md)
    +- Deploy into the dev system: `bash ../_dev/deploy.sh de.yourecom.wcf.api.mpdf`
    +- All checks: `bash ../_dev/standard/check.sh de.yourecom.wcf.api.mpdf`
    +
    +Describe here what the plugin does and what is special about it (options, dependencies, interfaces).
  • composer.json
    <pre>@@ -0,0 +1,24 @@
    +{
    + "name": "yourecom/de.yourecom.wcf.api.mpdf",
    + "description": "Development tools of de.yourecom.wcf.api.mpdf (not part of the package). YoureCom Standard: same versions as _dev/tools.",
    + "type": "project",
    + "require": {
    + "php": ">=8.2"
    + },
    + "require-dev": {
    + "friendsofphp/php-cs-fixer": "3.95.27",
    + "phpstan/phpstan": "2.2.16",
    + "phpstan/phpstan-deprecation-rules": "2.0.5",
    + "phpstan/phpstan-strict-rules": "2.0.12",
    + "phpunit/phpunit": "^11"
    + },
    + "scripts": {
    + "test": "phpunit --testsuite unit",
    + "test-integration": "phpunit -c phpunit.integration.xml",
    + "cs": "php-cs-fixer check --diff",
    + "cs-fix": "php-cs-fixer fix"
    + },
    + "config": {
    + "sort-packages": true
    + }
    +}
  • constants.php
    <pre>@@ -0,0 +1,17 @@
    +<?php
    +/**
    + * Defines constants for autocompletion in IDEs. This file is not meant to be actively used anywhere!
    + *
    + * @author Marcel Beckers
    + * @license YoureCom License - Commercial (YCLC) <https://www.yourecom.de/shop/licence-commercial/>
    + * @package de.yourecom.wcf.api.mpdf
    + */
    +
    +// option constants
    +
    +// application constants
    +
    +// hardcoded framework constants
    +define('WCF_DIR', '');
    +define('LEGAL_NOTICE_EMAIL_ADDRESS', '');
    +define('DOMPDF_LOG_FILE', WCF_DIR . 'tmp/dompdf.log');
  • eslint.config.mjs
    <pre>@@ -0,0 +1,31 @@
    +// YoureCom Standard: managed by _dev/standard (apply.php), do not edit here.
    +// @ts-check
    +import tseslint from "typescript-eslint";
    +import eslintConfigPrettier from "eslint-config-prettier";
    +
    +export default tseslint.config(
    + {
    + ignores: ["files/**", "files_wcf/**", "node_modules/**", "vendor/**", "var/**", "snapshots/**"],
    + },
    + ...tseslint.configs.recommended,
    + {
    + rules: {
    + // the core modules are typed loosely in places, `any` at those boundaries is a warning only
    + "@typescript-eslint/no-explicit-any": "warn",
    + "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
    + // strict comparisons only
    + eqeqeq: ["error", "always"],
    + // no debug output in the package (tests may log)
    + "no-console": "error",
    + "no-debugger": "error",
    + "no-alert": "error",
    + },
    + },
    + {
    + files: ["tests/**"],
    + rules: {
    + "no-console": "off",
    + },
    + },
    + eslintConfigPrettier,
    +);
  • files/lib/system/api/mpdf/autoload.php
    <pre>@@ -1 +1 @@
    -<?php require (__DIR__ . '/vendor/autoload.php');
    +<?php require(__DIR__ . '/vendor/autoload.php');
  • package.xml
    <pre>@@ -1,13 +1,13 @@
    <?xml version="1.0" encoding="utf-8"?>
    -<package name="de.yourecom.wcf.api.mpdf" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/5.4/package.xsd">
    +<package name="de.yourecom.wcf.api.mpdf" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com https://www.woltlab.com/XSD/6.0/package.xsd">
    <packageinformation>
    <packagename><![CDATA[mPDF]]></packagename>
    <packagename languagecode="de"><![CDATA[mPDF]]></packagename>
    <packagedescription><![CDATA[Bundles the mPDF library (HTML to PDF converter) for use by other packages. Developed by Matěj Humpál and contributors: https://github.com/mpdf/mpdf]]></packagedescription>
    <packagedescription languagecode="de"><![CDATA[Stellt die mPDF-Bibliothek (HTML-zu-PDF-Konverter) für andere Pakete bereit. Entwickelt von Matěj Humpál und Mitwirkenden: https://github.com/mpdf/mpdf]]></packagedescription>
    <isapplication>0</isapplication>
    - <version>8.3.2 Beta 1</version>
    - <date>2026-10-12</date>
    + <version>8.3.2 Beta 2</version>
    + <date>2026-10-13</date>
    <packageurl><![CDATA[https://yourecom.de]]></packageurl>
    </packageinformation>
  • phpstan.ci.neon
    <pre>@@ -0,0 +1,17 @@
    +# YoureCom Standard: PHPStan in the GitHub workflow, the WoltLab Suite Core is checked out into ../wcf and the
    +# required YoureCom packages next to the plugin (.github/scripts/checkout-dependencies.sh).
    +includes:
    + - vendor/phpstan/phpstan-strict-rules/rules.neon
    + - vendor/phpstan/phpstan-deprecation-rules/rules.neon
    + - phpstan.common.neon
    +
    +parameters:
    + tmpDir: var/phpstan
    +
    + bootstrapFiles:
    + - '../wcf/constants.php'
    + - 'constants.php'
    +
    + scanDirectories:
    + - ../wcf/wcfsetup/install/files/lib/
    +
  • phpstan.common.neon
    <pre>@@ -0,0 +1,36 @@
    +# YoureCom Standard: shared PHPStan settings of the plugin (level 9 at least, strict and deprecation rules).
    +# Local: phpstan.neon.dist, CI: phpstan.ci.neon.
    +includes:
    + - phpstanWoltLab.neon
    + # rules of the standard: strict comparisons (no empty(), no ==), #[\Override] or a docblock on every method
    + - phpstan.standard.neon
    +
    +parameters:
    + level: 9
    +
    + # strict rules, except the ones that ask for a different style than the WoltLab code base
    + strictRules:
    + booleansInConditions: false
    + disallowedShortTernary: false
    + # `@property-read int` on a database object names the target type, the database delivers strings
    + uselessCast: false
    +
    + paths:
    + - files
    + - tests
    +
    + reportUnmatchedIgnoredErrors: true
    +
    + excludePaths:
    + analyse:
    + - vendor/*
    + - "**/vendor/*"
    + - node_modules/*
    + - var/*
    + - tests/e2e/*
    + # tooling of the standard, not part of the package
    + - tests/lint/*
    + - .vscode (?)
    +
    + dynamicConstantNames:
    + - TIME_NOW
  • phpstan.neon.dist
    <pre>@@ -0,0 +1,17 @@
    +# YoureCom Standard: local PHPStan run against C:/laragon/www/wsc6.2 with the shared tools of _dev/tools.
    +# php -d memory_limit=4G ../_dev/tools/vendor/bin/phpstan analyse -c phpstan.neon.dist --no-progress
    +includes:
    + - ../_dev/tools/vendor/phpstan/phpstan-strict-rules/rules.neon
    + - ../_dev/tools/vendor/phpstan/phpstan-deprecation-rules/rules.neon
    + - phpstan.common.neon
    +
    +parameters:
    + tmpDir: ../var/phpstan/de.yourecom.wcf.api.mpdf
    +
    + bootstrapFiles:
    + - 'C:/laragon/www/wsc6.2/constants.php'
    + - 'constants.php'
    +
    + scanDirectories:
    + - C:/laragon/www/wsc6.2/lib/
    +
  • phpstan.standard.neon
    <pre>@@ -0,0 +1,15 @@
    +# YoureCom Standard: managed by _dev/standard (apply.php), do not edit here.
    +# Rules of the standard on top of level 9 and the strict rules, included by phpstan.common.neon.
    +# - strict comparisons: no empty() (compare with === [], === '', === 0 or === null), no == or != (strict rules)
    +# - every method has #[\Override] or a docblock that explains it (tests/phpstan/OverrideOrDocblockRule.php)
    +includes:
    + - tests/phpstan/rules.php
    +
    +parameters:
    + strictRules:
    + disallowedEmpty: true
    + disallowedLooseComparison: true
    +
    + excludePaths:
    + analyse:
    + - tests/phpstan/*
  • phpstanWoltLab.neon
    <pre>@@ -0,0 +1,235 @@
    +parameters:
    + universalObjectCratesClasses:
    + - wcf\data\category\Category
    + - wcf\data\condition\Condition
    + - wcf\data\modification\log\ModificationLog
    + - wcf\data\object\type\ObjectType
    + - wcf\data\option\Option
    + - wcf\data\user\activity\event\ViewableUserActivityEvent
    + - wcf\data\user\notification\UserNotification
    + - wcf\data\user\User
    + - wcf\system\menu\ITreeMenuItem
    + - wcf\system\message\embedded\object\IMessageEmbeddedObjectHandler
    + - wcf\system\user\notification\event\IUserNotificationEvent
    + - wcf\system\user\notification\object\type\IUserNotificationObjectType
    +
    + dynamicConstantNames:
    + - PACKAGE_ID
    + - PACKAGE_NAME
    + - RELATIVE_WCF_DIR
    + - TMP_DIR
    + - WCF_N
    + - TIME_NOW
    + - WCF_OPTION_INC_PHP_SUCCESS
    + - LAST_UPDATE_TIME
    + - WCF_UUID
    + - WOLTLAB_BRANDING
    + - VISITOR_USE_TINY_BUILD
    + - ENABLE_DEBUG_MODE
    + - ENABLE_BENCHMARK
    + - LOG_IP_ADDRESS
    + - MODULE_SYSTEM_RECAPTCHA
    + - MODULE_SMILEY
    + - MODULE_USERS_ONLINE
    + - MODULE_USER_RANK
    + - MODULE_USER_SIGNATURE
    + - MODULE_MEMBERS_LIST
    + - MODULE_TEAM_PAGE
    + - MODULE_LIKE
    + - MODULE_USER_PROFILE_WALL
    + - MODULE_TAGGING
    + - MODULE_POLL
    + - MODULE_WCF_AD
    + - PAGE_TITLE
    + - PAGE_DESCRIPTION
    + - META_DESCRIPTION
    + - SHOW_VERSION_NUMBER
    + - EXTERNAL_LINK_TARGET_BLANK
    + - FOOTER_CODE
    + - URL_OMIT_INDEX_PHP
    + - URL_TITLE_COMPONENT_REPLACEMENT
    + - OFFLINE
    + - OFFLINE_MESSAGE
    + - OFFLINE_MESSAGE_ALLOW_HTML
    + - IMAGE_ADAPTER_TYPE
    + - SEARCH_ENGINE
    + - EXCEPTION_PRIVACY
    + - COOKIE_PREFIX
    + - PACKAGE_SERVER_AUTH_CODE
    + - PROXY_SERVER_HTTP
    + - IP_ADDRESS_SEARCH_ENGINE
    + - USER_ONLINE_TIMEOUT
    + - ENABLE_USER_AUTHENTICATION_FAILURE
    + - USER_AUTHENTICATION_FAILURE_TIMEOUT
    + - USER_AUTHENTICATION_FAILURE_IP_CAPTCHA
    + - USER_AUTHENTICATION_FAILURE_IP_BLOCK
    + - USER_AUTHENTICATION_FAILURE_USER_CAPTCHA
    + - USER_AUTHENTICATION_FAILURE_EXPIRATION
    + - SIGNATURE_SECRET
    + - CAPTCHA_TYPE
    + - REGISTER_USE_CAPTCHA
    + - LOST_PASSWORD_USE_CAPTCHA
    + - RECAPTCHA_PUBLICKEY
    + - RECAPTCHA_PRIVATEKEY
    + - RECAPTCHA_PRIVATEKEY_INVISIBLE
    + - TIMEZONE
    + - GOOGLE_MAPS_API_KEY
    + - GOOGLE_MAPS_ZOOM
    + - GOOGLE_MAPS_DEFAULT_LATITUDE
    + - GOOGLE_MAPS_DEFAULT_LONGITUDE
    + - MAIL_FROM_NAME
    + - MAIL_FROM_ADDRESS
    + - MAIL_ADMIN_ADDRESS
    + - MAIL_SIGNATURE
    + - MAIL_SIGNATURE_HTML
    + - MAIL_SEND_METHOD
    + - MAIL_SMTP_HOST
    + - MAIL_SMTP_PORT
    + - MAIL_SMTP_STARTTLS
    + - MAIL_SMTP_USER
    + - MAIL_SMTP_PASSWORD
    + - MAIL_USE_F_PARAM
    + - CACHE_SOURCE_TYPE
    + - CACHE_SOURCE_REDIS_HOST
    + - AVAILABLE_PAYMENT_METHODS
    + - PAYPAL_EMAIL_ADDRESS
    + - MODULE_PAID_SUBSCRIPTION
    + - PAID_SUBSCRIPTION_ENABLE_TOS_CONFIRMATION
    + - PAID_SUBSCRIPTION_TOS_URL
    + - ATTACHMENT_RETAIN_DIMENSIONS
    + - ATTACHMENT_THUMBNAIL_HEIGHT
    + - ATTACHMENT_THUMBNAIL_WIDTH
    + - MODULE_EDIT_HISTORY
    + - EDIT_HISTORY_EXPIRATION
    + - ENABLE_SHARE_BUTTONS
    + - SHARE_BUTTONS_PROVIDERS
    + - MESSAGE_FORCE_SECURE_IMAGES
    + - MODULE_IMAGE_PROXY
    + - IMAGE_PROXY_INSECURE_ONLY
    + - IMAGE_PROXY_EXPIRATION
    + - IMAGE_PROXY_HOST_WHITELIST
    + - CENSORED_WORDS
    + - PASSWORD_MIN_SCORE
    + - REGISTER_FORBIDDEN_USERNAMES
    + - REGISTER_FORBIDDEN_EMAILS
    + - REGISTER_ALLOWED_EMAILS
    + - REGISTER_DISABLED
    + - REGISTER_ENABLE_DISCLAIMER
    + - REGISTER_ACTIVATION_METHOD
    + - REGISTER_USERNAME_MIN_LENGTH
    + - REGISTER_USERNAME_MAX_LENGTH
    + - REGISTER_USERNAME_FORCE_ASCII
    + - REGISTER_MIN_USER_AGE
    + - REGISTER_ANTISPAM_ACTION
    + - GITHUB_PUBLIC_KEY
    + - GITHUB_PRIVATE_KEY
    + - TWITTER_PUBLIC_KEY
    + - TWITTER_PRIVATE_KEY
    + - FACEBOOK_PUBLIC_KEY
    + - FACEBOOK_PRIVATE_KEY
    + - GOOGLE_PUBLIC_KEY
    + - GOOGLE_PRIVATE_KEY
    + - SIGNATURE_MAX_IMAGE_HEIGHT
    + - USER_TITLE_MAX_LENGTH
    + - USER_FORBIDDEN_TITLES
    + - PROFILE_SHOW_OLD_USERNAME
    + - PROFILE_ENABLE_VISITORS
    + - MEMBERS_LIST_USERS_PER_PAGE
    + - MEMBERS_LIST_DEFAULT_SORT_FIELD
    + - MEMBERS_LIST_DEFAULT_SORT_ORDER
    + - USERS_ONLINE_SHOW_GUESTS
    + - USERS_ONLINE_SHOW_ROBOTS
    + - USERS_ONLINE_DEFAULT_SORT_FIELD
    + - USERS_ONLINE_DEFAULT_SORT_ORDER
    + - USERS_ONLINE_PAGE_REFRESH
    + - USERS_ONLINE_ENABLE_LEGEND
    + - USERS_ONLINE_RECORD
    + - USERS_ONLINE_RECORD_TIME
    + - USER_CLEANUP_NOTIFICATION_LIFETIME
    + - USER_CLEANUP_ACTIVITY_EVENT_LIFETIME
    + - USER_CLEANUP_PROFILE_VISITOR_LIFETIME
    + - LIKE_SHOW_SUMMARY
    + - MESSAGE_SIDEBAR_ENABLE_ONLINE_STATUS
    + - MESSAGE_SIDEBAR_ENABLE_LIKES_RECEIVED
    + - MESSAGE_SIDEBAR_ENABLE_ACTIVITY_POINTS
    + - MESSAGE_SIDEBAR_USER_OPTIONS
    + - TAGGING_MAX_TAG_LENGTH
    + - MESSAGE_MAX_QUOTE_DEPTH
    + - SEARCH_RESULTS_PER_PAGE
    + - SEARCH_DEFAULT_SORT_FIELD
    + - SEARCH_DEFAULT_SORT_ORDER
    + - POLL_MAX_OPTIONS
    + - POLL_FULL_WIDTH
    + - MEDIA_SMALL_THUMBNAIL_WIDTH
    + - MEDIA_SMALL_THUMBNAIL_HEIGHT
    + - MEDIA_SMALL_THUMBNAIL_RETAIN_DIMENSIONS
    + - MEDIA_MEDIUM_THUMBNAIL_WIDTH
    + - MEDIA_MEDIUM_THUMBNAIL_HEIGHT
    + - MEDIA_MEDIUM_THUMBNAIL_RETAIN_DIMENSIONS
    + - MEDIA_LARGE_THUMBNAIL_WIDTH
    + - MEDIA_LARGE_THUMBNAIL_HEIGHT
    + - MEDIA_LARGE_THUMBNAIL_RETAIN_DIMENSIONS
    + - MODULE_ARTICLE
    + - ARTICLE_SHOW_ABOUT_AUTHOR
    + - ARTICLE_ENABLE_COMMENTS_DEFAULT_VALUE
    + - ARTICLE_ENABLE_LIKE
    + - ARTICLES_PER_PAGE
    + - ARTICLE_RELATED_ARTICLES
    + - ARTICLE_RELATED_ARTICLES_MATCH_THRESHOLD
    + - SHOW_UPDATE_NOTICE_FRONTEND
    + - LANGUAGE_USE_INFORMAL_VARIANT
    + - SHOW_STYLE_CHANGER
    + - ARTICLE_SORT_ORDER
    + - USE_PAGE_TITLE_ON_LANDING_PAGE
    + - OG_IMAGE
    + - HEAD_CODE
    + - AVATAR_DEFAULT_TYPE
    + - ARTICLE_ENABLE_VISIT_TRACKING
    + - ENABLE_AD_ROTATION
    + - ENABLE_POLLING
    + - FB_SHARE_APP_ID
    + - MODULE_CONTACT_FORM
    + - SITEMAP_INDEX_TIME_FRAME
    + - MODULE_TROPHY
    + - ENABLE_DEVELOPER_TOOLS
    + - FORCE_LOGIN
    + - PAGE_LOGO_LINK_TO_APP_DEFAULT
    + - IMAGE_ALLOW_EXTERNAL_SOURCE
    + - MESSAGE_ENABLE_TOC
    + - MESSAGE_PUBLIC_HIGHLIGHTERS
    + - MESSAGE_SIDEBAR_ENABLE_ARTICLES
    + - IMAGE_PROXY_ENABLE_PRUNE
    + - SEARCH_ENABLE_PAGES
    + - SEARCH_ENABLE_ARTICLES
    + - ATTACHMENT_IMAGE_AUTOSCALE
    + - ATTACHMENT_IMAGE_AUTOSCALE_MAX_WIDTH
    + - ATTACHMENT_IMAGE_AUTOSCALE_MAX_HEIGHT
    + - ATTACHMENT_IMAGE_AUTOSCALE_FILE_TYPE
    + - ATTACHMENT_IMAGE_AUTOSCALE_QUALITY
    + - LOG_MISSING_LANGUAGE_ITEMS
    + - PRUNE_IP_ADDRESS
    + - BREADCRUMBS_HOME_USE_PAGE_TITLE
    + - CONTACT_FORM_ENABLE_ATTACHMENTS
    + - CONTACT_FORM_PRUNE_ATTACHMENTS
    + - IMAGE_EXTERNAL_SOURCE_WHITELIST
    + - SEARCH_MAX_COMBINED_TAGS
    + - ENABLE_PRODUCTION_DEBUG_MODE
    + - BLACKLIST_SFS_ENABLE
    + - BLACKLIST_SFS_USERNAME
    + - BLACKLIST_SFS_EMAIL_ADDRESS
    + - BLACKLIST_SFS_IP_ADDRESS
    + - ENABLE_ENTERPRISE_MODE
    + - MESSAGE_ENABLE_USER_CONSENT
    + - MODIFICATION_LOG_EXPIRATION
    + - INTERNAL_HOSTNAMES
    + - MODULE_URL_UNFURLING
    + - FIRST_TIME_SETUP_STATE
    + - FORMATTING_REMOVE_COLOR
    + - FORMATTING_REMOVE_FONT
    + - FORMATTING_REMOVE_SIZE
    + - URL_UNFURLING_SAVE_IMAGES
    + - SERVICE_WORKER_PRIVATE_KEY
    + - SERVICE_WORKER_PUBLIC_KEY
    + - RECAPTCHA_PRIVATEKEY_V3
    + - IMAGE_CONVERT_FORMAT
    + - IMAGE_STRIP_EXIF
  • phpunit.integration.xml
    <pre>@@ -0,0 +1,17 @@
    +<?xml version="1.0" encoding="UTF-8"?>
    +<!--
    + Integration tests against the local WoltLab Suite installation with the plugin deployed (deploy first).
    + The installation is taken from the environment variable WCF_DIR (default: C:/laragon/www/wsc6.2).
    + Every test runs in a transaction that is rolled back.
    +-->
    +<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    + xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
    + bootstrap="tests/Integration/bootstrap.php"
    + colors="true"
    + cacheDirectory=".phpunit.cache">
    + <testsuites>
    + <testsuite name="integration">
    + <directory>tests/Integration</directory>
    + </testsuite>
    + </testsuites>
    +</phpunit>
Es wurden keine Einträge gefunden.

Bereit, deine Community smarter zu machen?

Ob fertiges Produkt oder individuelle Softwarelösung – überzeuge dich selbst.

Jetzt kaufen Demo testen

Direkter Support vom Entwickler

Zuletzt erledigte Aufgaben

  1. Multihunter meldet jede Anmeldung als Doppelaccount Multihunter (Doppelaccount Jäger) Multihunter: Forum Benachrichtigungen

    villain Erledigt am 27. Oktober 2026 um 20:09
  2. Multihunter meldet jede Anmeldung als Doppelaccount Multihunter (Doppelaccount Jäger)

    villain Erledigt am 26. Oktober 2026 um 14:41
  3. Optionen vom "Dateien Feld-Typ" sprechen von Bildern Database: Medienfelder

    doerek Erledigt am 25. Oktober 2026 um 18:20
  4. Nach Installation ohne Popup Begriffserklärung

    mbbaureihen.de Erledigt am 24. Oktober 2026 um 23:33
  5. Fehlermeldung beim Hinzufügen einer neuen Clanseite Clan Verwaltung

    BMWTom Erledigt am 24. Oktober 2026 um 23:16
  6. neue Dateiendungen werden nicht übernommen. Database: Medienfelder

    doerek Erledigt am 24. Oktober 2026 um 19:46
Arbeitsplatz
YoureCom – Software für Vereine, Teams & Communities

YoureCom – Software für Vereine, Teams & Communities. Seit 2004.

Fertig eingerichtete Lösungen für Verein, Team und Community, dazu Erweiterungen für die WoltLab Suite. Aus Wuppertal, für Kunden weltweit.

Lösungen

  • Tipprunde
  • Aufgaben & Support
  • Mitglieder-Netzwerk
  • Online-Shop
  • Alle Lösungen & Preise

Für Administratoren

  • Plugins
  • Clan Verwaltung
  • Wettbewerbe
  • MultiHunter
  • ByteMon
  • Individuelle Entwicklung

YoureCom

  • Über mich
  • Shop
  • Kontakt
  • Neuigkeiten
  • GitHub

Cloud-Verträge

  • AGB Cloud
  • AVV Cloud
  • Rechtswidrige Inhalte melden
  • Datenwechsel

Rechtliches

  • Datenschutzerklärung
  • Impressum
  • AGB
  • Vertrag widerrufen
  • Abonnements kündigen
  • Widerrufsbelehrung
© 2026 YoureCom · Marcel Beckers