Make WordPress Core

Ticket #4727: grouptags.php

File grouptags.php, 26.5 KB (added by jhodgdon, 16 years ago)

Group Tags plugin (GPL) with type-ahead tag lookup functionality

Line 
1<?php
2/*
3Plugin Name: Group Tag Entry
4Plugin URI:
5Description: Allows you to set up groups of tags, and then assign them to posts by selecting check boxes, drop-down lists, and the like.
6Version: 1.0
7Author: Jennifer Hodgdon, Poplar ProductivityWare
8Author URI: http://poplarware.com
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14*/
15
16$grouptagsFileName = plugin_basename(__FILE__);
17$grouptagsTextDomain = 'grouptags';
18$grouptagsDBVersion = 1;
19$grouptagsElemTable = $wpdb->prefix . 'grouptags_ui_elems';
20$grouptagsSubelemTable = $wpdb->prefix . 'grouptags_ui_subelems';
21$grouptagsBlankItemCount = 3;
22
23add_action('activate_' . $grouptagsFileName, 'grouptags_install_tables');
24add_action('dbx_post_advanced', 'grouptags_post_entry_section' );
25add_action('save_post', 'grouptags_post_save' );
26add_action('admin_menu', 'grouptags_admin_screen');
27add_action('admin_print_scripts', 'grouptags_js_header');
28
29// Activation function -- creates or updates database tables for plugin
30function grouptags_install_tables()
31{ 
32  global $grouptagsDBVersion, $grouptagsElemTable, $grouptagsSubelemTable;
33
34   // newer versions of WP have this file in a different place...
35
36   if( file_exists( ABSPATH . 'wp-admin/includes/upgrade.php' ))
37     require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
38   else
39     require_once(ABSPATH . 'wp-admin/upgrade-functions.php');
40   
41   $elemStructure = "CREATE TABLE " . $grouptagsElemTable . " (" .
42                "elem_id BIGINT(20) NOT NULL AUTO_INCREMENT, \n" .
43                "elem_type VARCHAR(15) NOT NULL, \n" .
44                "elem_display_name VARCHAR(50) NOT NULL, \n" .
45                "elem_order DOUBLE NOT NULL, \n" .
46                "PRIMARY KEY  (elem_id), \n" .
47                "KEY elem_order (elem_order));";
48
49   $subelemStructure = "CREATE TABLE " . $grouptagsSubelemTable . " (" .
50                "subelem_id BIGINT(20) NOT NULL AUTO_INCREMENT, \n" .
51                "elem_id BIGINT(20) NOT NULL, \n" .
52                "subelem_display_name VARCHAR(50), \n" .
53                "subelem_order DOUBLE, \n" .
54                "subelem_tags TEXT, \n" .
55                "PRIMARY KEY  (subelem_id), \n" .
56                "KEY subelem_order (subelem_order), \n" .
57                "KEY (elem_id));" ;
58
59    dbDelta( $elemStructure, true );
60    dbDelta( $subelemStructure, true );
61 
62    add_option( "grouptags_db_version", $grouptagsDBVersion );
63    update_option( "grouptags_db_version", $grouptagsDBVersion );
64} // end of grouptags_install_tables function
65
66// Sets up admin screen for plugin
67function grouptags_admin_screen()
68{
69  global $grouptagsTextDomain, $grouptagsFileName;
70
71  add_options_page( __('Group Tags Setup', $grouptagsTextDomain), 
72                    __('Group Tags', $grouptagsTextDomain), 6, 
73                    $grouptagsFileName, 
74                    'grouptags_setup_page' );
75} // end of grouptags_admin_screen function
76
77// Creates and processes the admin setup page
78function grouptags_setup_page()
79{
80  global $grouptagsTextDomain;
81  global $grouptagsBlankItemCount;
82
83  // read current UI info from db
84
85  $info = _grouptags_get_ui_info();
86
87  // See if we have posted info
88
89  if( $_POST['grouptags_hidden'] == 'Y' ) {
90
91    // clear old info from DB
92    _grouptags_clear_elems();
93
94    $skipping = 1;
95    $last_id = -1;
96    $new_id = -1;
97    $last_type = '';
98    $last_disp = '';
99
100    // go through old IDs and see if we have info for them
101
102    for( $i = 0; $i < count( $info ); $i++ ) {
103      $id = $info[$i]['elem_id'];
104
105      if( $id != $last_id ) {
106        // we have arrived at a new item in the array...
107
108        if( !$skipping ) {
109          // process new sub-items
110          for( $j = 0; $j < $grouptagsBlankItemCount; $j++ ) {
111            $subid = "New" . $j;
112            _grouptags_process_subelem( $last_id, $subid, $new_id );
113          }
114        }
115
116        // see if we are skipping this item or not
117        // and save the item info
118
119        $last_id = $id;
120        $ord = $_POST['grouptags_order_' . $id ];
121
122        if( $ord < 0 ) {
123          $skipping = 1;
124        } else {
125          $skipping = 0;
126          $last_ord = $ord;
127          $last_type = $_POST['grouptags_type_' . $id ];
128          $last_disp = $_POST['grouptags_dispname_' . $id ];
129          $new_id = _grouptags_insert_elem( $last_type, $last_disp, $last_ord );
130        }
131      }
132   
133      // process sub-item info
134
135      if( !$skipping ) {
136        if( $last_type == "checkbox" ) {
137
138          // should only be one sub-item, get and save info
139          $subid = $info[$i]['subelem_id'];
140          $tags = $_POST['grouptags_tags_' . $last_id . '_' . $subid ];
141
142          _grouptags_insert_subelem( $new_id, '', 1, $tags );
143
144          // skip any other sub-items left over from before
145          $skipping = 1;
146
147        } else if( $last_type != "label" ) {
148          // process all subitems, with full info
149
150          $subid = $info[$i]['subelem_id'];
151          _grouptags_process_subelem( $last_id, $subid, $new_id );
152        }
153      }
154
155    }
156
157    // process any new sub-items in last item
158    if( !$skipping ) {
159      for( $j = 0; $j < $grouptagsBlankItemCount; $j++ ) {
160        $subid = "New" . $j;
161        _grouptags_process_subelem( $last_id, $subid, $new_id );
162      }
163    }
164
165    // see if user has added any new items - could be up to 3 of them
166
167    for( $i = 0; $i < $grouptagsBlankItemCount; $i++ ) {
168      $id = "New" . $i;
169      $ord = $_POST['grouptags_order_' . $id ];
170
171      if( $ord > 0 ) {
172
173        $type = $_POST['grouptags_type_' . $id ];
174        $disp = $_POST['grouptags_dispname_' . $id ];
175        $new_id = _grouptags_insert_elem( $type, $disp, $ord );
176
177        // process sub-items
178
179        $todo = $grouptagsBlankItemCount;
180        if( $type == "checkbox" ) { 
181          $todo = 1;
182        } else if( $type == "label" ) {
183          $todo = 0;
184        }
185
186        for( $j = 0; $j < $todo; $j++ ) {
187          $subid = "New" . $j;
188          _grouptags_process_subelem( $id, $subid, $new_id );
189        }
190      }
191    }
192
193    // now re-read info from DB
194    $info = _grouptags_get_ui_info();
195
196  }
197
198  // page header
199
200  ?>
201      <div class="wrap">
202         <h2><?php _e('Tag Groups Setup', $grouptagsTextDomain ); ?></h2>
203         <h3><?php _e('Tag Group Entry Section:', $grouptagsTextDomain ); ?></h3>
204         <p><?php _e('(Hints and Output Preview at bottom of page...)', $grouptagsTextDomain ); ?></p>
205         
206<form name="form1" method="post">
207         <input type="hidden" name="grouptags_hidden" value="Y">
208  <?
209
210  // display current items in text entry fields
211
212  $last_elem_id = -1;
213  $last_elem_type = '';
214  $count = 0;
215  $elem_start = "<hr /><p>";
216  $subelems_start = "</p><ul>";
217  $elem_end = "</ul>\n";
218
219  foreach( $info as $item ) {
220    if( $item['elem_id'] != $last_elem_id ) {
221
222      // close out the previous element, if it was open
223
224      if( $count ) {
225        if( $last_elem_type != "label" && 
226            $last_elem_type != "checkbox" ) {
227          echo _grouptags_blank_subelems( $item['elem_id'] );
228        }
229
230        echo $elem_end;
231      }
232
233      // start a new element
234
235      echo $elem_start;
236
237      echo _grouptags_order_box( $item['elem_order'], 1, $item['elem_id'] ) . " " .
238        _grouptags_type_dropdown( $item['elem_type'], $item['elem_id'] ) . " " . 
239        _grouptags_disp_name_box( $item['elem_display_name'], 1, $item['elem_id'] );
240
241      echo $subelems_start;
242
243      $last_elem_id = $item['elem_id'];
244      $last_elem_type = $item['elem_type'];
245    }
246
247    $count++;
248
249    // put in sub-elem info
250
251    if( $item['elem_type'] == "checkbox" ) {
252      echo "<li>" .
253        _grouptags_tag_box( $item['subelem_tags'], $item['elem_id'], $item['subelem_id'] ) . 
254        "</li>";
255    } else if( $item['elem_type'] != "label" ) {
256
257      echo "<li>" .
258        _grouptags_order_box( $item['subelem_order'], 0, $item['elem_id'], $item['subelem_id'] ) . " " .
259        _grouptags_disp_name_box( $item['subelem_display_name'], 0, $item['elem_id'], $item['subelem_id'] ) . " " .
260        "<br />" .
261        _grouptags_tag_box( $item['subelem_tags'], $item['elem_id'], $item['subelem_id'] ) . 
262        "</li>";
263    }
264  }
265
266  if( $count ) {
267    if( $last_elem_type != "label" && 
268        $last_elem_type != "checkbox" ) {
269      echo _grouptags_blank_subelems( $item['elem_id'] );
270    }
271
272    echo $elem_end;
273  }
274
275  // add some blank lines for new elements
276
277  for( $i = 0; $i < $grouptagsBlankItemCount; $i++ ) {
278
279    $id = "New" . $i;
280
281    echo $elem_start;
282    echo _grouptags_order_box( -1, 1, $id ) . " " .
283      _grouptags_type_dropdown( '', $id ) . " " . 
284      _grouptags_disp_name_box( '', 1, $id );
285
286    echo $subelems_start;
287    echo _grouptags_blank_subelems( $id );
288    echo $elem_end;
289
290  }
291
292  // submit button and form close
293
294  ?>
295          <p class="submit">
296          <input type="submit" name="Submit" value="<?php _e('Update Tag Groups', $grouptagsTextDomain) ?>" />
297          </p>
298         </form>
299
300         <hr />
301         <h3><?php _e('Data Entry Hints:', $grouptagsTextDomain ); ?></h3>
302         <ul>
303         <li><?php _e( "Terminlology: Labels, Check Boxes, etc. are Elements. WIthin some Elements, you have Items (such as the items in a drop-down list).", $grouptagsTextDomain ); ?></li>
304         <li><?php _e( "The overall Order number determines the order of Elements on the page. The item Order number determines the order of items in a list.", $grouptagsTextDomain ); ?></li>
305         <li><?php _e( "You can use decimal points in your Order numbers, for instance 2.5 to go between order 2 and order 3.", $grouptagsTextDomain ); ?></li>
306         <li><?php _e( "Set the Order to -1 to delete/omit an item or element. When entering an item/element for the first time, you must change the Order to something other than -1, or it will be ignored.", $grouptagsTextDomain ); ?></li>
307         <li><?php _e( "Separate tags by commas in Tags fields.", $grouptagsTextDomain ); ?></li>
308         <li><?php _e( "When defining a Check Box, only fill in the Tags field on the first item in the group. Leave the other items blank.", $grouptagsTextDomain ); ?></li>
309         <li><?php _e( "When defining a Label, leave all items blank.", $grouptagsTextDomain ); ?></li>
310         <li><?php _e( "If you need more blank lines to define new elements, or to add more items within elements, save what you have and more blank lines will appear.", $grouptagsTextDomain ); ?></li>
311         </ul>
312         <hr />
313
314         <h3><?php _e('Preview of Tag Entry Section:', $grouptagsTextDomain ); ?></h3>
315      <form>
316       <?php _grouptags_tag_entry_form( ); ?>
317      </form>
318        </div>
319
320  <?php
321
322} // end of grouptags_setup_page function
323
324// internal function: processes a POSTed sub-elem
325function _grouptags_process_subelem( $elem_id, $subid, $new_elem_id ) {
326  $subord = $_POST['grouptags_sub_order_' . $elem_id . '_' . $subid ];
327  $disp = $_POST['grouptags_sub_dispname_' . $elem_id . '_' . $subid ];
328  $tags = $_POST['grouptags_tags_' . $elem_id . '_' . $subid ];
329
330  if( $subord > 0 ) {
331    _grouptags_insert_subelem( $new_elem_id, $disp, $subord, $tags );
332  }
333}
334
335// internal function: returns a string containing blank sub-elem lines
336function _grouptags_blank_subelems( $id ) {
337
338  global $grouptagsBlankItemCount;
339
340  $str = '';
341
342  for( $i = 0; $i < $grouptagsBlankItemCount; $i++ ) {
343
344    $str .= "<li>";
345    $sub_id = "New" . $i;
346    $str .= _grouptags_order_box( -1, 0, $id, $sub_id ) . " " .
347      _grouptags_disp_name_box( '', 0, $id, $sub_id ) . " " .
348      "<br />" .
349      _grouptags_tag_box( '', $id, $sub_id ) . 
350      "</li>\n";
351  }
352
353  return $str;
354}
355
356// internal function: returns a string containing an order text box
357// inputs: current value of order, true/false is it an item (or subitem),
358// item ID, sub-item ID (can omit)
359function _grouptags_order_box( $ord, $is_item, $id, $sub_id = 0 ) {
360  global $grouptagsTextDomain;
361
362  $str = '';
363
364  $str .= __("Order:", $grouptagsTextDomain );
365  $str .= " ";
366  $str .= '<input type="text" size="5" value="' . $ord . '" ';
367  if( $is_item ) {
368    $str .= 'name="grouptags_order_' . $id;
369  } else {
370    $str .= 'name="grouptags_sub_order_' . $id . '_' . $sub_id;
371  }
372
373  $str .= '"' . ">\n";
374
375  return $str;
376}
377
378// internal function: returns a string containing an item type drop-down
379// inputs: current value of type, item ID
380function _grouptags_type_dropdown( $type, $id ) {
381  global $grouptagsTextDomain;
382
383  $types = array( 'label', 'checkbox', 'drop-down', 'radio' );
384  $labels = array( __('Label', $grouptagsTextDomain), 
385                   __('Check box', $grouptagsTextDomain),
386                   __('Drop-Down List', $grouptagsTextDomain),
387                   __('Radio Button Group', $grouptagsTextDomain ));
388
389  $str = '';
390
391  $str .= '<select name="grouptags_type_' . $id . '">' . "\n";
392
393  for( $i = 0; $i < count( $types ); $i++ ) {
394    $str .= '<option value="' . $types[$i] . '"';
395    if( $types[$i] == $type ) {
396      $str .= " selected";
397    }
398    $str .= ">" . $labels[$i] . "</option>\n";
399  }
400
401  $str .= "</select>\n";
402
403  return $str;
404
405}
406
407// internal function: returns a string containing a display name textbox
408// inputs: current value of name, true/false is it an item (or subitem),
409// item ID, sub-item ID (can omit)
410function _grouptags_disp_name_box( $name, $is_item, $id, $sub_id = 0 ) {
411  global $grouptagsTextDomain;
412
413  $str = '';
414
415  $str .= __("Displayed Name:", $grouptagsTextDomain );
416  $str .= " ";
417  $str .= '<input type="text" size="30" value="' . 
418    _grouptags_escape_dq( $name ). '" ';
419  if( $is_item ) {
420    $str .= 'name="grouptags_dispname_' . $id;
421  } else {
422    $str .= 'name="grouptags_sub_dispname_' . $id . '_' . $sub_id;
423  }
424
425  $str .= '"' . ">\n";
426
427  return $str;
428}
429
430// internal function: returns a string containing a tags textbox
431// inputs: current value of tags, item ID, sub-item ID (can omit)
432function _grouptags_tag_box( $tags, $id, $sub_id = 0 ) {
433  global $grouptagsTextDomain;
434
435  $str = '';
436
437  $str .= __("Tags:", $grouptagsTextDomain );
438  $str .= " ";
439  $str .= '<input type="text" size="80" value="' . 
440    _grouptags_escape_dq( $tags ). '" ';
441  $str .= 'name="grouptags_tags_' . $id . '_' . $sub_id . '"';
442
443  $str .= ">\n";
444
445  return $str;
446}
447
448// Internal function: returns the string with double quotes
449// escaped for HTML use
450function _grouptags_escape_dq( $str ) {
451  return preg_replace( '/"/', '&quot;', _grouptags_remove_backslash( $str ));
452}
453
454// Internal function: removes backslashes in a string and returns it
455function _grouptags_remove_backslash( $str ) {
456  return preg_replace( "/\\\\/", '', $str );
457}
458
459// Internal function: prints the tag entry form. Returns an array
460// of tags that were not found in the UI elements
461function _grouptags_tag_entry_form( $tags = array() ) {
462
463  global $grouptagsTextDomain;
464
465  $info = _grouptags_get_ui_info();
466  $tags_found = array();
467
468  $last_elem_id = -1;
469  $elem_start = "<br /><br />\n";
470  $subelem_pre = "";
471  $subelem_mid = "";
472  $subelem_post = "";
473  $elem_end = "";
474  $dosubs = 0;
475  $radio_count = 0;
476
477  foreach( $info as $item ) {
478
479    $thistags = explode( ',', $item['subelem_tags'] );
480    for( $i = 0; $i < count( $thistags ); $i++ ) {
481      $thistags[$i] = trim( $thistags[$i] );
482    }
483
484    if( $item['elem_id'] != $last_elem_id ) {
485
486      // close out the previous element
487      // and start a new element
488
489      if( $last_elem_id != -1 ) {
490        echo $elem_end;
491        echo $elem_start;
492      }
493
494      $last_elem_id = $item['elem_id'];
495      $elem_end = '';
496      $subelem_pre = '';
497      $subelem_mid = '';
498      $subelem_mid_selected = '';
499      $subelem_post = '';
500      $dosubs = 0;
501     
502     
503      if( $item['elem_type'] == "label" ) {
504        echo "<strong>" . $item['elem_display_name'] . "</strong>";
505
506      } else if( $item['elem_type'] == "checkbox" ) {
507
508        echo '<input type="checkbox" value="' . 
509          _grouptags_escape_dq( $item['subelem_tags'] ) . 
510          '" name="grouptags_tags[]"';
511
512        if( count( array_intersect( $tags, $thistags ))) {
513          echo " checked";
514          $tags_found = array_merge( $tags_found, $thistags );
515        }
516
517        echo '> '.
518          $item['elem_display_name'];
519
520      } else if( $item['elem_type'] == "drop-down" ) {
521
522        echo $item['elem_display_name'] . ": ";
523
524        echo '<select name="grouptags_tags[]">' . "\n";
525        echo "<option />\n";
526        $elem_end = '</select>' . "\n";
527        $dosubs = 1;
528
529        $subelem_pre = '<option value="';
530        $subelem_mid = '">';
531        $subelem_post = "</option>\n";
532        $subelem_mid_selected = '" selected>';
533
534      } else { // radio
535        $radio_count++;
536        echo $item['elem_display_name'] . ":\n";
537
538        $dosubs = 1;
539        $subelem_pre = 
540          '<br /><input type="radio" name="grouptags_radio_' . $radio_count . 
541          '" value="';
542        $subelem_mid = '"> ';
543        $subelem_post = "\n";
544        $subelem_mid_selected = '" checked>';
545      }
546
547    }
548
549    // put in sub-elem info
550
551    if( $dosubs ) {
552      echo $subelem_pre . _grouptags_escape_dq( $item['subelem_tags'] );
553
554      if( count( array_intersect( $tags, $thistags ))) {
555        echo $subelem_mid_selected;
556        $tags_found = array_merge( $tags_found, $thistags );
557      } else {
558        echo $subelem_mid;
559      }
560
561      echo $item['subelem_display_name'] .
562        $subelem_post;
563    }
564  }
565
566  echo $elem_end;
567
568  return array_diff( $tags, $tags_found );
569}
570
571// JavaScript for post editing screen
572function grouptags_js_header() 
573{
574
575  global $editing, $post, $post_ID;
576  global $grouptagsTextDomain;
577
578  if( !$editing ) {
579    // not on a post/page edit screen
580    return;
581  }
582
583  if( $post && $post->post_type == 'page' ) {
584    // it's a page, not a post -- note that $post is NOT set for a new
585    // page/post, see below
586    return;
587  }
588
589  // check the URL to see if it's a new page screen
590  $req_url = $_SERVER['REQUEST_URI'];
591  if( preg_match( '/page-new.php$/', $req_url )) {
592    // it's the "new page" editing screen, not new post
593    return;
594  }
595
596  // if we get here, we are on a post editing page, so we need the
597  // JavaScript for this page
598
599  // we need JQuery library loaded...
600  wp_print_scripts( array( 'jquery' ));
601 
602  // Set up JavaScript array of existing tags for lookup
603
604?>
605<style type="text/css">
606#grouptags_popup ul { list-style: none; color: black; background: #eeeeee; border: 1px solid black; margin: 0; padding: 0; width: 150px;}
607#grouptags_popup ul li { margin-left: 0; padding: 2px; text-indent: 0;}
608.gtselected { background: white; font-style: bold;}
609</style>
610
611<script type="text/javascript">
612  //<![CDATA[
613
614   var grouptags_all_tags = new Array();
615
616<?php
617
618  $all_tags = get_terms( 'post_tag', 'hide_empty=0' );
619 
620  $i = 0;
621  foreach( $all_tags as $item ) {
622    $item = sanitize_term( $item, 'post_tag', 'display' );
623
624    if( strlen( $item->name )) {
625      echo "grouptags_all_tags[$i] = " . '"' .
626        _grouptags_escape_dq( $item->name ) . '";' . "\n";
627
628      $i++;
629    }
630  }
631?>
632
633  grouptags_all_tags.sort();
634
635  var grouptags_curr_choices;
636
637  function grouptags_list_choices() {
638    grouptags_hide_choices();
639
640    // figure out what tags to suggest
641
642    // first find what the user is typing
643    var txt = jQuery( '#grouptags_free_entry' ).val();
644
645    // go back to previous comma
646    var start = txt.lastIndexOf(',');
647    if( start ) {
648      txt = txt.substr( start + 1 );
649    }
650    while( txt.charAt(0) == ' ' && txt.length ) {
651      txt = txt.substr( 1 );
652    }
653
654    if( !txt.length ) {
655      // nothing to suggest
656      return;
657    }
658
659    // now see which tags match this
660
661    jQuery( '#grouptags_popup' ).html( '<ul></ul>' );
662
663    grouptags_curr_choices = new Array();
664    var count = 0;
665    var i;
666    for( i = 0; i < grouptags_all_tags.length; i++ ) {
667      if( grouptags_all_tags[i].indexOf( txt ) == 0 ) {
668        grouptags_curr_choices[ count ] = grouptags_all_tags[i];
669        count++;
670        jQuery( '#grouptags_popup ul' ).append( '<li>' + grouptags_all_tags[i] + '</li>' );
671      }
672    }
673
674    if( !count ) {
675      return;
676    }
677
678    jQuery( '#grouptags_popup ul li' ).hover(
679      function( ) {
680        jQuery( this ).addClass( "gtselected" );
681      },
682      function( ) {
683        jQuery( this ).removeClass( "gtselected" );
684      });
685
686    jQuery( '#grouptags_popup ul li' ).click( function() {
687        var prev = jQuery( '#grouptags_free_entry' ).val();
688        if( prev.lastIndexOf( ',' ) > 1 ) {
689          prev = prev.substring( 0, prev.lastIndexOf( ',' ) + 1) + ' ';
690        } else {
691          prev = '';
692        }
693        prev = prev + jQuery( this ).text() + ", ";
694
695        jQuery( '#grouptags_free_entry' ).val( prev );
696        jQuery( '#grouptags_free_entry' ).focus();
697        grouptags_hide_choices();
698      });
699
700    jQuery( '#grouptags_popup' ).show();
701
702  }
703
704  function grouptags_hide_choices() {
705    grouptags_curr_choices = new Array();
706    jQuery( '#grouptags_popup' ).hide();
707  }
708
709  addLoadEvent( function() {
710      jQuery( '#grouptags_free_entry' ).keyup( function( e ) {
711          var kc = e.which;
712          if( !e.which ) {
713            kc = window.keyCode;
714          }
715
716          if( kc == 27  || kc == 44 || kc == 188 ) {
717            // escape/comma -- hide choices
718            grouptags_hide_choices();
719          } else if(( kc >= 65 &&
720                      kc <= 90 ) ||
721                    ( kc >= 97 &&
722                      kc <= 122 ) ||
723                    kc == 8 ) {
724            // alpha character, or backspace: put up choice list
725            // note: timeout is to allow choice to get into drop-down
726            setTimeout( grouptags_list_choices, 100 );
727          }
728         
729        });
730
731   });
732                   
733//]]>
734</script>
735<?php
736
737}  // end of grouptags_js_header function
738
739
740// Post edit screen section for group tag entry
741function grouptags_post_entry_section() {
742  global $post_ID;
743  global $grouptagTextDomain;
744
745  // header info
746
747  echo '<div class="dbx-b-ox-wrapper">' . "\n";
748  echo '<fieldset id="group_tag_entry" class="dbx-box">' . "\n";
749  echo '<div class="dbx-h-andle-wrapper"><h3 class="dbx-handle">' . 
750        __( "Group Tag Entry - Overrides tag field above!", $grouptagTextDomain ) . "</h3></div>";   
751   
752  echo '<div class="dbx-c-ontent-wrapper"><div class="dbx-content" ' .
753    ' id="group_tag_entry_section">';
754
755  echo '<p>';
756  _e( 'Note: If you have already typed in tags using the Tags field above, you MUST re-enter them in this section!', $grouptagTextDomain );
757  echo '</p>';
758
759  $curr_tags = wp_get_object_terms( $post_ID, 'post_tag' );
760  $tags = array();
761  foreach( $curr_tags as $tag ) {
762    $tags[] = $tag->name;
763  }
764
765  $leftovers = _grouptags_tag_entry_form( $tags );
766
767  echo "<br /><br />Additional Tags (separate by commas):" . 
768    '<input type="text" id="grouptags_free_entry" name="grouptags_tags[]" value="' .
769    _grouptags_escape_dq( implode( ', ', $leftovers )) . '" style="width:90%">';
770
771  echo '<br /><div id="grouptags_popup"></div>';
772
773  echo "</div></fieldset></div>\n";
774}  // end of grouptags_post_entry_section function
775
776// Process tags on post save
777function grouptags_post_save( $post_id ) {
778
779  $newtags = '';
780  $comma = '';
781  foreach( $_POST['grouptags_tags'] as $entry ) {
782    $entry = trim( $entry );
783    if( strlen( $entry )) {
784      $newtags .= $comma . $entry;
785      $comma = ',';
786    }
787  }
788
789  for( $i = 1; $i < 100; $i++ ) {
790    if( $_POST['grouptags_radio_' . $i ] ) {
791      $entry = trim( $_POST['grouptags_radio_' . $i ] );
792      if( strlen( $entry )) {
793        $newtags .= $comma . $entry;
794        $comma = ',';
795      }
796    }
797  }
798
799  wp_set_post_tags( $post_id, $newtags );
800
801} // end of grouptags_post_save function
802
803
804// Internal function: reads the current UI info from the database
805// and returns it as an array of objects
806function _grouptags_get_ui_info() {
807
808  global $grouptagsElemTable, $grouptagsSubelemTable;
809  global $wpdb;
810
811  $qryStr = "SELECT " .
812    "$grouptagsElemTable.elem_id as elem_id, " .
813    "$grouptagsElemTable.elem_type as elem_type, " .
814    "$grouptagsElemTable.elem_display_name as elem_display_name, " .
815    "$grouptagsElemTable.elem_order as elem_order, " .
816    "$grouptagsSubelemTable.subelem_id as subelem_id, " .
817    "$grouptagsSubelemTable.subelem_display_name as subelem_display_name, " .
818    "$grouptagsSubelemTable.subelem_order as subelem_order, " .
819    "$grouptagsSubelemTable.subelem_tags as subelem_tags " .
820    "FROM $grouptagsElemTable LEFT JOIN $grouptagsSubelemTable ON " .
821    "$grouptagsElemTable.elem_id = $grouptagsSubelemTable.elem_id " .
822    "ORDER BY elem_order, subelem_order";
823
824  $info = $wpdb->get_results( $qryStr, ARRAY_A );
825  if( !$info ) {
826    return array();
827  }
828
829  return $info;
830}
831
832// internal function: clears database of elements and sub-elements
833function _grouptags_clear_elems() {
834  global $grouptagsElemTable, $grouptagsSubelemTable;
835  global $wpdb;
836
837  $qryStr = "TRUNCATE $grouptagsElemTable";
838  $wpdb->query( $qryStr );
839
840  $qryStr = "TRUNCATE $grouptagsSubelemTable";
841  $wpdb->query( $qryStr );
842}
843
844// internal function: adds a new element, returns ID
845 function _grouptags_insert_elem( $type, $disp, $ord ) {
846
847  global $grouptagsElemTable;
848  global $wpdb;
849
850  $qryStr = "INSERT INTO $grouptagsElemTable (elem_type, elem_display_name, elem_order) VALUES ('" . 
851    $wpdb->escape( _grouptags_remove_backslash( $type )) . "', '" .
852    $wpdb->escape( _grouptags_remove_backslash( $disp )) . "', '" .   
853    $wpdb->escape( intval( _grouptags_remove_backslash( $ord ))) . "')";
854
855  $wpdb->query( $qryStr );
856  return $wpdb->insert_id;
857}
858
859// internal function: adds a new sub-element, returns ID
860function _grouptags_insert_subelem( $elem_id, $disp, $ord, $tags ) {
861  global $grouptagsSubelemTable;
862  global $wpdb;
863
864  $qryStr = "INSERT INTO $grouptagsSubelemTable (elem_id, subelem_display_name, subelem_order, subelem_tags) VALUES ('" . 
865    $wpdb->escape( _grouptags_remove_backslash( intval( $elem_id ))) . "', '" .   
866    $wpdb->escape( _grouptags_remove_backslash( $disp )) . "', '" .   
867    $wpdb->escape( intval( _grouptags_remove_backslash( $ord ))) . "', '" .   
868    $wpdb->escape( _grouptags_remove_backslash( $tags )) . "')";
869
870  $wpdb->query( $qryStr );
871  return $wpdb->insert_id;
872
873}
874
875?>