implemented tag interface as a tree
This commit is contained in:
parent
3c151eb62b
commit
6ee5474955
100
src/media.php
100
src/media.php
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
namespace TheaterGF\Core;
|
namespace TheaterGF\Core;
|
||||||
|
|
||||||
require_once __DIR__ . "/media-meta-box-html.php";
|
require_once __DIR__ . "/tag.php";
|
||||||
|
|
||||||
|
function array_contains( $array, $element ) {
|
||||||
|
return null != array_find($array, function ( $e ) use ($element) { return $e == $element; });
|
||||||
|
}
|
||||||
|
|
||||||
function build_tag_name( $term ) {
|
function build_tag_name( $term ) {
|
||||||
|
|
||||||
|
|
@ -33,12 +37,15 @@ function build_tag_name( $term ) {
|
||||||
|
|
||||||
class MediaManager {
|
class MediaManager {
|
||||||
|
|
||||||
|
public $tags;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
|
|
||||||
add_action('init', [ $this, 'register_structure' ]);
|
add_action('init', [ $this, 'register_structure' ]);
|
||||||
|
|
||||||
add_filter('attachment_fields_to_edit', [ $this, 'create_edit_media_control' ], 10, 2);
|
add_filter('attachment_fields_to_edit', [ $this, 'create_edit_media_control' ], 10, 2);
|
||||||
add_action('add_meta_boxes', [ $this, 'create_tag_management_box' ]);
|
add_action('add_meta_boxes', [ $this, 'create_tag_management_box' ]);
|
||||||
|
add_action('save_post', [ $this, 'save_tags' ]);
|
||||||
|
|
||||||
// Dont know what it does
|
// Dont know what it does
|
||||||
add_filter( 'update_post_term_count_statuses', function( $statuses, $taxonomy ) {
|
add_filter( 'update_post_term_count_statuses', function( $statuses, $taxonomy ) {
|
||||||
|
|
@ -56,26 +63,7 @@ class MediaManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function register_structure() {
|
public function register_structure() {
|
||||||
register_taxonomy('ttgf_media_tags', 'attachment', [
|
$this->tags = TagTree::create('ttgf_media_tags');
|
||||||
'labels' => [
|
|
||||||
'name' => 'Tags',
|
|
||||||
'singular_name' => 'Tag',
|
|
||||||
'search_items' => 'Search tags',
|
|
||||||
'all_items' => 'All tags',
|
|
||||||
'parent_item' => 'Parent tag',
|
|
||||||
'edit_item' => 'Edit tags',
|
|
||||||
'update_item' => 'Update tags',
|
|
||||||
'add_new_item' => 'Add new tag',
|
|
||||||
'new_item_name' => 'New tag name',
|
|
||||||
'menu_name' => 'Tags',
|
|
||||||
],
|
|
||||||
'hierarchical' => true,
|
|
||||||
'public' => false,
|
|
||||||
'show_ui' => false,
|
|
||||||
'show_admin_column' => true,
|
|
||||||
'rewrite' => false,
|
|
||||||
'update_count_callback' => '_update_generic_term_count'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create_tag_management_box() {
|
public function create_tag_management_box() {
|
||||||
|
|
@ -89,25 +77,79 @@ class MediaManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tag_management_meta_box_html( $post ) {
|
public function tag_management_meta_box_html( $post ) {
|
||||||
$all_terms = get_terms([
|
|
||||||
'taxonomy' => 'ttgf_media_tags',
|
|
||||||
'hide_empty' => false,
|
|
||||||
]);
|
|
||||||
$all_tags = build_tag_name($all_terms);
|
|
||||||
|
|
||||||
$terms = get_the_terms($post, 'ttgf_media_tags');
|
$terms = get_the_terms($post, 'ttgf_media_tags');
|
||||||
$tags = build_tag_name($terms);
|
$tags = $this->tags->get_multiple($terms ? $terms : []);
|
||||||
?>
|
?>
|
||||||
<h3>Assigned</h3>
|
<h3>Assigned</h3>
|
||||||
|
|
||||||
<div class="ttgf_tags_container">
|
<div class="ttgf_tags_container">
|
||||||
<?php foreach ( $tags as $tag ): ?>
|
<?php foreach ( $tags as $tag ): ?>
|
||||||
<div class="ttgf_tag"><?= $tag ?></div>
|
<div class="ttgf_tag"><?= $tag->name() ?></div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3>Available</h3>
|
||||||
|
<div>
|
||||||
|
<?php foreach ( $this->tags->get_all() as $tag ): ?>
|
||||||
|
<?= $tag->name() ?>: <?= $tag->id ?><br/>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Add new</h3>
|
||||||
|
<div class="ttgf_tag_add">
|
||||||
|
<?php wp_nonce_field(basename(__FILE__), 'ttgf_core_admin_nonce'); ?>
|
||||||
|
<input type="text" list="ttgf_available_tags" name="ttgf_new_tag">
|
||||||
|
<datalist id="ttgf_available_tags">
|
||||||
|
<?php foreach ( $this->tags->get_all() as $tag ): ?>
|
||||||
|
<option value="<?= $tag->name() ?>">
|
||||||
|
<?php endforeach ?>
|
||||||
|
</datalist>
|
||||||
|
</div>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function save_tags( $post ) {
|
||||||
|
$is_autosave = wp_is_post_autosave( $post_id );
|
||||||
|
$is_revision = wp_is_post_revision( $post_id );
|
||||||
|
$is_valid_nonce = isset($_POST['ttgf_core_admin_nonce']) && wp_verify_nonce($_POST['ttgf_core_admin_nonce'], basename(__FILE__));
|
||||||
|
|
||||||
|
if ( $is_autosave || $is_revision || !$is_valid_nonce ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_tag = sanitize_text_field($_POST['ttgf_new_tag']);
|
||||||
|
if ( isset($new_tag) ) {
|
||||||
|
|
||||||
|
$all_terms = get_terms([
|
||||||
|
'taxonomy' => 'ttgf_media_tags',
|
||||||
|
'hide_empty' => false,
|
||||||
|
]);
|
||||||
|
$all_tags = build_tag_name($all_terms);
|
||||||
|
|
||||||
|
$terms = get_the_terms($post, 'ttgf_media_tags');
|
||||||
|
$tags = build_tag_name($terms);
|
||||||
|
|
||||||
|
if ( array_find($tags, function ( $tag ) { return $tag == $new_tag; }) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! array_find($all_tags, function ( $tag ) { return $tag == $new_tag; }) ) {
|
||||||
|
|
||||||
|
$parts = explode("/", $new_tag);
|
||||||
|
|
||||||
|
$index = count($parts);
|
||||||
|
for ( ; $index > 0; --$index ) {
|
||||||
|
if ( array_contains($all_tags, implode("/", array_slice($parts, 0, $index))) ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function create_edit_media_control( $fields, $post ) {
|
public function create_edit_media_control( $fields, $post ) {
|
||||||
|
|
||||||
$terms = get_terms([ 'taxonomy' => 'ttgf_media_tags', 'hide_empty' => false ]);
|
$terms = get_terms([ 'taxonomy' => 'ttgf_media_tags', 'hide_empty' => false ]);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,235 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TheaterGF\Core;
|
||||||
|
|
||||||
|
class Tag {
|
||||||
|
|
||||||
|
public $term;
|
||||||
|
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
public $parent;
|
||||||
|
public $children;
|
||||||
|
|
||||||
|
public function __construct( $term ) {
|
||||||
|
$this->term = $term;
|
||||||
|
$this->id = $term->term_id;
|
||||||
|
$this->parent = null;
|
||||||
|
$this->children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function name() {
|
||||||
|
return implode('/', array_map(function ($segment) { return $segment->term->name; }, $this->path()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function path() {
|
||||||
|
$path = [ $this ];
|
||||||
|
|
||||||
|
$parent = $this->parent;
|
||||||
|
while ( $parent ) {
|
||||||
|
$path[] = $parent;
|
||||||
|
$parent = $parent->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_reverse($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_all_children() {
|
||||||
|
$child_list = $this->children;
|
||||||
|
|
||||||
|
foreach ( $this->children as $child ) {
|
||||||
|
$child_list = array_merge($child_list, $child->get_all_children());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $child_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function move( $new_term, $new_parent ) {
|
||||||
|
$this->term = $new_term;
|
||||||
|
$this->id = $new_term->term_id;
|
||||||
|
|
||||||
|
if ( $this->parent == $new_parent ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->parent->remove_child($this);
|
||||||
|
$this->parent->add_child($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update_term( $new_term ) {
|
||||||
|
$this->term = $new_term;
|
||||||
|
$this->id = $new_term->term_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function add_child( $child ) {
|
||||||
|
$this->children[] = $child;
|
||||||
|
$child->parent = $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove() {
|
||||||
|
$this->parent->remove_child($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function remove_child( $child ) {
|
||||||
|
$index = array_find($this->children, function ($c) use ($child) { return $c == $child; });
|
||||||
|
if ( $index ) {
|
||||||
|
$this->children = array_splice($this->children, $index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class TagTree {
|
||||||
|
|
||||||
|
static public function create( $taxonomy_id ) {
|
||||||
|
$taxonomy = register_taxonomy($taxonomy_id, 'attachment', [
|
||||||
|
'labels' => [
|
||||||
|
'name' => 'Tags',
|
||||||
|
'singular_name' => 'Tag',
|
||||||
|
'search_items' => 'Search tags',
|
||||||
|
'all_items' => 'All tags',
|
||||||
|
'parent_item' => 'Parent tag',
|
||||||
|
'edit_item' => 'Edit tags',
|
||||||
|
'update_item' => 'Update tags',
|
||||||
|
'add_new_item' => 'Add new tag',
|
||||||
|
'new_item_name' => 'New tag name',
|
||||||
|
'menu_name' => 'Tags',
|
||||||
|
],
|
||||||
|
'hierarchical' => true,
|
||||||
|
'public' => false,
|
||||||
|
'show_ui' => false,
|
||||||
|
'show_admin_column' => true,
|
||||||
|
'rewrite' => false,
|
||||||
|
'update_count_callback' => '_update_generic_term_count'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return new TagTree($taxonomy_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public $taxonomy;
|
||||||
|
public $root_tags;
|
||||||
|
|
||||||
|
public function __construct ( $taxonomy ) {
|
||||||
|
$this->taxonomy = $taxonomy;
|
||||||
|
$this->root_tags = [];
|
||||||
|
|
||||||
|
$this->rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_all() {
|
||||||
|
$all = $this->root_tags;
|
||||||
|
|
||||||
|
foreach ( $this->root_tags as $tag ) {
|
||||||
|
$all = array_merge($all, $tag->get_all_children());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $all;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_multiple( $terms ) {
|
||||||
|
|
||||||
|
$num_terms = count($terms);
|
||||||
|
if ( $num_terms == 0 ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$term_ids = array_map(function ($term) { return $term->term_id; }, $terms);
|
||||||
|
$term_ids_set = array_flip($term_ids);
|
||||||
|
|
||||||
|
foreach ( $this->root_tags as $rt ) {
|
||||||
|
foreach ( $rt->get_all_children() as $child ) {
|
||||||
|
if ( isset($term_ids_set[$child->id]) ) {
|
||||||
|
$tags[] = $child;
|
||||||
|
}
|
||||||
|
if ( count($tags) == $num_terms ) {
|
||||||
|
return $tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get( $term ) {
|
||||||
|
|
||||||
|
foreach ( $this->root_tags as $rt ) {
|
||||||
|
$found = array_find($rt->get_all_children(), function ($child) use ($term) { return $child->id == $term->term_id; });
|
||||||
|
if ( $found ) {
|
||||||
|
return $found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create_tag( $parent, $tag_name, $description = '') {
|
||||||
|
$new_term = wp_insert_term( $tag_name, $this->taxonomy, [
|
||||||
|
'description' => $description,
|
||||||
|
'parent' => $parent->id
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ( is_wp_error($new_term) ) {
|
||||||
|
return $new_term;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tag($new_term, $parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function move_tag( $tag, $new_parent ) {
|
||||||
|
|
||||||
|
$result = wp_update_term($tag->id, $this->taxonomy, [ 'parent' => $new_parent->id ]);
|
||||||
|
|
||||||
|
if ( is_wp_error($result) ) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_term = get_term($result->term_id, $this->taxonomy);
|
||||||
|
|
||||||
|
$tag->update_term( $new_term, $new_parent );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update_tag( $tag, $new_description ) {
|
||||||
|
|
||||||
|
$result = wp_update_term($tag->id, $this->taxonomy, [ 'parent' => $tag->parent->id, 'description' => $new_description ]);
|
||||||
|
|
||||||
|
if ( is_wp_error($result) ) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_term = get_term($result->term_id, $this->taxonomy);
|
||||||
|
|
||||||
|
$tag->update_term($new_term);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete_tag( $tag ) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rebuild() {
|
||||||
|
$root_terms = get_terms([ 'taxonomy' => $this->taxonomy, 'hide_empty' => false, 'parent' => 0 ]);
|
||||||
|
|
||||||
|
foreach ( $root_terms as $term ) {
|
||||||
|
$this->root_tags[] = new Tag($term);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $this->root_tags as $tag ) {
|
||||||
|
$this->rebuild_children($tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function rebuild_children( $child ) {
|
||||||
|
$child_terms = get_terms([ 'taxonomy' => $this->taxonomy, 'hide_empty' => false, 'parent' => $child->term->term_id ]);
|
||||||
|
|
||||||
|
foreach ( $child_terms as $child_term ) {
|
||||||
|
$child->add_child(new Tag($child_term));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $child->children as $grandchild ) {
|
||||||
|
$this->rebuild_children($grandchild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue