0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WordPress 管理画面の メディア コピー → ペースト(Ctrl / ⌘ + V)するだけで 画像・音声・動画をメディアライブラリへ保存できるプラグインです

0
Last updated at Posted at 2026-01-11

Clipboard Media Saver Plusというプラグイン

制作した経緯

WP(ワードプレス)のメディアライブラリにメディアをコピペ保存出来るプラグインを作りました.メディアライブラリの項目を開きコントロール+V(ペースト)する事でコピーしたメディアをメディアライブラリに保存できるプラグインです.

この頃、ブログのアイキャッチ画像は画像をクリップボードでコピーして、そのまま記事に貼り付けてメディア保存していたのだけど、それだと記事を書かない時にもそういう対応しないといけないのが手間だったのでプラグインを生成AIと共に作りました.

配布

コードをクローンしたい方はプラグインをgithub上に置いてあるのでご自由にお使い下さい.

ソースコード

clipboard-media-saver-plus.php
<?php

/**
 * Plugin Name: Clipboard Media Saver Plus
 * Description: クリップボードから画像・音声・動画を貼り付けるだけでメディアライブラリに保存
 * Version: 1.1.0
 * Author: @toshiaki_taoka
 * Author URI: https://x.com/toshiaki_taoka
 */

if (!defined('ABSPATH')) exit;

class Clipboard_Media_Saver_Plus
{

    public function __construct()
    {
        add_action('admin_enqueue_scripts', [$this, 'enqueue']);
        add_action('wp_ajax_clipboard_media_upload', [$this, 'upload']);
    }

    public function enqueue($hook)
    {
        // 念のため二重ガード
        if ($hook !== 'upload.php') {
            return;
        }

        wp_enqueue_script(
            'clipboard-media-saver-plus',
            plugin_dir_url(__FILE__) . 'clipboard-media-saver-plus.js',
            [],
            '1.1.0',
            true
        );

        wp_localize_script('clipboard-media-saver-plus', 'CMSP', [
            'ajax'  => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('clipboard_media_upload')
        ]);
    }

    public function upload()
    {
        check_ajax_referer('clipboard_media_upload', 'nonce');

        if (!current_user_can('upload_files')) {
            wp_send_json_error('権限がありません');
        }

        if (empty($_FILES['file'])) {
            wp_send_json_error('ファイルがありません');
        }

        require_once ABSPATH . 'wp-admin/includes/file.php';
        require_once ABSPATH . 'wp-admin/includes/media.php';
        require_once ABSPATH . 'wp-admin/includes/image.php';

        $file = $_FILES['file'];

        // MIMEと拡張子をWP基準で再判定(超重要)
        $check = wp_check_filetype_and_ext(
            $file['tmp_name'],
            $file['name']
        );

        if (!$check['ext'] || !$check['type']) {
            wp_send_json_error('不正なファイル形式');
        }

        $upload = wp_handle_upload($file, [
            'test_form' => false,
            'mimes'     => get_allowed_mime_types()
        ]);

        if (isset($upload['error'])) {
            wp_send_json_error($upload['error']);
        }

        $attachment = [
            'post_mime_type' => $check['type'],
            'post_title'     => sanitize_file_name(pathinfo($file['name'], PATHINFO_FILENAME)),
            'post_status'    => 'inherit'
        ];

        $attach_id = wp_insert_attachment($attachment, $upload['file']);

        // 画像のみメタ生成
        if (strpos($check['type'], 'image/') === 0) {
            $meta = wp_generate_attachment_metadata($attach_id, $upload['file']);
            wp_update_attachment_metadata($attach_id, $meta);
        }

        wp_send_json_success([
            'id'  => $attach_id,
            'url' => wp_get_attachment_url($attach_id),
            'type' => $check['type']
        ]);
    }
}

new Clipboard_Media_Saver_Plus();

clipboard-media-saver-plus.js
(function () {
  document.addEventListener('paste', function (e) {
    if (!document.body.classList.contains('upload-php')) {
      return;
    }

    const items = e.clipboardData?.items || [];

    for (const item of items) {
      if (item.kind !== 'file') continue;

      const file = item.getAsFile();
      if (!file) continue;

      let ext = '';
      if (file.type.startsWith('image/')) ext = '.png';
      else if (file.type.startsWith('image/')) ext = '.jpg';
      else if (file.type.startsWith('image/')) ext = '.gif';
      else if (file.type.startsWith('image/')) ext = '.webp';
      else if (file.type.startsWith('audio/')) ext = '.mp3';
      else if (file.type.startsWith('video/')) ext = '.mp4';
      else continue;

      const filename = file.name && file.name.includes('.')
        ? file.name
        : `clipboard-${Date.now()}${ext}`;

      const formData = new FormData();
      formData.append('action', 'clipboard_media_upload');
      formData.append('nonce', CMSP.nonce);
      formData.append('file', file, filename);

      fetch(CMSP.ajax, {
        method: 'POST',
        credentials: 'same-origin',
        body: formData
      })
        .then(r => r.json())
        .then(r => {
          if (!r.success) {
            alert(r.data || 'Upload failed');
          } else {
            alert('保存しました.リロードします.');
            console.log('Saved:', r.data.url);
            this.location.reload();
          }
        })
        .catch(err => console.error(err));
    }
  });
})();

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?