Source: attachment/Shortcut.class.php

<?php
namespace MatthiasWeb\RealMediaLibrary\attachment;
use MatthiasWeb\RealMediaLibrary\general;
use MatthiasWeb\RealMediaLibrary\base;

defined( 'ABSPATH' ) or die( 'No script kiddies please!' );

/**
 * Handle the metadata and attached file for shortcuts.
 */
class Shortcut extends base\Base {
	private static $me = null;
    
    /**
     * @see Shortcut::create()
     */
    private $lockCreate = false;
    
    /**
     * @see this::create()
     * @see this::getLastIds()
     * @see this::_resetLastIds()
     */
    private $lastIds = false;
    
    private function __construct() {
        // Silence is golden.
    }
    
    /**
     * Creates a shortcut.
     * 
     * @see wp_rml_create_shortcuts
     * @see _wp_rml_synchronize_attachment
     */
    public function create($postId, $fid, $isShortcut = false) {
        global $wpdb;
        
        // Is locked?
        if ($this->lockCreate === true) {
            $this->lockCreate = false;
            return false;
        }
        
        // Collect data
        $table_name = $this->getTableName("posts");
        $oldFolder = wp_attachment_folder($postId);
        $isShortcut = $isShortcut ? 1 : 0;
        $attachmentId = $postId; // The id for the realmedialibrary_posts table
        
        // Check if attachment exists
        if (get_post_type($postId) !== "attachment") {
            return false;
        }
        
        // Process
        if ($isShortcut > 0) {
            // Ensure, that we are working with the source file and not create a shortcut from a shortcut...
            $postId = wp_attachment_ensure_source_file($postId);

            // Prepare the new post
            $wp_post = get_post($postId);
            $new_post = array(
                "guid" => $wp_post->guid . "?sc=" . $postId,
                "post_mime_type" => $wp_post->post_mime_type,
                "post_title" => $wp_post->post_title,
                "post_content" => "",
                "post_excerpt" => $wp_post->post_excerpt, // Caption
                "post_content" => $wp_post->post_content, // Description
                "post_status" => "inherit"
            );
            $attachedFile = get_attached_file($postId);
            
            // Create new post
            $this->lockCreate = true;
            try {
                $scId = wp_insert_attachment($new_post, $attachedFile);
                
                // Copy alt text if present
                $altText = get_post_meta($postId, '_wp_attachment_image_alt', true);
                if (!empty($altText)) {
                    update_post_meta($scId, '_wp_attachment_image_alt', $altText);
                }
                
                $this->debug("Shortcut for " . $postId . " created in posts table with id " . $scId, __METHOD__);
                $this->lockCreate = false;
            }catch (\Exception $e) {
                $this->lockCreate = false;
                return false;
            }
            $attachmentId = $scId;
            $this->lastIds[] = $attachmentId;
            $isShortcut = $postId;
        }else{
            $isShortcut = wp_attachment_is_shortcut($postId, true);
        }
        
        // Insert or update the new attachment relationship
        $sql = $wpdb->prepare("INSERT INTO $table_name (`attachment`, `fid`, `isShortcut`)
            VALUES (%d, %d, %d) ON DUPLICATE KEY UPDATE fid=VALUES(fid), isShortcut=VALUES(isShortcut), nr=0, oldCustomNr=0",
            $attachmentId, $fid, $isShortcut);
        $wpdb->query($sql);
        
        /**
         * An attachment is moved to a specific folder.
         * 
         * @param {int} $postId The post id of the attachment
         * @param {int} $oldFolder The old folder id of the attachment
         * @param {int} $fid The new folder id of the attachment
         * @param {boolean} $isShortcut If true the attachment was copied to a folder
         * @hook RML/Item/Moved
         */
        do_action("RML/Item/Moved", $postId, $oldFolder, $fid, $isShortcut);
        return true;
    }
    
    /**
     * Check if a meta key is inheritable.
     * 
     * @returns boolean
     */
    private function isInheritableMetaKey($meta_key, $withAttached = true) {
        return $meta_key === "_wp_attachment_metadata" || ($meta_key === "_wp_attached_file" && $withAttached) || $meta_key === "_wp_attachment_backup_sizes";
    }
    
    /**
     * If it is a shortcut, read the metadata from the source file.
     * It also handles the wp_delete_attachment process to avoid to delete
     * the source files if shortcut.
     */
    public function get_post_metadata($check, $object_id, $meta_key, $single) {
        if ($this->isInheritableMetaKey($meta_key) && ($source_id = wp_attachment_is_shortcut($object_id, true))) {
            // Check if we want to delete the attachment
            $backtrace = debug_backtrace();
            foreach ($backtrace as $value) {
                if ($value["function"] === "wp_delete_attachment") {
                    $this->debug("Tried to delete an attachment shortcut... Avoid to delete the physical files (" . $meta_key . ")", __METHOD__);
                    return $single ? "" : array(array());
                }
            }
            
            // Return main file data
            $meta = get_post_meta($source_id, $meta_key, $single);
            return $single ? array($meta) : $meta;
        }
        return $check;
    }
    
    /**
     * Avoids to generate own meta data for shortcuts.
     */
    public function add_post_metadata($check, $object_id, $meta_key, $meta_value, $unique) {
        if ($this->isInheritableMetaKey($meta_key) && ($source_id = wp_attachment_is_shortcut($object_id, true))) {
            $add = add_post_meta($source_id, $meta_key, $meta_value, $unique);
            return is_bool($add) ? $add : $add > 0;
        }
        return $check;
    }
    
    /**
     * Avoids to generate own meta data for shortcuts.
     */
    public function update_post_metadata($check, $object_id, $meta_key, $meta_value, $prev_value) {
        if ($this->isInheritableMetaKey($meta_key) && ($source_id = wp_attachment_is_shortcut($object_id, true))) {
            $this->debug("Probably the image gets regenerated, save the new metadata to the source file...", __METHOD__);
            $update = update_post_meta($source_id, $meta_key, $meta_value, $prev_value);
            return is_bool($update) ? $update : $update > 0;
        }
        return $check;
    }
    
    /**
     * @see wp_rml_created_shortcuts_last_ids()
     */
    public function getLastIds() {
        return is_array($this->lastIds) ? $this->lastIds : ( $this->lastIds = array() );
    }
    
    /**
     * Delete all associated shortcuts.
     */
    public function delete_attachment($postId) {
        $shortcuts = wp_attachment_get_shortcuts($postId);
        if (count($shortcuts) > 0) {
            $this->debug("Found shortcuts for this postid (" . $postId . "): " . json_encode($shortcuts), __METHOD__);
            foreach ($shortcuts as $value) {
                wp_delete_attachment($value, true);
            }
        }
    }
    
    /**
     * This function should only be used in the Creatable::insert() function.
     */
    public function _resetLastIds() {
        $this->lastIds = array();
    }
    
    public static function getInstance() {
        if (self::$me == null) {
            self::$me = new Shortcut();
        }
        return self::$me;
    }
}

?>