Veröffentlichen Sie keine benutzerdefinierten Posts vom Typ Post, wenn ein Metadatenfeld nicht gültig ist

12

Ich habe einen benutzerdefinierten Beitragstyp (CPT) namens event. Ich habe eine Meta-Box für den Typ mit mehreren Feldern. Ich möchte einige Felder validieren, bevor ich ein Ereignis veröffentliche. Wenn beispielsweise das Datum eines Ereignisses nicht angegeben ist, möchte ich eine informative Fehlermeldung anzeigen, das Ereignis für die zukünftige Bearbeitung speichern, aber verhindern, dass dieses Ereignis veröffentlicht wird. Ist der Status "Ausstehend" für einen CPT-Beitrag ohne alle erforderlichen Informationen der richtige Weg, um ihn zu behandeln?

Was ist die beste Vorgehensweise, um die Validierung von CPT-Feldern durchzuführen und zu verhindern, dass ein Beitrag veröffentlicht wird? Speichern Sie ihn jedoch für die zukünftige Bearbeitung.

Vielen Dank, Dasha

Dashaluna
quelle
Ein sanfter Anstoß, um Sie daran zu erinnern, dass diese Frage noch eine akzeptierte Antwort benötigt ..;) Wenn keine Antwort auf Ihre Frage eingegangen ist, sollten Sie Ihre Frage mit zusätzlichen Kommentaren aktualisieren, in denen angegeben ist, was nicht angesprochen wurde (oder wo Sie gegebenenfalls Hilfe benötigen).
t31os

Antworten:

14

Sie können verhindern, dass der Beitrag alle zusammen mit kleineren JQuery-Hacks speichert, und die Felder überprüfen, bevor Sie auf der Client- oder Serverseite mit Ajax speichern:

Zuerst fügen wir unser JavaScript hinzu, um das Submit / Publish-Ereignis zu erfassen und verwenden es, um unsere eigene Ajax-Funktion vor dem eigentlichen Submit zu senden:

 add_action('wp_print_scripts','my_publish_admin_hook');

function my_publish_admin_hook(){
if (is_admin()){
        ?>
        <script language="javascript" type="text/javascript">
            jQuery(document).ready(function() {
                jQuery('#post').submit(function() {

                    var form_data = jQuery('#post').serializeArray();
                    form_data = jQuery.param(form_data);
                    var data = {
                        action: 'my_pre_submit_validation',
                        security: '<?php echo wp_create_nonce( 'pre_publish_validation' ); ?>',
                        form_data: form_data
                    };
                    jQuery.post(ajaxurl, data, function(response) {
                        if (response.indexOf('True') > -1 || response.indexOf('true') > -1 || response === true ||  response) {
                            jQuery('#ajax-loading').hide();
                            jQuery('#publish').removeClass('button-primary-disabled');
                            return true;
                        }else{
                            alert("please correct the following errors: " + response);
                            jQuery('#ajax-loading').hide();
                            jQuery('#publish').removeClass('button-primary-disabled');
                            return false;
                        }
                    });
                    return false;
                });
            });
        </script>
        <?php
    }
}

dann erstellen wir die Funktion für die eigentliche Validierung:

add_action('wp_ajax_my_pre_submit_validation', 'pre_submit_validation');
function pre_submit_validation(){
    //simple Security check
    check_ajax_referer( 'pre_publish_validation', 'security' );

    //do your validation here
    //all of the form fields are in $_POST['form_data'] array
    //and return true to submit: echo 'true'; die();
    //or your error message: echo 'bal bla bla'; die();
}

Sie können es jederzeit ein wenig ändern, um die Validierung nur für Ihren Beitragstyp durchzuführen, indem Sie eine bedingte Prüfung hinzufügen, um my_publish_admin_hookfür Ihren Beitragstyp zu funktionieren und auf der Clientseite zu validieren, aber ich bevorzuge auf der Serverseite.

Bainternet
quelle
Gibt es keine serverseitige Möglichkeit, dies zu tun?
Jeff
1
Dies ist eine serverseitige Methode.
Bainternet
1
Vielleicht verstehe ich etwas falsch. Es sieht so aus, als würden Sie nur PHP verwenden, um JavaScript zu rendern, das die Validierung durchführt. Das ist keine serverseitige Validierung. Ich verstehe nicht wirklich, wie das pre_submit_validationpasst.
Jeff
Der erste my_publish_admin_hookBlock fängt die Client-Seite nach der Übermittlung ab pre_submit_validation, führt dann jedoch einen AJAX-Aufruf an den Server durch (Pre-Official-Submit-In ), der die serverseitige Validierung durchführt.
emc
1
Dies ist immer noch eine clientseitige Validierung, selbst wenn AJAX für die Validierung verwendet wird. Der Client muss zuerst das JavaScript ausführen, damit eine Validierung stattfinden kann. Allerdings ... fand ich diese Antwort immer noch nützlich für die Validierung vor der Einreichung. Vielen Dank!
Cr0ybot
7

Die Methode besteht aus zwei Schritten: Erstens einer Funktion zum Speichern Ihrer benutzerdefinierten Metabox-Felddaten (verknüpft mit save_post) und zweitens einer Funktion zum Lesen dieser neuen post_meta (die Sie gerade gespeichert haben), zum Überprüfen und Ändern des Ergebnisses von Speichern nach Bedarf (auch mit save_post verbunden, jedoch nach dem ersten). Wenn die Validierungsfunktion fehlschlägt, ändert die Validierungsfunktion den post_status direkt wieder in "ausstehend", wodurch effektiv verhindert wird, dass der Post veröffentlicht wird.

Da die Funktion save_post häufig aufgerufen wird, muss jede Funktion nur dann ausgeführt werden, wenn der Benutzer sie veröffentlichen möchte, und nur für Ihren benutzerdefinierten Beitragstyp (mycustomtype).

Normalerweise füge ich auch einige benutzerdefinierte Benachrichtigungsnachrichten hinzu, damit der Benutzer weiß, warum sein Beitrag nicht veröffentlicht wurde, aber diese wurden hier etwas kompliziert ...

Ich habe diesen genauen Code nicht getestet, aber es ist eine vereinfachte Version dessen, was ich in umfangreichen benutzerdefinierten Post-Type-Setups getan habe.

add_action('save_post', 'save_my_fields', 10, 2);
add_action('save_post', 'completion_validator', 20, 2);

function save_my_fields($pid, $post) {
    // don't do on autosave or when new posts are first created
    if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
    // abort if not my custom type
    if ( $post->post_type != 'mycustomtype' ) return $pid;

    // save post_meta with contents of custom field
    update_post_meta($pid, 'mymetafield', $_POST['mymetafield']);
}


function completion_validator($pid, $post) {
    // don't do on autosave or when new posts are first created
    if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || $post->post_status == 'auto-draft' ) return $pid;
    // abort if not my custom type
    if ( $post->post_type != 'mycustomtype' ) return $pid;

    // init completion marker (add more as needed)
    $meta_missing = false;

    // retrieve meta to be validated
    $mymeta = get_post_meta( $pid, 'mymetafield', true );
    // just checking it's not empty - you could do other tests...
    if ( empty( $mymeta ) ) {
        $meta_missing = true;
    }

    // on attempting to publish - check for completion and intervene if necessary
    if ( ( isset( $_POST['publish'] ) || isset( $_POST['save'] ) ) && $_POST['post_status'] == 'publish' ) {
        //  don't allow publishing while any of these are incomplete
        if ( $meta_missing ) {
            global $wpdb;
            $wpdb->update( $wpdb->posts, array( 'post_status' => 'pending' ), array( 'ID' => $pid ) );
            // filter the query URL to change the published message
            add_filter( 'redirect_post_location', create_function( '$location','return add_query_arg("message", "4", $location);' ) );
        }
    }
}

Fügen Sie für mehrere Metabox-Felder einfach weitere Abschlussmarkierungen hinzu, rufen Sie mehr post_meta ab und führen Sie weitere Tests durch.

somatisch
quelle
1

Sie müssen Ihren Metafeldwert auf Ajax überprüfen / validieren, dh wenn der Benutzer auf die Schaltfläche "Veröffentlichen / Aktualisieren" klickt. Hier validiere ich ein Woocommerce-Produkt mit dem Metafeld "product_number" für einen leeren Wert.

add_action('admin_head-post.php','ep_publish_admin_hook');
add_action('admin_head-post-new.php','ep_publish_admin_hook');

function ep_publish_admin_hook(){
    global $post;
    if ( is_admin() && $post->post_type == 'product' ){
        ?>
        <script language="javascript" type="text/javascript">
            (function($){
                jQuery(document).ready(function() {

                    jQuery('#publish').click(function() {
                        if(jQuery(this).data("valid")) {
                            return true;
                        }

                        //hide loading icon, return Publish button to normal
                        jQuery('#publishing-action .spinner').addClass('is-active');
                        jQuery('#publish').addClass('button-primary-disabled');
                        jQuery('#save-post').addClass('button-disabled');

                        var data = {
                            action: 'ep_pre_product_submit',
                            security: '<?php echo wp_create_nonce( "pre_publish_validation" ); ?>',
                            'product_number': jQuery('#acf-field-product_number').val()
                        };
                        jQuery.post(ajaxurl, data, function(response) {

                            jQuery('#publishing-action .spinner').removeClass('is-active');
                            if ( response.success ){
                                jQuery("#post").data("valid", true).submit();
                            } else {
                                alert("Error: " + response.data.message );
                                jQuery("#post").data( "valid", false );

                            }
                            //hide loading icon, return Publish button to normal
                            jQuery('#publish').removeClass('button-primary-disabled');
                            jQuery('#save-post').removeClass('button-disabled');
                        });
                        return false;
                    });
                });
            })(jQuery);
        </script>
        <?php
    }
}

Fügen Sie danach die Ajax-Handler-Funktion hinzu.

add_action('wp_ajax_ep_pre_product_submit', 'ep_pre_product_submit_func');
function ep_pre_product_submit_func() {
    //simple Security check
    check_ajax_referer( 'pre_publish_validation', 'security' );

    if ( empty( $_POST['product_number'] ) || empty( $_POST['file_attachment'] ) ) {
         $data = array(
            'message' => __('Please enter part number and specification document.'),
        );
        wp_send_json_error( $data );
    }
    wp_send_json_success();
}
Mohan Dere
quelle
0

Ich wollte nur hinzufügen, dass Sie zum Lesen der Post-Variablen mithilfe der Bainternet-Lösung die Zeichenfolge $_POST['form_data']mithilfe der PHP- parse_strFunktion analysieren müssen (nur um Zeit für die Recherche zu sparen).

$vars = parse_str( $_POST['form_data'] );

Dann können Sie mit nur auf jede Variable zugreifen $varname. Wenn Sie beispielsweise ein Metafeld mit dem Namen "my_meta" haben, können Sie folgendermaßen darauf zugreifen:

$vars = parse_str ( $_POST['form_data'] ) 
if ( $my_meta == "something" ) { // do something }
Agus
quelle