web-dev-qa-db-fra.com

Existe-t-il un moyen simple d’économiser AJAX-ify?

Nous avons un plugin qui nous permet de gérer des types de publication personnalisés et nous aimerions ajouter la fonctionnalité AJAX lors de la sauvegarde, de la modification et de la suppression de publications. Je ne pouvais pas trouver de problèmes similaires sur Internet, alors je me demande si ce n'est pas quelque chose de facilement faisable?

1
jilseego

Vous pouvez techniquement créer un fichier XHR sur post.php via JavaScript. Vous trouverez ci-dessous une démonstration de principe pour l'enregistrement/la modification de messages uniquement. Je ne l'ai pas du tout testé, alors je suis sûr que vous devrez l'améliorer. Je voulais vous donner un flux de travail de base pour accomplir quelque chose comme ça. Vous pouvez le prendre et le suivre si vous avez besoin de l'étendre.

Étape 1: Ajoutez le gestionnaire AJAX à admin_head pour les publications nouvelles et existantes.

function my_post_type_xhr(){
    global $post;
    if('my_post_type' === $post->post_type){
        $post_url = admin_url('post.php'); #In case we're on post-new.php
        echo "
        <script>
            jQuery(document).ready(function($){
                //Click handler - you might have to bind this click event another way
                $('input#publish, input#save-post').click(function(){
                    //Post to post.php
                    var postURL = '$post_url';

                    //Collate all post form data
                    var data = $('form#post').serializeArray();

                    //Set a trigger for our save_post action
                    data.Push({foo_doing_ajax: true});

                    //The XHR Goodness
                    $.post(postURL, data, function(response){
                        var obj = $.parseJSON(response);
                        if(obj.success)
                            alert('Successfully saved post!');
                        else
                            alert('Something went wrong. ' + response);
                    });
                    return false;
                });
            });
        </script>";
    }
}
add_action('admin_head-post.php', 'my_post_type_xhr');
add_action('admin_head-post-new.php', 'my_post_type_xhr');

Étape 2: Accrochez-vous dans l'action save_post.

Ceci s’exécute après que le message ait été sauvegardé dans la base de données, vous pouvez donc sauvegarder le postmeta dont vous avez besoin et arrêter le rendu de la page.

add_action('save_post', 'save_my_post_type');
function save_my_post_type($post_id){
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;

    #If this is your post type
    if('my_post_type' === $_POST['post_type']){
        //Save any post meta here

        #We conditionally exit so we don't return the full wp-admin load if foo_doing_ajax is true
        if(isset($_POST['foo_doing_ajax']) && $_POST['foo_doing_ajax'] === true){
            header('Content-type: application/json');
            #Send a response
            echo json_encode(array('success' => true));
            exit;
            #You should keep this conditional to degrade gracefully for no JS
        }
    }
}

Le seul inconvénient majeur que je puisse voir est que vous devrez rafraîchir les onces de la page en quelque sorte via XHR.

Pour supprimer un message, je ne sais pas pourquoi vous voudriez utiliser AJAX quand il s'agit d'un simple clic sur un lien qui fait déjà le travail. Supprimer une page dans tous les cas vous enverra à une autre page, à savoir edit.php. Cela annule le but d'utiliser AJAX qui consiste à tout conserver de manière asynchrone lors du chargement d'une page.

J'espère que cela vous aide.

3
Brian Fegter

La réponse de Brian Fegter était la bonne idée, mais il y avait quelques bugs. Voici une solution plus raffinée basée sur le même principe.

Étape 1: PHP Logique.

Placez dans functions.php (ou un fichier de plugin)

// Saving the post via AJAX
add_action('save_post', 'save_post_ajax');
function save_post_ajax( $post_id )
{
        # Ignore autosaves
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
                return;

        # Only enabled for one post type
        # Remove this if statement if you want to enable for all post types
        if ($_POST['post_type'] == 'my_custom_post_type')
        {
                # Send JSON response
                # NOTE: We use ==, not ===, because the value may be String("true")
                if (isset($_POST['save_post_ajax']) && $_POST['save_post_ajax'] == TRUE)
                {
                        header('Content-type: application/json');
                        echo json_encode(array('success' => true));

                        # Don't return full wp-admin
                        exit;
                }
        }
}

Étape 2: Créer du javascript dans un fichier externe

La solution de Brian consistant à envoyer le js directement à la page fonctionne également.

// Avoid collisions with other libraries
(function($) {
        // Make sure the document is ready
        $(document).ready(function() {
                // This is the post.php url we localized (via php) above
                var url = ajax_object.post_url;
                // Serialize form data
                var data = $('form#post').serializeArray();
                // Tell PHP what we're doing
                // NOTE: "name" and "value" are the array keys. This is important. I use int(1) for the value to make sure we don't get a string server-side.
                data.Push({name: 'save_post_ajax', value: 1});

                // Replaces wp.autosave.initialCompareString
                var ajax_updated = false;

                /**
                 * Supercede the WP beforeunload function to remove
                 * the confirm dialog when leaving the page (if we saved via ajax)
                 * 
                 * The following line of code SHOULD work in $.post.done(), but 
                 *     for some reason, wp.autosave.initialCompareString isn't changed 
                 *     when called from wp-includes/js/autosave.js
                 * wp.autosave.initialCompareString = wp.autosave.getCompareString();
                 */
                $(window).unbind('beforeunload.edit-post');
                $(window).on( 'beforeunload.edit-post', function() {
                        var editor = typeof tinymce !== 'undefined' && tinymce.get('content');

                        // Use our "ajax_updated" var instead of wp.autosave.initialCompareString
                        if ( ( editor && !editor.isHidden() && editor.isDirty() ) ||
                                ( wp.autosave && wp.autosave.getCompareString() != ajax_updated) ) { 
                                return postL10n.saveAlert;
                        }   
                });


                // Post it
                $.post(url, data, function(response) {
                        // Validate response
                        if (response.success) {
                                // Mark TinyMCE as saved
                                if (typeof tinyMCE !== 'undefined') {
                                        for (id in tinyMCE.editors) {
                                                var editor = tinyMCE.get(id);
                                                editor.isNotDirty = true;
                                        }   
                                }
                                // Update the saved content for the beforeunload check
                                ajax_updated = wp.autosave.getCompareString();

                                console.log('Saved post successfully');
                        } else {
                                console.log('ERROR: Server returned false. ',response);
                        }
                }).fail(function(response) {
                        console.log('ERROR: Could not contact server. ',response);
                });
        });     
})(jQuery);

Étape 3: Mettez votre fichier javascript en file d'attente

Si vous l'avez répercuté (comme Brian), vous n'avez pas à le faire. Je préfère cette méthode car elle nous permet de libérer le script, de localiser les variables et d'ajuster facilement l'ordre de chargement du script.

function my_post_type_xhr()
{
        global $post;
        # Only for one post type. 
        if ($post->post_type == 'custom_post_type')
        {
                # The url for the js file we created above
                $url = '/url/to/my/javascript.js';

                # Register and enqueue the script, dependent on jquery
                wp_register_script( 'my_script', $url, array('jquery') );
                wp_enqueue_script( 'my_script' );

                # Localize our variables for use in our js script
                wp_localize_script( 'my_script', 'ajax_object', array(
                                'post_id' => $post_id,
                                'post_url' => admin_url('post.php'),
                ) );
        }
}

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

Cet extrait ne concerne pas les nonces. Quoi qu'il en soit, j'espère que cela aidera quelqu'un.

3
Jess Mann