web-dev-qa-db-fra.com

WP Rest Rest API - Télécharger un média sans enregistrer la publication en pièce jointe

J'ai besoin de raccrocher après le téléchargement du fichier sur le serveur, obtenir le chemin du fichier, puis empêcher WordPress de sauvegarder la publication en pièce jointe.

J'ai trouvé ce filtre add_filter('attachment_fields_to_save', 'attachment_stuff'); mais c'est après la création de la pièce jointe que je souhaite accrocher avant la sauvegarde de la publication.

Mise à jour 26.03.2018

J'ai fini par utiliser un terminal multimédia personnalisé pour enregistrer les fichiers sans enregistrer une publication en pièce jointe. Exemple complet ci-dessous dans answer

3
BenB

Selon vos commentaires, vous utilisez apparemment l'API REST. Il n'y a pas d'accrochage entre le téléchargement du fichier et la création de la publication de pièce jointe qui pourrait être utilisé à cette fin dans le noeud final de l'API.

Le mieux que vous puissiez faire semble être d'utiliser l'action rest_insert_attachment. Il fournit des fonctions de rappel avec l'objet WP_Post pour la publication en pièce jointe et l'objet WP_REST_Request représentant la demande. Cette action est appelée immédiatement après la création de la pièce jointe, mais avant la génération de métadonnées ou de tailles. Vous pouvez donc vous connecter ici, vérifier la requête pour le drapeau que vous utilisez pour identifier les supports qui ne devraient pas être enregistrés en tant que publication, obtenez le chemin, puis supprimez la publication en pièce jointe.

function wpse_297026_rest_insert_attachment( $attachment, $request, $creating ) {
    // Only handle new attachments.
    if ( ! $creating ) {
        return;
    }

    // Check for parameter on request that tells us not to create an attachment post.
    if ( $request->get_param( 'flag' ) == true ) {
        // Get file path.
        $file = get_attached_file( $attachment->ID );

        // Do whatever you need to with the file path.

        // Delete attachment post.
        wp_delete_post( $attachment->ID );

        // Kill the request and send a 201 response.
        wp_die('', '', 201);
    }
}
add_action( 'rest_insert_attachment', 'wpse_297026_rest_insert_attachment' )

Je pense qu'il faut souligner que si vous ne créez pas de pièces jointes, vous ne devriez pas utiliser le point de terminaison de la pièce jointe. C'est pourquoi nous devons tuer maladroitement la requête contenue dans ce code. Tout ce qui suit rest_insert_attachment suppose l’existence d’une publication en pièce jointe et la majeure partie du code du contrôleur de ce noeud final est dédiée à la création et à la gestion de données ayant un sens pour une publication en pièce jointe. Vous devriez probablement créer votre propre terminal pour ce type de travail.

3
Jacob Peattie

Le téléchargement du fichier et la création d’une pièce jointe sont gérés par la fonction media_handle_upload . Comme vous pouvez le constater à partir de la source, il télécharge d'abord le fichier, puis commence à rassembler les métadonnées (y compris de longs morceaux de fichiers audio), puis appelle wp_insert_attachment pour créer la publication en pièce jointe. Il n'y a pas d'endroit où vous pouvez vous accrocher.

Cette dernière fonction est juste un espace réservé pour wp_insert_post . Ici, vous avez pas mal de crochets pour filtrer les métadonnées. Cependant, il existe une seule condition empêchant la publication du poste, où il est indiqué if ( ! empty( $import_id ) ). Et il n'y a pas de moyen évident de jouer avec $import_id. Donc, vous êtes coincé.

Sauf qu'un peu plus tard dans la fonction, il y a cet appel: do_action( 'add_attachment', $post_ID );. Cela se déclenche juste après la création d'un article en pièce jointe. Vous pouvez utiliser ceci pour supprimer immédiatement le message:

add_action ('add_attachment', 'wpse297026_delete_post');
function wpse297026_delete_post ($post_ID) {
  wp_delete_post ($post_ID);
  }

Cela laissera le fichier téléchargé à sa place, mais WordPress l'aura perdu de vue.

2
cjbj

J'ai fini par utiliser le code du point de terminaison wp media dans un point de terminaison personnalisé sans enregistrer la partie post.

Voici un exemple complet sur le thème des vingt-sept enfants au cas où quelqu'un en aurait besoin.

  1. Ajoutez ceci à functions.php

    $Custom_Media_Uploader = new Custom_Media_Uploader();
    $Custom_Media_Uploader->init();
    
    class Custom_Media_Uploader {
    
      function init() {
        add_action( 'rest_api_init', [ $this, 'register_routes' ] );
    
      }
    
    
      function register_routes() {
        $version   = '1';
        $namespace = 'custom-end-point/v' . $version;
        $base      = 'media';
        register_rest_route( $namespace, '/' . $base, array(
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'upload_file' ],
                'permission_callback' => [ $this, 'file_upload_permissions' 
             ],
                'args'                => [],
            ]
        ) );
    }
    
      function file_upload_permissions() {
        return is_user_logged_in();
      }
    
      function upload_file( $request ) {
        $params = $request->get_params();
    
        if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array(
                'revision',
                'attachment'
            ), true )
        ) {
            return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) );
        }
      // Get the file via $_FILES or raw data.
        $files   = $request->get_file_params();
        $headers = $request->get_headers();
        if ( ! empty( $files ) ) {
            $file = $this->upload_from_file( $files, $headers );
        } else {
            $file = $this->upload_from_data( $request->get_body(), $headers );
        }
        if ( is_wp_error( $file ) ) {
            return $file;
        }
        $name       = basename( $file['file'] );
        $name_parts = pathinfo( $name );
        $name       = trim( substr( $name, 0, - ( 1 + strlen( $name_parts['extension'] ) ) ) );
        $url        = $file['url'];
        $type       = $file['type'];
        $file       = $file['file'];
    
        return [ 'url' => $url, 'type' => $type ];
      }
    
    
    /**
     * Handles an upload via multipart/form-data ($_FILES).
     *
     * @since 4.7.0
     *
     * @param array $files Data from the `$_FILES` superglobal.
     * @param array $headers HTTP headers from the request.
     *
     * @return array|WP_Error Data from wp_handle_upload().
     */
      protected function upload_from_file( $files, $headers ) {
    
        if ( empty( $files ) ) {
            return new WP_Error( 'rest_upload_no_data', __( 'No data supplied.' ), array( 'status' => 400 ) );
        }
    // Verify hash, if given.
        if ( ! empty( $headers['content_md5'] ) ) {
            $content_md5 = array_shift( $headers['content_md5'] );
            $expected    = trim( $content_md5 );
            $actual      = md5_file( $files['file']['tmp_name'] );
            if ( $expected !== $actual ) {
                return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected.' ), array( 'status' => 412 ) );
            }
        }
      // Pass off to WP to handle the actual upload.
        $overrides = array(
            'test_form' => false,
        );
     // Bypasses is_uploaded_file() when running unit tests.
        if ( defined( 'DIR_TESTDATA' ) && DIR_TESTDATA ) {
            $overrides['action'] = 'wp_handle_mock_upload';
        }
        /** Include admin functions to get access to wp_handle_upload() */
        require_once ABSPATH . 'wp-admin/includes/admin.php';
        $file = wp_handle_upload( $files['file'], $overrides );
        if ( isset( $file['error'] ) ) {
            return new WP_Error( 'rest_upload_unknown_error', $file['error'], array( 'status' => 500 ) );
        }
    
        return $file;
      }
    }
    
  1. créez un fichier sur la racine du thème avec le nom page-upload.php

    <?php get_header(); ?>
         <div class="wrap">
         <div id="primary" class="content-area">
          <main id="main" class="site-main" role="main">
            <input type='file' onchange="uploadFile(this);"/>
            <div style="display:none" id="ajax-response">
                <div><b>File URL: </b><span id="file-url"></span></div>
                <div><b>File type: </b><span id="file-type"></span></div>
                <div></div>
            </div>
        </main><!-- #main -->
      </div><!-- #primary -->
    </div><!-- .wrap -->
    
    <script>
    function uploadFile(input) {
        if (input.files && input.files[0]) {
            var file = input.files[0];
            var formData = new FormData();
            formData.append('file', file);
    
            // Fire the request.
            jQuery.ajax({
                url: '<?php echo esc_url_raw( rest_url() ) ?>custom-end-point/v1/media',
                method: 'POST',
                processData: false,
                contentType: false,
                beforeSend: function (xhr) {
                    xhr.setRequestHeader('X-WP-Nonce', '<?php echo wp_create_nonce( 'wp_rest' ) ?>');
                },
                data: formData
            }).success(function (response) {
                jQuery('#file-url').text(response.url);
                jQuery('#file-type').text(response.type);
                jQuery('#ajax-response').show();
                console.log(response);
            }).error(function (response) {
                console.log(response);
            });
    
        }
    }
    </script>
    
    <?php get_footer();
    
  2. Créez et enregistrez une page avec le titre "upload" et accédez au site www.domain.com/upload, téléchargez un fichier et vous pourrez voir l'URL et le type de fichier renvoyés à partir du point de terminaison du média après le téléchargement d'un fichier.

Assurez-vous que vous êtes connecté et que les permaliens sont configurés sur post-name pour permettre au point final de fonctionner.

1
BenB