Ein Blog über Code, Hardware und Co

Wordpress und Webentwicklung

Daten eines eigenen Plugins zum WordPress Userdaten-Export hinzufügen

Zuletzt aktualisiert am 26. April 2021.

Oder: So kannst Du den Nutzern deines Plugins einen DSGVO-koformen Datenexport anbieten.

Mittlerweile ist es nicht nur rechtlich notwendig, Nutzern eine Datenauskunft zu ermöglichen, sondern es gehört zum guten Ton, dem Nutzer nach Möglichkeit die Hoheit über seine Daten zurück zu geben. Das solltest du auch bei deinen WordPress Plugins beachten.

Besonders für Nutzer aus der EU oder Webmaster, deren Webseiten Nutzer in der EU ansprechen, ist es wichtig, dass das EU-Recht seit 2018 die sog. GDPR (“General Data Protection Regulation”) bzw. zu deutsch DSGVO (“Datenschutzgrundverordnung”) beinhaltet, die vorsieht, dass ein Nutzer eine Auskunft über die über ihn gespeicherten Daten verlangen kann.

Datenauskunft in WordPress

Seit WordPress 4.9.6 bietet WordPress von Haus aus umfangreiche Funktionen für den Export von Userdaten und das Löschen von Userdaten, um der GDPR genüge zutun. Sogar ein Prozess, die Datenauskunft anzufordern, freizugeben und dann übersichtlich anzuzeigen, ist integriert.

Nutzerdaten in Plugins

Die Entwickler von WordPress haben hier mit gedacht und die Funktionalität erweiterbar implementiert. Man kann sich ähnlich wie mit Hooks an den Exporter-Prozess anhängen und so zu einem Nutzer entsprechend auch im Plugin hinterlassene Daten zu einem Datenexport hinzufügen.

Achtung: Der Identifier ist hierbei NICHT die user_id, sondern eine E-Mail-Adresse.

Der Prozess des Nutzerdatenexports ist dann eine Art Loop-Prozess, der alle angehängten Funktionen mit durchläuft und die durch eine entsprechende Callback-Funktion übergebenen Daten mit in den Datenexport einbaut.

So bindest du dein Plugin in die WordPress-Datenauskunft ein

Am Beispiel des WP-Event-Manager-Plugins

Ich nutze in diversen Projekten gerne das Plugin “WP-Event-Manager“. Leider bietet das Plugin von sich aus keine Integration in den WordPress-Datenexport an. Also bauen wir uns eine 😉
Wir folgen hierbei der Empfehlung direkt von den WordPress-Entwicklern.

Um die Daten deines Plugins an einen Export anzuhängen, musst du die entsprechende Funktion schreiben, die aufgerufen wird und die Daten zurückgibt.
Als Parameter wird dieser Funktion eine Mailadresse als Identifier übergeben.

Optional kann der Funktion noch ein “page”-Parameter übergeben werden, der bei großen Datenexports dazu dient, Timeouts zu vermeiden. So kann der Export auf mehrere “Requests” aufgeteilt werden und eine Paginierung genutzt werden.

Schritt 1) Callback-Funktion erstellen

/**
 * Export user meta for a user using the supplied email.
 *
 * @param string $email_address   email address to manipulate
 * @param int    $page            pagination
 *
 * @return array
 */
function wp_event_manager_registrations_export( $email_address, $page = 1 ) {
    $number = 500; // Limit us to avoid timing out
    $page   = (int) $page;

    $export_items = array();

    $args = array(
            'post_type' => 'event_registration',
            'number'       => $number,
            'paged'        => $page,
            'meta_key'     => 'deine_mailadresse',
            'meta_value'   => $email_address,
        );
   $event_registrations = new WP_Query($args);
   $event_registrations = $event_registrations->posts;

    foreach ( (array) $event_registrations as $registration ) {
            $event_name = get_post_meta( $registration->ID, '_event_registered_for', true );
            $post_date = $registration->post_date;
            $einverstaendnis = get_post_meta( $registration->ID, 'einverstaendnis', true );
            $email = get_post_meta( $registration->ID, 'deine_mailadresse', true );
            $name = get_post_meta( $registration->ID, 'dein_name', true );


        // Only add data to the export if email is not empty.
        if (!empty( $email ) ) {
            // Most item IDs should look like postType-postID. If you don't have a post, comment or other ID to work with,
            // use a unique value to avoid having this item's export combined in the final report with other items
            // of the same id.
            $item_id = "registration-{$registration->ID}";

            // Core group IDs include 'comments', 'posts', etc. But you can add your own group IDs as needed
            $group_id = 'posts';

            // Optional group label. Core provides these for core groups. If you define your own group, the first
            // exporter to include a label will be used as the group label in the final exported report.
            $group_label = __( 'Event Bewerbungen', 'text-domain' );

            // Plugins can add as many items in the item data array as they want.
            $data = array(
                array(
                    'name'  => __( 'Name des Events', 'text-domain' ),
                    'value' => $event_name,
                ),
                array(
                    'name'  => __( 'Bewerbungszeitpunkt', 'text-domain' ),
                    'value' => $post_date,
                ),
                array(
                    'name'  => __( 'Einverstaendnis', 'text-domain' ),
                    'value' => $einverstaendnis,
                ),
                array(
                    'name'  => __( 'E-Mail Adresse', 'text-domain' ),
                    'value' => $email,
),
                array(
                    'name'  => __( 'Dein Name', 'text-domain' ),
                    'value' => $name,
                ),
            );

            $export_items[] = array(
                'group_id'    => $group_id,
                'group_label' => $group_label,
                'item_id'     => $item_id,
                'data'        => $data,
            );
        }
    }

    // Tell core if we have more comments to work on still.
    $done = count( (array) $event_registrations ) < $number;
    return array(
        'data' => $export_items,
        'done' => $done,
    );
}

                                                                       

Schritt 2) Den Exporter registrieren und über den Filter “wp_privacy_personal_data_exporters” anhängen

//Filter Registieren, der den Exporter für das WP-Event-Plugin hinzufügt
/**
 * Registers all data exporters.
 *
 * @param array $exporters
 *
 * @return mixed
 */
function wporg_register_user_data_exporters( $exporters ) {
    $exporters['wp-event-manager-registrations'] = array(
        'exporter_friendly_name' => __( 'Aktionsteilnahmen', 'text-domain' ),
        'callback'               => 'wp_event_manager_registrations_export',
    );
    return $exporters;
}

add_filter( 'wp_privacy_personal_data_exporters', 'wporg_register_user_data_exporters' );

Das Löschen von Userdaten

Ebenfalls mit WordPress 4.9.6 ist eine Funktionalität zum Löschen persönlicher Daten integriert worden. Die Einbindung läuft dabei sehr ähnlich zum Prozess des Datenexports ab:

Man hängt sich mit seiner eigenen Löschfunktionalität an den “Eraser”-Hook an und lässt seine Callbackfunktion die Daten löschen. Auch hier iteriert eine Ajax-Schleife beim Auslösen einer Datenlöschung über alle mit dem Nutzer verbundenen Daten.
Auch hier ist die E-Mail-Adresse der key.

Schritt 1)

Callback-Funktion erstellen

/**
 * Removes any stored location data from a user's comment meta for the supplied email address.
 *
 * @param string $email_address   email address to manipulate
 * @param int    $page            pagination
 *
 * @return array
 */
function wp_event_manager_registrations_eraser( $email_address, $page = 1 ) {
    $number = 500; // Limit us to avoid timing out
    $page   = (int) $page;
 
        $args = array(
            'post_type' => 'event_registration',
            'number'       => $number,
            'paged'        => $page,
            'meta_key'     => 'deine_mailadresse',
            'meta_value'   => $email_address,
        );
   $event_registrations = new WP_Query($args);
   $event_registrations = $event_registrations->posts;
 
    $items_removed = false;
 
    foreach ( (array) $event_registrations as $event_registration ) {
            $email = get_post_meta( $registration->ID, 'deine_mailadresse', true );
            
        if ( ! empty( $email ) ) {
            wp_delete_post( $registration->ID, $force_delete = false )
            $items_removed = true;
        }
 
    }
 
    // Tell core if we have more comments to work on still
    $done = count( $comments ) < $number;
    return array(
        'items_removed'  => $items_removed,
        'items_retained' => false, // always false in this example
        'messages'       => array(), // no messages in this example
        'done'           => $done,
    );
}

Schritt 2)

Die zuvor erstellte Eraser-Callback-Funktion an den registrierten Filter “wp_privacy_personal_data_erasers” anhängen:

/**
 * Registers all data erasers.
 *
 * @param array $exporters
 *
 * @return mixed
 */
function wporg_register_privacy_erasers( $erasers ) {
    $erasers['wp-event-manager-registrations'] = array(
        'eraser_friendly_name' => __( 'Aktionsteilnahmen', 'text-domain' ),
        'callback'             => 'wp_event_manager_registrations_eraser',
    );
    return $erasers;
}
 
add_filter( 'wp_privacy_personal_data_erasers', 'wporg_register_privacy_erasers' );

Stolpersteine

  • In der offiziellen WP-Doku ist das Größer/Kleiner-Zeichen für den Check der Anzahl der Ergebnisse und die Paginierung falschherum. So kommt es u.U. zu einer Endlosschleife.
  • WP_Query() gibt ein Objekt zurück, mittels foreach kann man jedoch nur über Arrays iterieren. Daher muss man zunächst explizit die Posts aus dem Objekt holen und dann als array casten.

Quellen:

  • https://developer.wordpress.org/plugins/privacy/adding-the-personal-data-exporter-to-your-plugin/
  • https://developer.wordpress.org/plugins/privacy/adding-the-personal-data-eraser-to-your-plugin/

Schreibe eine Antwort