Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tagging uploaded files
#1
I think it would be useful if you could tag files after you have uploaded. If that functionality existed, it would be easy to create a component/plugin/template that could list files matching a given tag. e.g. get_files() (all files) / get_files('tag-name') - returning array of files (including file size and created/last modified too maybe).

I cannot see how you could do it as a plugin - I can see the files-uploaded and files-extra hooks, but not sure how these could be used to extend the files feature.

Also the 'hello world' sample plugin does not work as is Call to undefined function add_hook()
I've found that this is the case with the latest version and 2.0.1 - it should say add_action instead.
-- Sam
Reply
#2
SamWM Wrote:I think it would be useful if you could tag files after you have uploaded.
It would also bloat the XML back-end, so I don’t see this happening any time soon. Chris might surprise me by implementing something like it though, he always surprises me ;-)

SamWM Wrote:I cannot see how you could do it as a plugin - I can see the files-uploaded and files-extra hooks, but not sure how these could be used to extend the files feature.
They can be used to extend the files (uploads) page, files-uploaded will run when you upload a file and files-extra allows you to run some action every time a file is being shown in the overview. You might be able to use files-extra to add a field for tags to each file.

If you’d like to see additional hooks, just request them.

SamWM Wrote:Also the 'hello world' sample plugin does not work as is Call to undefined function add_hook()
I've found that this is the case with the latest version and 2.0.1 - it should say add_action instead.
You’re very right, the documentation on the website hasn’t been updated to reflect the latest version changes in the core yet.
“Don’t forget the important ˚ (not °) on the a,” says the Unicode lover.
Help us test a key change for the core! ¶ Problems with GetSimple? Be sure to enable debug mode!
Reply
#3
What is the purpose of the page_type parameter in register_plugin? It does not seem to matter what I put in there.

Also noticed it is file-extras not files-extras (as in documentation) and the code is run before the closing </table> tag. So would have to echo a new row rather that add to the existing row (if valid markup is to be generated).

I am not sure how you can get the current file though, as the following results in an Undefined variable error (which reduces the value of the hook):

Code:
# activate filter
add_action('file-extras','hello_world');

# functions
function hello_world() {
    echo '<tr><td>'.$upload['name'].'</td></tr>';
}
-- Sam
Reply
#4
A PHP function never has access to the variables that are not within it unless these variables are globals or passed to the function in the form of parameters. Easiest in your case is probably using this:
Code:
function hello_world() {
    global $upload; // This takes the currently existing $upload variable into the function.
    echo '<tr><td>'.$upload['name'].'</td></tr>';
}
“Don’t forget the important ˚ (not °) on the a,” says the Unicode lover.
Help us test a key change for the core! ¶ Problems with GetSimple? Be sure to enable debug mode!
Reply
#5
Created a new plugin File Meta Info, which allows you to store extra (meta) information about files. Data is stored in an XML file (data/other/file_meta.xml) and you can define what meta data to store by changing the array $file_meta_fields.

To display the data in a page, use <?php echo file_meta_data('filename.pdf', 'tags') ?>.

Code:

Code:
<?php
/*
Plugin Name: File Meta Info
Description: Store additional information about uploaded files
Version: 1.0
Author: Sam Collett
*/

# get correct id for plugin
$thisfile=basename(__FILE__, ".php");

# register plugin
register_plugin(
    $thisfile,
    'File Meta Info',    
    '1.0',        
    'Sam Collett',
    'http://www.texotela.co.uk',
    'Save additional meta information for uploaded files',
    '',
    ''  
);

# "Text to display" => "metakey" (no spaces)
$file_meta_fields = array("Tags" => "tags");

# activate filter
add_action('index-pretemplate', 'file_meta_preload');
add_action('header', 'file_meta_header');
add_action('file-extras','file_meta_extras');

# path to xml file
$file_meta_path = GSDATAOTHERPATH.'file_meta.xml';
# xml data
$file_meta_xml;

# functions
function file_meta_preload()
{
    global $file_meta_xml, $file_meta_path;
    if(is_file($file_meta_path)) {
        $file_meta_xml = getXML($file_meta_path);
    }
    else {
        $file_meta_xml = @new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><files></files>');
        XMLsave($file_meta_xml, $file_meta_path);
    }
    if (isset($_REQUEST["file_meta"]))
    {
        file_meta_update();
    }
}

function file_meta_header()
{
    // preload data
    file_meta_preload();
    echo '<style type="text/css">tr.file_meta { font-size: 0.875em } tr.file_meta input.meta { font-size: 0.875em; width: 200px } tr.file_meta td { padding: 0 18px }</style>';
}

function file_meta_extras() {
    global $file_meta_fields, $upload;
    echo '<tr class="file_meta"><td colspan="4">
    <form method="post" action="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES).'">';
    foreach($file_meta_fields as $text => $metakey)
    {
        echo $text.': <input name="meta_'.$metakey.'" value="'.file_meta_data($upload['name'], $metakey).'" class="'.$metakey.' meta" />';
    }
    echo '<input type="hidden" name="file" value="'.$upload['name'].'" />
    <input type="submit" value="Save" name="file_meta" />
    </form>
    </td></tr>';
}

function file_meta_data($file, $meta)
{
    global $file_meta_xml;
    $meta_data = '';
    if(is_object($file_meta_xml))
    {
        $current = $file_meta_xml->xpath('//files/file[@name="'.$file.'"]');
        if(count($current) !== 0) {
            $children = $current[0]->xpath($meta);
            if(count($children) > 0)
            {
                $meta_data = $children[0];
            }
        }
    }
    return $meta_data;
}

function file_meta_update()
{
    global $file_meta_xml, $file_meta_path;
    $file = '';
    // meta data to update
    $meta_update = array();
    foreach($_REQUEST as $key => $value)
    {
        // temp array for storing meta key and its value
        $ar = array();
        // if request key is file
        if($key == "file") $file = $value;
        if(strpos($key, "meta_") === 0) {
            $ar = explode('_',$key);
            $meta_update[$ar[1]] = $value;
        }
    }
    // find the file in the XML document
    $file_item = $file_meta_xml->xpath('//files/file[@name="'.$file.'"]');
    // if the file is not found
    if(count($file_item) === 0) {
        $file_item = $file_meta_xml->addChild('file');
        $file_item->addAttribute('name', $file);
    }
    
    // loop through all meta keys to update
    foreach($meta_update as $key => $value)
    {
        $children = $file_item[0]->xpath($key);
        if(count($children) > 0)
        {
            // remove existing tag
            unset($children[0][0]);
        }
        $file_item[0]->addChild($key, $value);
        
    }
    
    XMLsave($file_meta_xml, $file_meta_path);
}
-- Sam
Reply
#6
Updated plugin. New functions:
  • file_meta_search - search file meta data
  • file_meta_list - list files (as an unordered list), filtered (using file_meta_search)
Example (list files with a tag tagname set):
Code:
<?php echo file_meta_list('tags', 'tagname'); ?>
Plugin code:
Code:
<?php
/*
Plugin Name: File Meta Info
Description: Store additional information about uploaded files. Search and list files matching that meta data.
Version: 1.1
Author: Sam Collett
*/

# get correct id for plugin
$thisfile=basename(__FILE__, ".php");

# register plugin
register_plugin(
    $thisfile,
    'File Meta Info',    
    '1.1',        
    'Sam Collett',
    'http://www.texotela.co.uk',
    'Save additional meta information for uploaded files. Search and list files matching that meta data.',
    '',
    ''  
);

# 'Text to display' => 'metakey' (no spaces)
$file_meta_fields = array('Title' => 'title', 'Tags' => 'tags');

# activate filter
add_action('index-pretemplate', 'file_meta_preload');
add_action('header', 'file_meta_header');
add_action('file-extras','file_meta_extras');

# path to xml file
$file_meta_path = GSDATAOTHERPATH.'file_meta.xml';
# xml data
$file_meta_xml;

# functions
function file_meta_preload()
{
    global $file_meta_xml, $file_meta_path;
    if(is_file($file_meta_path)) {
        $file_meta_xml = getXML($file_meta_path);
    }
    else {
        $file_meta_xml = @new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><files></files>');
        XMLsave($file_meta_xml, $file_meta_path);
    }
    if (isset($_REQUEST["file_meta"]))
    {
        file_meta_update();
    }
}

function file_meta_header()
{
    // preload data
    file_meta_preload();
    echo '<style type="text/css">tr.file_meta { font-size: 0.875em } tr.file_meta input.meta { font-size: 0.875em; width: 200px } tr.file_meta td { padding: 0 18px }</style>';
}

function file_meta_extras()
{
    global $file_meta_fields, $upload;
    echo '<tr class="file_meta"><td colspan="4">
    <form method="post" action="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES).'">';
    foreach($file_meta_fields as $text => $metakey)
    {
        echo $text.': <input name="meta_'.$metakey.'" value="'.file_meta_data($upload['name'], $metakey).'" class="'.$metakey.' meta" />';
    }
    echo '<input type="hidden" name="file" value="'.$upload['name'].'" />
    <input type="submit" value="Save" name="file_meta" />
    </form>
    </td></tr>';
}

function file_meta_search($meta, $search)
{
    global $file_meta_xml;
    if(is_object($file_meta_xml))
    {
        return $file_meta_xml->xpath('//files/file[contains('.$meta.',"'.$search.'")]');
    }
    return null;
}

// list files
function file_meta_list($meta, $search)
{
    global $SITEURL;
    $files = file_meta_search($meta, $search);
    if(count($files) > 0)
    {
        $list = '<ul class="file_list">';
        foreach($files as $file)
        {
            // get file statistics
            $ss = @stat(GSDATAUPLOADPATH.$file['name']);
            // date last modified
            $date = @date('M j, Y',$ss['mtime']);
            // file size
            $size = fSize($ss['size']);
            // if title set in the meta data, use that
            $filetitle = $file->xpath('title');
            if(count($filetitle) > 0 && strlen($filetitle[0]) > 0)
            {
                $title = $filetitle[0];
            }
            // otherwise use file name without the extension
            else $title = substr($file['name'], 0, strrpos($file['name'], '.'));
            $list .= '<li><a href="'.$SITEURL.'data/uploads/'.$file['name'].'">'.$title.'</a> ('.$size.'. '.$date.')</li>';
        }
        $list .= '</ul>';
        return $list;
    }
    return null;
}

function file_meta_data($file, $meta)
{
    global $file_meta_xml;
    $meta_data = '';
    if(is_object($file_meta_xml))
    {
        $current = $file_meta_xml->xpath('//files/file[@name="'.$file.'"]');
        if(count($current) !== 0) {
            $children = $current[0]->xpath($meta);
            if(count($children) > 0)
            {
                $meta_data = $children[0];
            }
        }
    }
    return $meta_data;
}

function file_meta_update()
{
    global $file_meta_xml, $file_meta_path;
    $file = '';
    // meta data to update
    $meta_update = array();
    foreach($_REQUEST as $key => $value)
    {
        // temp array for storing meta key and its value
        $ar = array();
        // if request key is file
        if($key == "file") $file = $value;
        if(strpos($key, "meta_") === 0) {
            $ar = explode('_',$key);
            $meta_update[$ar[1]] = $value;
        }
    }
    // find the file in the XML document
    $file_item = $file_meta_xml->xpath('//files/file[@name="'.$file.'"]');
    // if the file is not found
    if(count($file_item) === 0) {
        $file_item = $file_meta_xml->addChild('file');
        $file_item->addAttribute('name', $file);
    }
    
    // loop through all meta keys to update
    foreach($meta_update as $key => $value)
    {
        $children = $file_item[0]->xpath($key);
        if(count($children) > 0)
        {
            // remove existing tag
            unset($children[0][0]);
        }
        $file_item[0]->addChild($key, $value);
        
    }
    
    XMLsave($file_meta_xml, $file_meta_path);
}
-- Sam
Reply
#7
Another version with some updates.

Bug fix - allows html special characters (< > " & )
New feature: file_meta_list shows a tooltip if 'tooltip' meta data set.

Code:
<?php
/*
Plugin Name: File Meta Info
Description: Store additional information about uploaded files. Search and list files matching that meta data.
Version: 1.2.1
Author: Sam Collett
*/

# get correct id for plugin
$thisfile=basename(__FILE__, ".php");

# register plugin
register_plugin(
    $thisfile,
    'File Meta Info',    
    '1.2.1',        
    'Sam Collett',
    'http://www.texotela.co.uk',
    'Save additional meta information for uploaded files. Search and list files matching that meta data.',
    '',
    ''  
);

# 'Text to display' => 'metakey' (no spaces)
$file_meta_fields = array('Title' => 'title', 'Tooltip' => 'tooltip', 'Tags' => 'tags');

# activate filter
add_action('index-pretemplate', 'file_meta_preload');
add_action('header', 'file_meta_header');
add_action('file-extras','file_meta_extras');

# path to xml file
$file_meta_path = GSDATAOTHERPATH.'file_meta.xml';
# xml data
$file_meta_xml;

# functions
function file_meta_preload()
{
    global $file_meta_xml, $file_meta_path;
    if(is_file($file_meta_path)) {
        $file_meta_xml = getXML($file_meta_path);
    }
    else {
        $file_meta_xml = @new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><files></files>');
        XMLsave($file_meta_xml, $file_meta_path);
    }
    if (isset($_REQUEST["file_meta"]))
    {
        file_meta_update();
    }
}

function file_meta_header()
{
    // preload data
    file_meta_preload();
    echo '<style type="text/css">tr.file_meta { font-size: 0.875em } tr.file_meta input.meta { font-size: 0.875em; width: 100px } tr.file_meta td { padding: 0 18px }</style>';
}

function file_meta_extras()
{
    global $file_meta_fields, $upload;
    echo '<tr class="file_meta"><td colspan="4">
    <form method="post" action="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES).'">';
    foreach($file_meta_fields as $text => $metakey)
    {
        echo $text.': <input name="meta_'.$metakey.'" value="'.file_meta_data($upload['name'], $metakey).'" class="'.$metakey.' meta" /> ';
    }
    echo '<input type="hidden" name="file" value="'.$upload['name'].'" />
    <input type="submit" value="Save" name="file_meta" />
    </form>
    </td></tr>';
}

function file_meta_search($meta, $search)
{
    global $file_meta_xml;
    if(is_object($file_meta_xml))
    {
        return $file_meta_xml->xpath('//files/file[contains('.$meta.',"'.$search.'")]');
    }
    return null;
}

// list files
function file_meta_list($meta, $search)
{
    global $SITEURL;
    $files = file_meta_search($meta, $search);
    if(count($files) > 0)
    {
        $list = '<ul class="file_list">';
        foreach($files as $file)
        {
            // get file statistics
            $ss = @stat(GSDATAUPLOADPATH.$file['name']);
            // date last modified
            $date = @date('M j, Y',$ss['mtime']);
            // file size
            $size = fSize($ss['size']);
            // if title set in the meta data, use that
            $filetitle = $file->xpath('title');
            if(count($filetitle) > 0 && strlen($filetitle[0]) > 0)
            {
                $title = $filetitle[0];
            }
            // otherwise use file name without the extension
            else $title = substr($file['name'], 0, strrpos($file['name'], '.'));
            $title = htmlspecialchars($title);
            // tooltip
            $tooltip = '';
            // if tooltip is set
            $filetooltip = $file->xpath('tooltip');
            if(count($filetooltip) > 0 && strlen($filetooltip[0]) > 0)
            {
                $tooltip = ' title="'.$filetooltip[0].'"';
            }
            $list .= '<li><a href="'.$SITEURL.'data/uploads/'.rawurlencode($file['name']).'"'.$tooltip.'>'.$title.'</a> ('.$size.'. '.$date.')</li>';
        }
        $list .= '</ul>';
        return $list;
    }
    return null;
}

function file_meta_data($file, $meta)
{
    global $file_meta_xml;
    $meta_data = '';
    if(is_object($file_meta_xml))
    {
        $current = $file_meta_xml->xpath('//files/file[@name="'.$file.'"]');
        if(count($current) !== 0) {
            $children = $current[0]->xpath($meta);
            if(count($children) > 0)
            {
                $meta_data = $children[0];
            }
        }
    }
    return htmlspecialchars($meta_data);
}

function file_meta_update()
{
    global $file_meta_xml, $file_meta_path;
    $file = '';
    // meta data to update
    $meta_update = array();
    foreach($_REQUEST as $key => $value)
    {
        // temp array for storing meta key and its value
        $ar = array();
        // if request key is file
        if($key == "file") $file = $value;
        if(strpos($key, "meta_") === 0) {
            $ar = explode('_',$key);
            $meta_update[$ar[1]] = $value;
        }
    }
    // find the file in the XML document
    $file_item = $file_meta_xml->xpath('//files/file[@name="'.$file.'"]');
    // if the file is not found
    if(count($file_item) === 0) {
        $file_item = $file_meta_xml->addChild('file');
        $file_item->addAttribute('name', $file);
    }
    
    // loop through all meta keys to update
    foreach($meta_update as $key => $value)
    {
        $children = $file_item[0]->xpath($key);
        if(count($children) > 0)
        {
            // remove existing tag
            unset($children[0][0]);
        }
        $file_item[0]->addChild($key, htmlspecialchars($value));
        
    }
    
    XMLsave($file_meta_xml, $file_meta_path);
}
-- Sam
Reply
#8
Version 1.3... with AJAX saving. Before there was no notification that the data was saved.
Code:
<?php
/*
Plugin Name: File Meta Info
Description: Store additional information about uploaded files. Search and list files matching that meta data.
Version: 1.3
Author: Sam Collett
*/

# get correct id for plugin
$thisfile=basename(__FILE__, ".php");

# register plugin
register_plugin(
    $thisfile,
    'File Meta Info',    
    '1.3',        
    'Sam Collett',
    'http://www.texotela.co.uk',
    'Save additional meta information for uploaded files. Search and list files matching that meta data.',
    '',
    ''  
);

# 'Text to display' => 'metakey' (no spaces)
$file_meta_fields = array('Title' => 'title', 'Tooltip' => 'tooltip', 'Tags' => 'tags');

# activate filter
add_action('index-pretemplate', 'file_meta_preload');
add_action('header', 'file_meta_header');
add_action('file-extras','file_meta_extras');

# path to xml file
$file_meta_path = GSDATAOTHERPATH.'file_meta.xml';
# xml data
$file_meta_xml;

# functions
function file_meta_preload()
{
    global $file_meta_xml, $file_meta_path;
    if(is_file($file_meta_path)) {
        $file_meta_xml = getXML($file_meta_path);
    }
    else {
        $file_meta_xml = @new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><files></files>');
        XMLsave($file_meta_xml, $file_meta_path);
    }
    if (isset($_REQUEST["file_meta"]))
    {
        file_meta_update();
    }
}

function file_meta_header()
{
    // preload data
    file_meta_preload();
    echo '<style type="text/css">
    tr.file_meta { font-size: 0.875em }
    tr.file_meta input.meta { font-size: 1em; width: 100px; border: 1px solid #ddd }
    tr.file_meta td { padding: 0 0 0 18px }
    tr.file_meta .notification { float: right; padding: 1px}
    tr.file_meta .highlight {background-color: #f00; color: #fff}
    tr.file_meta input[name=file_meta] { padding: 2px}
    </style>';
    echo '<script type="text/javascript">
    $( function() {
        $("form.file_meta_form").submit(filemetaSubmit);
    });
    
    function filemetaSubmit(e) {
        e.preventDefault();
        var $this = $(this);
        var $notification = $this.find("div.notification");
        var dataString = $this.serialize() + "&file_meta=Save";
        var method = $this.attr("method").toUpperCase();
        var action = $this.attr("action");
        $.ajax({
            type: method,
            url: action,
            data: dataString,
            success: function(response) {
                $notification.html(response).fadeIn("slow", callback).addClass("highlight");
            }
        });

        function callback() {
            setTimeout(function() {
                $notification.hide("slow").parents("tr.file_meta").removeClass("highlight");
            }, 2000);
        };
    }
    </script>';
}

function file_meta_extras()
{
    global $file_meta_fields, $upload;
    echo '<tr class="file_meta"><td colspan="4">
    <form method="post" action="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES).'" class="file_meta_form">';
    foreach($file_meta_fields as $text => $metakey)
    {
        echo $text.': <input name="meta_'.$metakey.'" value="'.file_meta_data($upload['name'], $metakey).'" class="'.$metakey.' meta" /> ';
    }
    echo '<input type="hidden" name="file" value="'.$upload['name'].'" />
    <input type="submit" value="Save" name="file_meta" /><div class="notification"></span>
    </form>
    </td></tr>';
}

function file_meta_search($meta, $search)
{
    global $file_meta_xml;
    if(is_object($file_meta_xml))
    {
        return $file_meta_xml->xpath('//files/file[contains('.$meta.',"'.$search.'")]');
    }
    return null;
}

// list files
function file_meta_list($meta, $search)
{
    global $SITEURL;
    $files = file_meta_search($meta, $search);
    if(count($files) > 0)
    {
        $list = '<ul class="file_list">';
        foreach($files as $file)
        {
            // get file statistics
            $ss = @stat(GSDATAUPLOADPATH.$file['name']);
            // date last modified
            $date = @date('M j, Y',$ss['mtime']);
            // file size
            $size = fSize($ss['size']);
            // if title set in the meta data, use that
            $filetitle = $file->xpath('title');
            if(count($filetitle) > 0 && strlen($filetitle[0]) > 0)
            {
                $title = $filetitle[0];
            }
            // otherwise use file name without the extension
            else $title = substr($file['name'], 0, strrpos($file['name'], '.'));
            $title = htmlspecialchars($title);
            // tooltip
            $tooltip = '';
            // if tooltip is set
            $filetooltip = $file->xpath('tooltip');
            if(count($filetooltip) > 0 && strlen($filetooltip[0]) > 0)
            {
                $tooltip = ' title="'.$filetooltip[0].'"';
            }
            $list .= '<li><a href="'.$SITEURL.'data/uploads/'.rawurlencode($file['name']).'"'.$tooltip.'>'.$title.'</a> ('.$size.'. '.$date.')</li>';
        }
        $list .= '</ul>';
        return $list;
    }
    return null;
}

function file_meta_data($file, $meta)
{
    global $file_meta_xml;
    $meta_data = '';
    if(is_object($file_meta_xml))
    {
        $current = $file_meta_xml->xpath('//files/file[@name="'.$file.'"]');
        if(count($current) !== 0) {
            $children = $current[0]->xpath($meta);
            if(count($children) > 0)
            {
                $meta_data = $children[0];
            }
        }
    }
    return htmlspecialchars($meta_data);
}

function file_meta_update()
{
    global $file_meta_xml, $file_meta_path;
    $file = '';
    // meta data to update
    $meta_update = array();
    foreach($_REQUEST as $key => $value)
    {
        // temp array for storing meta key and its value
        $ar = array();
        // if request key is file
        if($key == "file") $file = $value;
        if(strpos($key, "meta_") === 0) {
            $ar = explode('_',$key);
            $meta_update[$ar[1]] = $value;
        }
    }
    // find the file in the XML document
    $file_item = $file_meta_xml->xpath('//files/file[@name="'.$file.'"]');
    // if the file is not found
    if(count($file_item) === 0) {
        $file_item = $file_meta_xml->addChild('file');
        $file_item->addAttribute('name', $file);
    }
    
    // loop through all meta keys to update
    foreach($meta_update as $key => $value)
    {
        $children = $file_item[0]->xpath($key);
        if(count($children) > 0)
        {
            // remove existing tag
            unset($children[0][0]);
        }
        $file_item[0]->addChild($key, htmlspecialchars($value));
        
    }
    
    XMLsave($file_meta_xml, $file_meta_path);
    
    if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
        ob_clean();
        die("Meta Data saved");
    }
}
-- Sam
Reply
#9
Perhaps it would be better if this was moved under 'Plugins'? Only tested it with the version from SVN though.
-- Sam
Reply




Users browsing this thread: 1 Guest(s)