PageRenderTime 59ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/functions/base.php

https://github.com/UCF/TechTransfer-Theme
PHP | 1715 lines | 1083 code | 230 blank | 402 comment | 113 complexity | 5505b638c21d870f2780339163ae0a5b MD5 | raw file
  1. <?php
  2. /***************************************************************************
  3. * CLASSES
  4. *
  5. ***************************************************************************/
  6. /**
  7. * The Config class provides a set of static properties and methods which store
  8. * and facilitate configuration of the theme.
  9. **/
  10. class ArgumentException extends Exception{}
  11. class Config{
  12. static
  13. $body_classes = array(), # Body classes
  14. $theme_settings = array(), # Theme settings
  15. $custom_post_types = array(), # Custom post types to register
  16. $custom_taxonomies = array(), # Custom taxonomies to register
  17. $styles = array(), # Stylesheets to register
  18. $scripts = array(), # Scripts to register
  19. $links = array(), # <link>s to include in <head>
  20. $metas = array(); # <meta>s to include in <head>
  21. /**
  22. * Creates and returns a normalized name for a resource url defined by $src.
  23. **/
  24. static function generate_name($src, $ignore_suffix=''){
  25. $base = basename($src, $ignore_suffix);
  26. $name = slug($base);
  27. return $name;
  28. }
  29. /**
  30. * Registers a stylesheet with built-in wordpress style registration.
  31. * Arguments to this can either be a string or an array with required css
  32. * attributes.
  33. *
  34. * A string argument will be treated as the src value for the css, and all
  35. * other attributes will default to the most common values. To override
  36. * those values, you must pass the attribute array.
  37. *
  38. * Array Argument:
  39. * $attr = array(
  40. * 'name' => 'theme-style', # Wordpress uses this to identify queued files
  41. * 'media' => 'all', # What media types this should apply to
  42. * 'admin' => False, # Should this be used in admin as well?
  43. * 'src' => 'http://some.domain/style.css',
  44. * );
  45. **/
  46. static function add_css($attr){
  47. # Allow string arguments, defining source.
  48. if (is_string($attr)){
  49. $new = array();
  50. $new['src'] = $attr;
  51. $attr = $new;
  52. }
  53. if (!isset($attr['src'])){
  54. throw new ArgumentException('add_css expects argument array to contain key "src"');
  55. }
  56. $default = array(
  57. 'name' => self::generate_name($attr['src'], '.css'),
  58. 'media' => 'all',
  59. 'admin' => False,
  60. );
  61. $attr = array_merge($default, $attr);
  62. $is_admin = (is_admin() or is_login());
  63. if (
  64. ($attr['admin'] and $is_admin) or
  65. (!$attr['admin'] and !$is_admin)
  66. ){
  67. wp_deregister_style($attr['name']);
  68. wp_enqueue_style($attr['name'], $attr['src'], null, null, $attr['media']);
  69. }
  70. }
  71. /**
  72. * Functions similar to add_css, but appends scripts to the footer instead.
  73. * Accepts a string or array argument, like add_css, with the string
  74. * argument assumed to be the src value for the script.
  75. *
  76. * Array Argument:
  77. * $attr = array(
  78. * 'name' => 'jquery', # Wordpress uses this to identify queued files
  79. * 'admin' => False, # Should this be used in admin as well?
  80. * 'src' => 'http://some.domain/style.js',
  81. * );
  82. **/
  83. static function add_script($attr){
  84. # Allow string arguments, defining source.
  85. if (is_string($attr)){
  86. $new = array();
  87. $new['src'] = $attr;
  88. $attr = $new;
  89. }
  90. if (!isset($attr['src'])){
  91. throw new ArgumentException('add_script expects argument array to contain key "src"');
  92. }
  93. $default = array(
  94. 'name' => self::generate_name($attr['src'], '.js'),
  95. 'admin' => False,
  96. );
  97. $attr = array_merge($default, $attr);
  98. $is_admin = (is_admin() or is_login());
  99. if (
  100. ($attr['admin'] and $is_admin) or
  101. (!$attr['admin'] and !$is_admin)
  102. ){
  103. # Override previously defined scripts
  104. wp_deregister_script($attr['name']);
  105. wp_enqueue_script($attr['name'], $attr['src'], null, null, True);
  106. }
  107. }
  108. }
  109. /**
  110. * Abstracted field class, all form fields should inherit from this.
  111. *
  112. * @package default
  113. * @author Jared Lang
  114. **/
  115. abstract class Field{
  116. protected function check_for_default(){
  117. if ($this->value === null){
  118. $this->value = $this->default;
  119. }
  120. }
  121. function __construct($attr){
  122. $this->name = @$attr['name'];
  123. $this->id = @$attr['id'];
  124. $this->value = @$attr['value'];
  125. $this->description = @$attr['description'];
  126. $this->default = @$attr['default'];
  127. $this->check_for_default();
  128. }
  129. function label_html(){
  130. ob_start();
  131. ?>
  132. <label class="block" for="<?=htmlentities($this->id)?>"><?=__($this->name)?></label>
  133. <?php
  134. return ob_get_clean();
  135. }
  136. function input_html(){
  137. return "Abstract Input Field, Override in Descendants";
  138. }
  139. function description_html(){
  140. ob_start();
  141. ?>
  142. <?php if($this->description):?>
  143. <p class="description"><?=__($this->description)?></p>
  144. <?php endif;?>
  145. <?php
  146. return ob_get_clean();
  147. }
  148. function html(){
  149. $label = $this->label_html();
  150. $input = $this->input_html();
  151. $description = $this->description_html();
  152. return $label.$input.$description;
  153. }
  154. }
  155. /**
  156. * Abstracted choices field. Choices fields have an additional attribute named
  157. * choices which allow a selection of values to be chosen from.
  158. *
  159. * @package default
  160. * @author Jared Lang
  161. **/
  162. abstract class ChoicesField extends Field{
  163. function __construct($attr){
  164. $this->choices = @$attr['choices'];
  165. parent::__construct($attr);
  166. }
  167. }
  168. /**
  169. * TextField class represents a simple text input
  170. *
  171. * @package default
  172. * @author Jared Lang
  173. **/
  174. class TextField extends Field{
  175. protected $type_attr = 'text';
  176. function input_html(){
  177. ob_start();
  178. ?>
  179. <input type="<?=$this->type_attr?>" id="<?=htmlentities($this->id)?>" name="<?=htmlentities($this->id)?>" value="<?=htmlentities($this->value)?>" />
  180. <?php
  181. return ob_get_clean();
  182. }
  183. }
  184. /**
  185. * PasswordField can be used to accept sensitive information, not encrypted on
  186. * wordpress' end however.
  187. *
  188. * @package default
  189. * @author Jared Lang
  190. **/
  191. class PasswordField extends TextField{
  192. protected $type_attr = 'password';
  193. }
  194. /**
  195. * TextareaField represents a textarea form element
  196. *
  197. * @package default
  198. * @author Jared Lang
  199. **/
  200. class TextareaField extends Field{
  201. function input_html(){
  202. ob_start();
  203. ?>
  204. <textarea id="<?=htmlentities($this->id)?>" name="<?=htmlentities($this->id)?>"><?=htmlentities($this->value)?></textarea>
  205. <?php
  206. return ob_get_clean();
  207. }
  208. }
  209. /**
  210. * Select form element
  211. *
  212. * @package default
  213. * @author Jared Lang
  214. **/
  215. class SelectField extends ChoicesField{
  216. function input_html(){
  217. ob_start();
  218. ?>
  219. <select name="<?=htmlentities($this->id)?>" id="<?=htmlentities($this->id)?>">
  220. <?php foreach($this->choices as $key=>$value):?>
  221. <option<?php if($this->value == $value):?> selected="selected"<?php endif;?> value="<?=htmlentities($value)?>"><?=htmlentities($key)?></option>
  222. <?php endforeach;?>
  223. </select>
  224. <?php
  225. return ob_get_clean();
  226. }
  227. }
  228. /**
  229. * Radio form element
  230. *
  231. * @package default
  232. * @author Jared Lang
  233. **/
  234. class RadioField extends ChoicesField{
  235. function input_html(){
  236. ob_start();
  237. ?>
  238. <ul class="radio-list">
  239. <?php $i = 0; foreach($this->choices as $key=>$value): $id = htmlentities($this->id).'_'.$i++;?>
  240. <li>
  241. <input<?php if($this->value == $value):?> checked="checked"<?php endif;?> type="radio" name="<?=htmlentities($this->id)?>" id="<?=$id?>" value="<?=htmlentities($value)?>" />
  242. <label for="<?=$id?>"><?=htmlentities($key)?></label>
  243. </li>
  244. <?php endforeach;?>
  245. </ul>
  246. <?php
  247. return ob_get_clean();
  248. }
  249. }
  250. /**
  251. * Checkbox form element
  252. *
  253. * @package default
  254. * @author Jared Lang
  255. **/
  256. class CheckboxField extends ChoicesField{
  257. function input_html(){
  258. ob_start();
  259. ?>
  260. <ul class="checkbox-list">
  261. <?php $i = 0; foreach($this->choices as $key=>$value): $id = htmlentities($this->id).'_'.$i++;?>
  262. <li>
  263. <input<?php if(is_array($this->value) and in_array($value, $this->value)):?> checked="checked"<?php endif;?> type="checkbox" name="<?=htmlentities($this->id)?>[]" id="<?=$id?>" value="<?=htmlentities($value)?>" />
  264. <label for="<?=$id?>"><?=htmlentities($key)?></label>
  265. </li>
  266. <?php endforeach;?>
  267. </ul>
  268. <?php
  269. return ob_get_clean();
  270. }
  271. }
  272. /**
  273. * Convenience class to calculate total execution times.
  274. *
  275. * @package default
  276. * @author Jared Lang
  277. **/
  278. class Timer{
  279. private $start_time = null;
  280. private $end_time = null;
  281. public function start_timer(){
  282. $this->start_time = microtime(True);
  283. $this->end_time = null;
  284. }
  285. public function stop_timer(){
  286. $this->end_time = microtime(True);
  287. }
  288. public function clear_timer(){
  289. $this->start_time = null;
  290. $this->end_time = null;
  291. }
  292. public function reset_timer(){
  293. $this->clear_timer();
  294. $this->start_timer();
  295. }
  296. public function elapsed(){
  297. if ($this->end_time !== null){
  298. return $this->end_time - $this->start_time;
  299. }else{
  300. return microtime(True) - $this->start_time;
  301. }
  302. }
  303. public function __toString(){
  304. return $this->elapsed;
  305. }
  306. /**
  307. * Returns a started instance of timer
  308. *
  309. * @return instance of Timer
  310. * @author Jared Lang
  311. **/
  312. public static function start(){
  313. $timer_instance = new self();
  314. $timer_instance->start_timer();
  315. return $timer_instance;
  316. }
  317. }
  318. /***************************************************************************
  319. * DEBUGGING FUNCTIONS
  320. *
  321. * Functions to assist in theme debugging.
  322. *
  323. ***************************************************************************/
  324. /**
  325. * Given an arbitrary number of arguments, will return a string with the
  326. * arguments dumped recursively, similar to the output of print_r but with pre
  327. * tags wrapped around the output.
  328. *
  329. * @return string
  330. * @author Jared Lang
  331. **/
  332. function dump(){
  333. $args = func_get_args();
  334. $out = array();
  335. foreach($args as $arg){
  336. $out[] = print_r($arg, True);
  337. }
  338. $out = implode("<br />", $out);
  339. return "<pre>{$out}</pre>";
  340. }
  341. /**
  342. * Will add a debug comment to the output when the debug constant is set true.
  343. * Any value, including null, is enough to trigger it.
  344. *
  345. * @return void
  346. * @author Jared Lang
  347. **/
  348. if (DEBUG){
  349. function debug($string){ /*
  350. print "<!-- DEBUG: {$string} -->\n"; */
  351. }
  352. }else{
  353. function debug($string){return;}
  354. }
  355. /**
  356. * Will execute the function $func with the arguments passed via $args if the
  357. * debug constant is set true. Returns whatever value the called function
  358. * returns, or void if debug is not set active.
  359. *
  360. * @return mixed
  361. * @author Jared Lang
  362. **/
  363. if (DEBUG){
  364. function debug_callfunc($func, $args){
  365. return call_user_func_array($func, $args);
  366. }
  367. }else{
  368. function debug_callfunc($func, $args){return;}
  369. }
  370. /**
  371. * Indent contents of $html passed by $n indentations.
  372. *
  373. * @return string
  374. * @author Jared Lang
  375. **/
  376. function indent($html, $n){
  377. $tabs = str_repeat("\t", $n);
  378. $html = explode("\n", $html);
  379. foreach($html as $key=>$line){
  380. $html[$key] = $tabs.trim($line);
  381. }
  382. $html = implode("\n", $html);
  383. return $html;
  384. }
  385. /***************************************************************************
  386. * GENERAL USE FUNCTIONS
  387. *
  388. * Theme-wide general use functions. (Alphabetized)
  389. *
  390. ***************************************************************************/
  391. /**
  392. * Walker function to add Bootstrap classes to nav menus using wp_nav_menu()
  393. *
  394. * based on https://gist.github.com/1597994
  395. **/
  396. function bootstrap_menus() {
  397. class Bootstrap_Walker_Nav_Menu extends Walker_Nav_Menu {
  398. function start_lvl( &$output, $depth ) {
  399. $indent = str_repeat( "\t", $depth );
  400. $output .= "\n$indent<ul class=\"dropdown-menu\">\n";
  401. }
  402. function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
  403. $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
  404. $li_attributes = '';
  405. $class_names = $value = '';
  406. $classes = empty( $item->classes ) ? array() : (array) $item->classes;
  407. $classes[] = ($args->has_children) ? 'dropdown' : '';
  408. $classes[] = ($item->current || $item->current_item_ancestor) ? 'active' : '';
  409. $classes[] = 'menu-item-' . $item->ID;
  410. $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
  411. $class_names = ' class="' . esc_attr( $class_names ) . '"';
  412. $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
  413. $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';
  414. $output .= $indent . '<li' . $id . $value . $class_names . $li_attributes . '>';
  415. $attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
  416. $attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
  417. $attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
  418. $attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
  419. $attributes .= ($args->has_children) ? ' class="dropdown-toggle" data-toggle="dropdown"' : '';
  420. $item_output = $args->before;
  421. $item_output .= '<a'. $attributes .'>';
  422. $item_output .= $args->link_before . apply_filters( 'the_title', strtoupper($item->title), $item->ID ) . $args->link_after;
  423. $item_output .= ($args->has_children) ? ' <b class="caret"></b></a>' : '</a>';
  424. $item_output .= $args->after;
  425. $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
  426. }
  427. function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
  428. if ( !$element )
  429. return;
  430. $id_field = $this->db_fields['id'];
  431. //display this element
  432. if ( is_array( $args[0] ) )
  433. $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );
  434. else if ( is_object( $args[0] ) )
  435. $args[0]->has_children = ! empty( $children_elements[$element->$id_field] );
  436. $cb_args = array_merge( array(&$output, $element, $depth), $args);
  437. call_user_func_array(array(&$this, 'start_el'), $cb_args);
  438. $id = $element->$id_field;
  439. // descend only when the depth is right and there are childrens for this element
  440. if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
  441. foreach( $children_elements[ $id ] as $child ){
  442. if ( !isset($newlevel) ) {
  443. $newlevel = true;
  444. //start the child delimiter
  445. $cb_args = array_merge( array(&$output, $depth), $args);
  446. call_user_func_array(array(&$this, 'start_lvl'), $cb_args);
  447. }
  448. $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
  449. }
  450. unset( $children_elements[ $id ] );
  451. }
  452. if ( isset($newlevel) && $newlevel ){
  453. //end the child delimiter
  454. $cb_args = array_merge( array(&$output, $depth), $args);
  455. call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
  456. }
  457. //end this element
  458. $cb_args = array_merge( array(&$output, $element, $depth), $args);
  459. call_user_func_array(array(&$this, 'end_el'), $cb_args);
  460. }
  461. }
  462. }
  463. add_action( 'after_setup_theme', 'bootstrap_menus' );
  464. /**
  465. * Strings passed to this function will be modified under the assumption that
  466. * they were outputted by wordpress' the_output filter. It checks for a handful
  467. * of things like empty, unnecessary, and unclosed tags.
  468. *
  469. * @return string
  470. * @author Jared Lang
  471. **/
  472. function cleanup($content){
  473. # Balance auto paragraphs
  474. $lines = explode("\n", $content);
  475. foreach($lines as $key=>$line){
  476. $null = null;
  477. $found_closed = preg_match_all('/<\/p>/', $line, $null);
  478. $found_opened = preg_match_all('/<p[^>]*>/', $line, $null);
  479. $diff = $found_closed - $found_opened;
  480. # Balanced tags
  481. if ($diff == 0){continue;}
  482. # missing closed
  483. if ($diff < 0){
  484. $lines[$key] = $lines[$key] . str_repeat('</p>', abs($diff));
  485. }
  486. # missing open
  487. if ($diff > 0){
  488. $lines[$key] = str_repeat('<p>', abs($diff)) . $lines[$key];
  489. }
  490. }
  491. $content = implode("\n", $lines);
  492. #Remove incomplete tags at start and end
  493. $content = preg_replace('/^<\/p>[\s]*/i', '', $content);
  494. $content = preg_replace('/[\s]*<p>$/i', '', $content);
  495. $content = preg_replace('/^<br \/>/i', '', $content);
  496. $content = preg_replace('/<br \/>$/i', '', $content);
  497. #Remove paragraph and linebreak tags wrapped around shortcodes
  498. $content = preg_replace('/(<p>|<br \/>)\[/i', '[', $content);
  499. $content = preg_replace('/\](<\/p>|<br \/>)/i', ']', $content);
  500. #Remove empty paragraphs
  501. $content = preg_replace('/<p><\/p>/i', '', $content);
  502. return $content;
  503. }
  504. /**
  505. * Creates a string of attributes and their values from the key/value defined by
  506. * $attr. The string is suitable for use in html tags.
  507. *
  508. * @return string
  509. * @author Jared Lang
  510. **/
  511. function create_attribute_string($attr){
  512. $attr_string = '';
  513. foreach($attr as $key=>$value){
  514. $attr_string .= " {$key}='{$value}'";
  515. }
  516. return $attr_string;
  517. }
  518. /**
  519. * Creates an arbitrary html element. $tag defines what element will be created
  520. * such as a p, h1, or div. $attr is an array defining attributes and their
  521. * associated values for the tag created. $content determines what data the tag
  522. * wraps. And $self_close defines whether or not the tag should close like
  523. * <tag></tag> (False) or <tag /> (True).
  524. *
  525. * @return string
  526. * @author Jared Lang
  527. **/
  528. function create_html_element($tag, $attr=array(), $content=null, $self_close=True){
  529. $attr_str = create_attribute_string($attr);
  530. if ($content){
  531. $element = "<{$tag}{$attr_str}>{$content}</{$tag}>";
  532. }else{
  533. if ($self_close){
  534. $element = "<{$tag}{$attr_str}/>";
  535. }else{
  536. $element = "<{$tag}{$attr_str}></{$tag}>";
  537. }
  538. }
  539. return $element;
  540. }
  541. /**
  542. * When called, prevents direct loads of the value of $page.
  543. **/
  544. function disallow_direct_load($page){
  545. if ($page == basename($_SERVER['SCRIPT_FILENAME'])){
  546. die('No');
  547. }
  548. }
  549. /**
  550. * Given a name will return the custom post type's class name, or null if not
  551. * found
  552. *
  553. * @return string
  554. * @author Jared Lang
  555. **/
  556. function get_custom_post_type($name){
  557. $installed = installed_custom_post_types();
  558. foreach($installed as $object){
  559. if ($object->options('name') == $name){
  560. return get_class($object);
  561. }
  562. }
  563. return null;
  564. }
  565. /**
  566. * Get featured image for a post
  567. *
  568. * @return array
  569. * @author Chris Conover
  570. **/
  571. function get_featured_image_url($post) {
  572. if(has_post_thumbnail($post) && ($thumbnail_id = get_post_thumbnail_id($post)) && ($image = wp_get_attachment_image_src($thumbnail_id))) {
  573. return $image[0];
  574. }
  575. return False;
  576. }
  577. /**
  578. * Get value of Theme Option Header Menu Styles and return relevant Boostrap
  579. * CSS classes. Indended for use as wp_nav_menu()'s menu_class argument.
  580. * See http://codex.wordpress.org/Function_Reference/wp_nav_menu
  581. *
  582. * @author Jo Greybill
  583. **/
  584. function get_header_styles() {
  585. $options = get_option(THEME_OPTIONS_NAME);
  586. $id = $options['bootstrap_menu_styles'];
  587. switch ($id) {
  588. case 'nav-tabs':
  589. $header_menu_class = 'nav nav-tabs';
  590. break;
  591. case 'nav-pills':
  592. $header_menu_class = 'nav nav-pills';
  593. break;
  594. default:
  595. $header_menu_class = 'horizontal';
  596. break;
  597. }
  598. return $header_menu_class;
  599. }
  600. /**
  601. * Return an array of choices representing all the images uploaded to the media
  602. * gallery.
  603. *
  604. * @return array
  605. * @author Jared Lang
  606. **/
  607. function get_image_choices(){
  608. $image_mimes = array(
  609. 'image/jpeg',
  610. 'image/png',
  611. );
  612. $images = array('(None)' => null);
  613. $args = array(
  614. 'post_type' => 'attachment',
  615. 'post_status' => 'inherit',
  616. 'numberposts' => -1,
  617. );
  618. $attachments = get_posts($args);
  619. $attachments = array_filter($attachments, create_function('$a', '
  620. $is_image = (strpos($a->post_mime_type, "image/") !== False);
  621. return $is_image;
  622. '));
  623. foreach($attachments as $image){
  624. $filename = basename(get_attached_file($image->ID));
  625. $value = $image->ID;
  626. $key = $image->post_title. " | {$filename}";
  627. $images[$key] = $value;
  628. }
  629. return $images;
  630. }
  631. /**
  632. * Wraps wordpress' native functions, allowing you to get a menu defined by
  633. * its location rather than the name given to the menu. The argument $classes
  634. * lets you define a custom class(es) to place on the list generated, $id does
  635. * the same but with an id attribute.
  636. *
  637. * If you require more customization of the output, a final optional argument
  638. * $callback lets you specify a function that will generate the output. Any
  639. * callback passed should accept one argument, which will be the items for the
  640. * menu in question.
  641. *
  642. * @return void
  643. * @author Jared Lang
  644. **/
  645. function get_menu($name, $classes=null, $id=null, $callback=null){
  646. $locations = get_nav_menu_locations();
  647. $menu = @$locations[$name];
  648. if (!$menu){
  649. return "<div class='error'>No menu location found with name '{$name}'. Set up menus in the <a href='".get_admin_url()."nav-menus.php'>admin's appearance menu.</a></div>";
  650. }
  651. $items = wp_get_nav_menu_items($menu);
  652. if ($callback === null){
  653. ob_start();
  654. ?>
  655. <ul<?php if($classes):?> class="<?=$classes?>"<?php endif;?><?php if($id):?> id="<?=$id?>"<?php endif;?>>
  656. <?php foreach($items as $key=>$item): $last = $key == count($items) - 1;?>
  657. <li<?php if($last):?> class="last"<?php endif;?>><a href="<?=$item->url?>"><?=$item->title?></a></li>
  658. <?php endforeach;?>
  659. </ul>
  660. <?php
  661. $menu = ob_get_clean();
  662. }else{
  663. $menu = call_user_func($callback, $items);
  664. }
  665. return $menu;
  666. }
  667. /**
  668. * Uses the google search appliance to search the current site or the site
  669. * defined by the argument $domain.
  670. *
  671. * @return array
  672. * @author Jared Lang
  673. **/
  674. function get_search_results(
  675. $query,
  676. $start=null,
  677. $per_page=null,
  678. $domain=null,
  679. $search_url="http://google.cc.ucf.edu/search"
  680. ){
  681. $start = ($start) ? $start : 0;
  682. $per_page = ($per_page) ? $per_page : 10;
  683. $domain = ($domain) ? $domain : $_SERVER['SERVER_NAME'];
  684. $results = array(
  685. 'number' => 0,
  686. 'items' => array(),
  687. );
  688. $query = trim($query);
  689. $per_page = (int)$per_page;
  690. $start = (int)$start;
  691. $query = urlencode($query);
  692. $arguments = array(
  693. 'num' => $per_page,
  694. 'start' => $start,
  695. 'ie' => 'UTF-8',
  696. 'oe' => 'UTF-8',
  697. 'client' => 'default_frontend',
  698. 'output' => 'xml',
  699. 'sitesearch' => $domain,
  700. 'q' => $query,
  701. );
  702. if (strlen($query) > 0){
  703. $query_string = http_build_query($arguments);
  704. $url = $search_url.'?'.$query_string;
  705. $response = file_get_contents($url);
  706. if ($response){
  707. $xml = simplexml_load_string($response);
  708. $items = $xml->RES->R;
  709. $total = $xml->RES->M;
  710. $temp = array();
  711. if ($total){
  712. foreach($items as $result){
  713. $item = array();
  714. $item['url'] = str_replace('https', 'http', $result->U);
  715. $item['title'] = $result->T;
  716. $item['rank'] = $result->RK;
  717. $item['snippet'] = $result->S;
  718. $item['mime'] = $result['MIME'];
  719. $temp[] = $item;
  720. }
  721. $results['items'] = $temp;
  722. }
  723. $results['number'] = $total;
  724. }
  725. }
  726. return $results;
  727. }
  728. /**
  729. * Returns true if the current request is on the login screen.
  730. *
  731. * @return boolean
  732. * @author Jared Lang
  733. **/
  734. function is_login(){
  735. return in_array($GLOBALS['pagenow'], array(
  736. 'wp-login.php',
  737. 'wp-register.php',
  738. ));
  739. }
  740. /**
  741. * Given a mimetype, will attempt to return a string representing the
  742. * application it is associated with. If the mimetype is unknown, the default
  743. * return is 'document'.
  744. *
  745. * @return string
  746. * @author Jared Lang
  747. **/
  748. function mimetype_to_application($mimetype){
  749. switch($mimetype){
  750. default:
  751. $type = 'document';
  752. break;
  753. case 'text/html':
  754. $type = "html";
  755. break;
  756. case 'application/zip':
  757. $type = "zip";
  758. break;
  759. case 'application/pdf':
  760. $type = 'pdf';
  761. break;
  762. case 'application/msword':
  763. case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
  764. $type = 'word';
  765. break;
  766. case 'application/msexcel':
  767. case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
  768. $type = 'excel';
  769. break;
  770. case 'application/vnd.ms-powerpoint':
  771. case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
  772. $type = 'powerpoint';
  773. break;
  774. }
  775. return $type;
  776. }
  777. /**
  778. * Really get the post type. A post type of revision will return it's parent
  779. * post type.
  780. *
  781. * @return string
  782. * @author Jared Lang
  783. **/
  784. function post_type($post){
  785. if (is_int($post)){
  786. $post = get_post($post);
  787. }
  788. # check post_type field
  789. $post_type = $post->post_type;
  790. if ($post_type === 'revision'){
  791. $parent = (int)$post->post_parent;
  792. $post_type = post_type($parent);
  793. }
  794. return $post_type;
  795. }
  796. /**
  797. * Fetches objects defined by arguments passed, outputs the objects according
  798. * to the objectsToHTML method located on the object. Used by the auto
  799. * generated shortcodes enabled on custom post types. See also:
  800. *
  801. * CustomPostType::objectsToHTML
  802. * CustomPostType::toHTML
  803. *
  804. * @return string
  805. * @author Jared Lang
  806. **/
  807. function sc_object_list($attrs, $options = array()){
  808. if (!is_array($attrs)){return '';}
  809. $default_options = array(
  810. 'default_content' => null,
  811. 'sort_func' => null,
  812. 'objects_only' => False
  813. );
  814. extract(array_merge($default_options, $options));
  815. # set defaults and combine with passed arguments
  816. $default_attrs = array(
  817. 'type' => null,
  818. 'limit' => -1,
  819. 'join' => 'or',
  820. 'class' => '',
  821. 'orderby' => 'menu_order title',
  822. 'order' => 'ASC',
  823. 'offset' => 0
  824. );
  825. $params = array_merge($default_attrs, $attrs);
  826. # verify options
  827. if ($params['type'] == null){
  828. return '<p class="error">No type defined for object list.</p>';
  829. }
  830. if (!is_numeric($params['limit'])){
  831. return '<p class="error">Invalid limit argument, must be a number.</p>';
  832. }
  833. if (!in_array(strtoupper($params['join']), array('AND', 'OR'))){
  834. return '<p class="error">Invalid join type, must be one of "and" or "or".</p>';
  835. }
  836. if (null == ($class = get_custom_post_type($params['type']))){
  837. return '<p class="error">Invalid post type.</p>';
  838. }
  839. $class = new $class;
  840. # Use post type specified ordering?
  841. if(!isset($attrs['orderby']) && !is_null($class->default_orderby)) {
  842. $params['orderby'] = $class->orderby;
  843. }
  844. if(!isset($attrs['order']) && !is_null($class->default_order)) {
  845. $params['order'] = $class->default_order;
  846. }
  847. # get taxonomies and translation
  848. $translate = array(
  849. 'tags' => 'post_tag',
  850. 'categories' => 'category',
  851. 'org_groups' => 'org_groups',
  852. );
  853. $taxonomies = array_diff(array_keys($attrs), array_keys($default_attrs));
  854. # assemble taxonomy query
  855. $tax_queries = array();
  856. $tax_queries['relation'] = strtoupper($params['join']);
  857. foreach($taxonomies as $tax){
  858. $terms = $params[$tax];
  859. $terms = trim(preg_replace('/\s+/', ' ', $terms));
  860. $terms = explode(' ', $terms);
  861. if (array_key_exists($tax, $translate)){
  862. $tax = $translate[$tax];
  863. }
  864. $tax_queries[] = array(
  865. 'taxonomy' => $tax,
  866. 'field' => 'slug',
  867. 'terms' => $terms,
  868. );
  869. }
  870. # perform query
  871. $query_array = array(
  872. 'tax_query' => $tax_queries,
  873. 'post_status' => 'publish',
  874. 'post_type' => $params['type'],
  875. 'posts_per_page' => $params['limit'],
  876. 'orderby' => $params['orderby'],
  877. 'order' => $params['order'],
  878. 'offset' => $params['offset']
  879. );
  880. $query = new WP_Query($query_array);
  881. global $post;
  882. $objects = array();
  883. while($query->have_posts()){
  884. $query->the_post();
  885. $objects[] = $post;
  886. }
  887. # Custom sort if applicable
  888. if ($sort_func !== null){
  889. usort($objects, $sort_func);
  890. }
  891. wp_reset_postdata();
  892. if($objects_only) {
  893. return $objects;
  894. }
  895. if (count($objects)){
  896. $html = $class->objectsToHTML($objects, $params['class']);
  897. }else{
  898. $html = $default_content;
  899. }
  900. return $html;
  901. }
  902. /**
  903. * Sets the default values for any theme options that are not currently stored.
  904. *
  905. * @return void
  906. * @author Jared Lang
  907. **/
  908. function set_defaults_for_options(){
  909. $values = get_option(THEME_OPTIONS_NAME);
  910. if ($values === False or is_string($values)){
  911. add_option(THEME_OPTIONS_NAME);
  912. $values = array();
  913. }
  914. $options = array();
  915. foreach(Config::$theme_settings as $option){
  916. if (is_array($option)){
  917. $options = array_merge($option, $options);
  918. }else{
  919. $options[] = $option;
  920. }
  921. }
  922. foreach ($options as $option){
  923. $key = str_replace(
  924. array(THEME_OPTIONS_NAME, '[', ']'),
  925. array('', '', ''),
  926. $option->id
  927. );
  928. if ($option->default !== null and !isset($values[$key])){
  929. $values[$key] = $option->default;
  930. update_option(THEME_OPTIONS_NAME, $values);
  931. }
  932. }
  933. }
  934. /**
  935. * Runs as wordpress is shutting down.
  936. *
  937. * @return void
  938. * @author Jared Lang
  939. **/
  940. function __shutdown__(){
  941. global $timer;
  942. $elapsed = round($timer->elapsed() * 1000);
  943. debug("{$elapsed} milliseconds");
  944. }
  945. add_action('shutdown', '__shutdown__');
  946. /**
  947. * Will return a string $s normalized to a slug value. The optional argument,
  948. * $spaces, allows you to define what spaces and other undesirable characters
  949. * will be replaced with. Useful for content that will appear in urls or
  950. * turning plain text into an id.
  951. *
  952. * @return string
  953. * @author Jared Lang
  954. **/
  955. function slug($s, $spaces='-'){
  956. $s = strtolower($s);
  957. $s = preg_replace('/[-_\s\.]/', $spaces, $s);
  958. return $s;
  959. }
  960. /***************************************************************************
  961. * HEADER AND FOOTER FUNCTIONS
  962. *
  963. * Functions that generate output for the header and footer, including
  964. * <meta>, <link>, page titles, body classes and Facebook OpenGraph
  965. * stuff.
  966. *
  967. ***************************************************************************/
  968. /**
  969. * Header content
  970. *
  971. * @return string
  972. * @author Jared Lang
  973. **/
  974. function header_($tabs=2){
  975. opengraph_setup();
  976. remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
  977. remove_action('wp_head', 'index_rel_link');
  978. remove_action('wp_head', 'rel_canonical');
  979. remove_action('wp_head', 'wp_generator');
  980. remove_action('wp_head', 'wlwmanifest_link');
  981. remove_action('wp_head', 'rsd_link');
  982. ob_start();
  983. print header_meta()."\n";
  984. wp_head();
  985. print header_links()."\n";
  986. print header_title()."\n";
  987. return indent(ob_get_clean(), $tabs);
  988. }
  989. /**
  990. * Footer content
  991. *
  992. * @return string
  993. * @author Jared Lang
  994. **/
  995. function footer_($tabs=2){
  996. ob_start();
  997. wp_footer();
  998. $html = ob_get_clean();
  999. return indent($html, $tabs);
  1000. }
  1001. /**
  1002. * Assembles the appropriate meta elements for facebook's opengraph stuff.
  1003. * Utilizes the themes Config object to queue up the created elements.
  1004. *
  1005. * @return void
  1006. * @author Jared Lang
  1007. **/
  1008. function opengraph_setup(){
  1009. $options = get_option(THEME_OPTIONS_NAME);
  1010. if (!(bool)$options['enable_og']){return;}
  1011. if (is_search()){return;}
  1012. global $post, $page;
  1013. setup_postdata($post);
  1014. if (is_front_page()){
  1015. $title = htmlentities(get_bloginfo('name'));
  1016. $url = get_bloginfo('url');
  1017. $site_name = $title;
  1018. }else{
  1019. $title = htmlentities($post->post_title);
  1020. $url = get_permalink($post->ID);
  1021. $site_name = htmlentities(get_bloginfo('name'));
  1022. }
  1023. # Set description
  1024. if (is_front_page()){
  1025. $description = htmlentities(get_bloginfo('description'));
  1026. }else{
  1027. ob_start();
  1028. the_excerpt();
  1029. $description = trim(str_replace('[...]', '', ob_get_clean()));
  1030. # Generate a description if excerpt is unavailable
  1031. if (strlen($description) < 1){
  1032. ob_start();
  1033. the_content();
  1034. $description = apply_filters('the_excerpt', preg_replace(
  1035. '/\s+/',
  1036. ' ',
  1037. strip_tags(ob_get_clean()))
  1038. );
  1039. $words = explode(' ', $description);
  1040. $description = implode(' ', array_slice($words, 0, 60));
  1041. }
  1042. }
  1043. $metas = array(
  1044. array('property' => 'og:title' , 'content' => $title),
  1045. array('property' => 'og:url' , 'content' => $url),
  1046. array('property' => 'og:site_name' , 'content' => $site_name),
  1047. array('property' => 'og:description', 'content' => $description),
  1048. );
  1049. # Include image if available
  1050. if (!is_front_page() and has_post_thumbnail($post->ID)){
  1051. $image = wp_get_attachment_image_src(
  1052. get_post_thumbnail_id( $post->ID ),
  1053. 'single-post-thumbnail'
  1054. );
  1055. $metas[] = array('property' => 'og:image', 'content' => $image[0]);
  1056. }
  1057. # Include admins if available
  1058. $admins = trim($options['fb_admins']);
  1059. if (strlen($admins) > 0){
  1060. $metas[] = array('property' => 'fb:admins', 'content' => $admins);
  1061. }
  1062. Config::$metas = array_merge(Config::$metas, $metas);
  1063. }
  1064. /**
  1065. * Handles generating the meta tags configured for this theme.
  1066. *
  1067. * @return string
  1068. * @author Jared Lang
  1069. **/
  1070. function header_meta(){
  1071. $metas = Config::$metas;
  1072. $meta_html = array();
  1073. $defaults = array();
  1074. foreach($metas as $meta){
  1075. $meta = array_merge($defaults, $meta);
  1076. $meta_html[] = create_html_element('meta', $meta);
  1077. }
  1078. $meta_html = implode("\n", $meta_html);
  1079. return $meta_html;
  1080. }
  1081. /**
  1082. * Handles generating the link tags configured for this theme.
  1083. *
  1084. * @return string
  1085. * @author Jared Lang
  1086. **/
  1087. function header_links(){
  1088. $links = Config::$links;
  1089. $links_html = array();
  1090. $defaults = array();
  1091. foreach($links as $link){
  1092. $link = array_merge($defaults, $link);
  1093. $links_html[] = create_html_element('link', $link, null, True);
  1094. }
  1095. $links_html = implode("\n", $links_html);
  1096. return $links_html;
  1097. }
  1098. /**
  1099. * Generates a title based on context page is viewed. Stolen from Thematic
  1100. **/
  1101. function header_title(){
  1102. $site_name = get_bloginfo('name');
  1103. $separator = '|';
  1104. if ( is_single() ) {
  1105. $content = single_post_title('', FALSE);
  1106. }
  1107. elseif ( is_home() || is_front_page() ) {
  1108. $content = get_bloginfo('description');
  1109. }
  1110. elseif ( is_page() ) {
  1111. $content = single_post_title('', FALSE);
  1112. }
  1113. elseif ( is_search() ) {
  1114. $content = __('Search Results for:');
  1115. $content .= ' ' . esc_html(stripslashes(get_search_query()));
  1116. }
  1117. elseif ( is_category() ) {
  1118. $content = __('Category Archives:');
  1119. $content .= ' ' . single_cat_title("", false);;
  1120. }
  1121. elseif ( is_404() ) {
  1122. $content = __('Not Found');
  1123. }
  1124. else {
  1125. $content = get_bloginfo('description');
  1126. }
  1127. if (get_query_var('paged')) {
  1128. $content .= ' ' .$separator. ' ';
  1129. $content .= 'Page';
  1130. $content .= ' ';
  1131. $content .= get_query_var('paged');
  1132. }
  1133. if($content) {
  1134. if (is_home() || is_front_page()) {
  1135. $elements = array(
  1136. 'site_name' => $site_name,
  1137. 'separator' => $separator,
  1138. 'content' => $content,
  1139. );
  1140. } else {
  1141. $elements = array(
  1142. 'content' => $content,
  1143. );
  1144. }
  1145. } else {
  1146. $elements = array(
  1147. 'site_name' => $site_name,
  1148. );
  1149. }
  1150. // But if they don't, it won't try to implode
  1151. if(is_array($elements)) {
  1152. $doctitle = implode(' ', $elements);
  1153. }
  1154. else {
  1155. $doctitle = $elements;
  1156. }
  1157. $doctitle = "<title>". $doctitle ."</title>";
  1158. return $doctitle;
  1159. }
  1160. /**
  1161. * Returns string to use for value of class attribute on body tag
  1162. **/
  1163. function body_classes(){
  1164. $classes = Config::$body_classes;
  1165. return implode(' ', $classes);
  1166. }
  1167. /***************************************************************************
  1168. * REGISTRATION AND INSTALLATION FUNCTIONS
  1169. *
  1170. * Functions that register and install custom post types, taxonomies,
  1171. * and meta boxes.
  1172. *
  1173. ***************************************************************************/
  1174. /**
  1175. * Adding custom post types to the installed array defined in this function
  1176. * will activate and make available for use those types.
  1177. **/
  1178. function installed_custom_post_types(){
  1179. $installed = Config::$custom_post_types;
  1180. return array_map(create_function('$class', '
  1181. return new $class;
  1182. '), $installed);
  1183. }
  1184. /**
  1185. * Adding custom post types to the installed array defined in this function
  1186. * will activate and make available for use those types.
  1187. **/
  1188. function installed_custom_taxonomies(){
  1189. $installed = Config::$custom_taxonomies;
  1190. return array_map(create_function('$class', '
  1191. return new $class;
  1192. '), $installed);
  1193. }
  1194. function flush_rewrite_rules_if_necessary(){
  1195. global $wp_rewrite;
  1196. $start = microtime(True);
  1197. $original = get_option('rewrite_rules');
  1198. $rules = $wp_rewrite->rewrite_rules();
  1199. if (!$rules or !$original){
  1200. return;
  1201. }
  1202. ksort($rules);
  1203. ksort($original);
  1204. $rules = md5(implode('', array_keys($rules)));
  1205. $original = md5(implode('', array_keys($original)));
  1206. if ($rules != $original){
  1207. flush_rewrite_rules();
  1208. }
  1209. }
  1210. /**
  1211. * Registers all installed custom taxonomies
  1212. *
  1213. * @return void
  1214. * @author Chris Conover
  1215. **/
  1216. function register_custom_taxonomies(){
  1217. #Register custom post types
  1218. foreach(installed_custom_taxonomies() as $custom_taxonomy){
  1219. $custom_taxonomy->register();
  1220. }
  1221. }
  1222. add_action('init', 'register_custom_taxonomies');
  1223. /**
  1224. * Registers all installed custom post types
  1225. *
  1226. * @return void
  1227. * @author Jared Lang
  1228. **/
  1229. function register_custom_post_types(){
  1230. #Register custom post types
  1231. foreach(installed_custom_post_types() as $custom_post_type){
  1232. $custom_post_type->register();
  1233. }
  1234. #This ensures that the permalinks for custom posts work
  1235. flush_rewrite_rules_if_necessary();
  1236. }
  1237. add_action('init', 'register_custom_post_types');
  1238. /**
  1239. * Registers all metaboxes for install custom post types
  1240. *
  1241. * @return void
  1242. * @author Jared Lang
  1243. **/
  1244. function register_meta_boxes(){
  1245. #Register custom post types metaboxes
  1246. foreach(installed_custom_post_types() as $custom_post_type){
  1247. $custom_post_type->register_metaboxes();
  1248. }
  1249. }
  1250. add_action('do_meta_boxes', 'register_meta_boxes');
  1251. /***************************************************************************
  1252. * POST DATA HANDLERS and META BOX FUNCTIONS
  1253. *
  1254. * Functions that display and save custom post types and their meta data.
  1255. *
  1256. ***************************************************************************/
  1257. /**
  1258. * Saves the data for a given post type
  1259. *
  1260. * @return void
  1261. * @author Jared Lang
  1262. **/
  1263. function save_meta_data($post){
  1264. #Register custom post types metaboxes
  1265. foreach(installed_custom_post_types() as $custom_post_type){
  1266. if (post_type($post) == $custom_post_type->options('name')){
  1267. $meta_box = $custom_post_type->metabox();
  1268. break;
  1269. }
  1270. }
  1271. return _save_meta_data($post, $meta_box);
  1272. }
  1273. add_action('save_post', 'save_meta_data');
  1274. /**
  1275. * Displays the metaboxes for a given post type
  1276. *
  1277. * @return void
  1278. * @author Jared Lang
  1279. **/
  1280. function show_meta_boxes($post){
  1281. #Register custom post types metaboxes
  1282. foreach(installed_custom_post_types() as $custom_post_type){
  1283. if (post_type($post) == $custom_post_type->options('name')){
  1284. $meta_box = $custom_post_type->metabox();
  1285. break;
  1286. }
  1287. }
  1288. return _show_meta_boxes($post, $meta_box);
  1289. }
  1290. function save_file($post_id, $field){
  1291. $file_uploaded = @!empty($_FILES[$field['id']]);
  1292. if ($file_uploaded){
  1293. require_once(ABSPATH.'wp-admin/includes/file.php');
  1294. $override['action'] = 'editpost';
  1295. $file = $_FILES[$field['id']];
  1296. $uploaded_file = wp_handle_upload($file, $override);
  1297. # TODO: Pass reason for error back to frontend
  1298. if ($uploaded_file['error']){return;}
  1299. $attachment = array(
  1300. 'post_title' => $file['name'],
  1301. 'post_content' => '',
  1302. 'post_type' => 'attachment',
  1303. 'post_parent' => $post_id,
  1304. 'post_mime_type' => $file['type'],
  1305. 'guid' => $uploaded_file['url'],
  1306. );
  1307. $id = wp_insert_attachment($attachment, $file['file'], $post_id);
  1308. wp_update_attachment_metadata(
  1309. $id,
  1310. wp_generate_attachment_metadata($id, $file['file'])
  1311. );
  1312. update_post_meta($post_id, $field['id'], $id);
  1313. }
  1314. }
  1315. function save_default($post_id, $field){
  1316. $old = get_post_meta($post_id, $field['id'], true);
  1317. $new = $_POST[$field['id']];
  1318. # Update if new is not empty and is not the same value as old
  1319. if ($new !== "" and $new !== null and $new != $old) {
  1320. update_post_meta($post_id, $field['id'], $new);
  1321. }
  1322. # Delete if we're sending a new null value and there was an old value
  1323. elseif (($new === "" or is_null($new)) and $old) {
  1324. delete_post_meta($post_id, $field['id'], $old);
  1325. }
  1326. # Otherwise we do nothing, field stays the same
  1327. return;
  1328. }
  1329. /**
  1330. * Handles saving a custom post as well as its custom fields and metadata.
  1331. *
  1332. * @return void
  1333. * @author Jared Lang
  1334. **/
  1335. function _save_meta_data($post_id, $meta_box){
  1336. // verify nonce
  1337. if (!wp_verify_nonce($_POST['meta_box_nonce'], basename(__FILE__))) {
  1338. return $post_id;
  1339. }
  1340. // check autosave
  1341. if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
  1342. return $post_id;
  1343. }
  1344. // check permissions
  1345. if ('page' == $_POST['post_type']) {
  1346. if (!current_user_can('edit_page', $post_id)) {
  1347. return $post_id;
  1348. }
  1349. } elseif (!current_user_can('edit_post', $post_id)) {
  1350. return $post_id;
  1351. }
  1352. foreach ($meta_box['fields'] as $field) {
  1353. switch ($field['type']){
  1354. case 'file':
  1355. save_file($post_id, $field);
  1356. break;
  1357. default:
  1358. save_default($post_id, $field);
  1359. break;
  1360. }
  1361. }
  1362. }
  1363. /**
  1364. * Outputs the html for the fields defined for a given post and metabox.
  1365. *
  1366. * @return void
  1367. * @author Jared Lang
  1368. **/
  1369. function _show_meta_boxes($post, $meta_box){
  1370. ?>
  1371. <input type="hidden" name="meta_box_nonce" value="<?=wp_create_nonce(basename(__FILE__))?>"/>
  1372. <table class="form-table">
  1373. <?php foreach($meta_box['fields'] as $field):
  1374. $current_value = get_post_meta($post->ID, $field['id'], true);?>
  1375. <tr>
  1376. <th><label for="<?=$field['id']?>"><?=$field['name']?></label></th>
  1377. <td>
  1378. <?php if($field['desc']):?>
  1379. <div class="description">
  1380. <?=$field['desc']?>
  1381. </div>
  1382. <?php endif;?>
  1383. <?php switch ($field['type']):
  1384. case 'text':?>
  1385. <input type="text" name="<?=$field['id']?>" id="<?=$field['id']?>" value="<?=($current_value) ? htmlentities($current_value) : $field['std']?>" />
  1386. <?php break; case 'textarea':?>
  1387. <textarea name="<?=$field['id']?>" id="<?=$field['id']?>" cols="60" rows="4"><?=($current_value) ? htmlentities($current_value) : $field['std']?></textarea>
  1388. <?php break; case 'select':?>
  1389. <select name="<?=$field['id']?>" id="<?=$field['id']?>">
  1390. <option value=""><?=($field['default']) ? $field['default'] : '--'?></option>
  1391. <?php foreach ($field['options'] as $k=>$v):?>
  1392. <option <?=($current_value == $v) ? ' selected="selected"' : ''?> value="<?=$v?>"><?=$k?></option>
  1393. <?php endforeach;?>
  1394. </select>
  1395. <?php break; case 'radio':?>
  1396. <?php foreach ($field['options'] as $k=>$v):?>
  1397. <label for="<?=$field['id']?>_<?=slug($k, '_')?>"><?=$k?></label>
  1398. <input type="radio" name="<?=$field['id']?>" id="<?=$field['id']?>_<?=slug($k, '_')?>" value="<?=$v?>"<?=($current_value == $v) ? ' checked="checked"' : ''?> />
  1399. <?php endforeach;?>
  1400. <?php break; case 'checkbox':?>
  1401. <input type="checkbox" name="<?=$field['id']?>" id="<?=$field['id']?>"<?=($current_value) ? ' checked="checked"' : ''?> />
  1402. <?php break; case 'file':?>
  1403. <?php
  1404. $document_id = get_post_meta($post->ID, $field['id'], True);
  1405. if ($document_id){
  1406. $document = get_post($document_id);
  1407. $url = str_replace('https://', 'http://', wp_get_attachment_url($document->ID));
  1408. }else{
  1409. $document = null;
  1410. }
  1411. ?>
  1412. <?php if($document):?>
  1413. <?php
  1414. // Is this is a file upload field for a Resource Link?
  1415. if ($post->post_type == 'document') {
  1416. // Give a direct link to the Enable Media Upload replace screen
  1417. $enable_media_replace_dir = 'enable-media-replace/enable-media-replace.php';
  1418. $media_edit_url = admin_url().'upload.php?page=enable-media-replace/enable-media-replace.php&action=media_replace&attachment_id='.$document->ID;
  1419. // Create a secure URL (Enable Media Replace requires this)
  1420. $action = 'media_replace';
  1421. $nonce_edit_url = wp_nonce_url( $media_edit_url, $action );
  1422. if (FORCE_SSL_ADMIN) {
  1423. $nonce_edit_url = str_replace("http:", "https:", $nonce_edit_url);
  1424. }
  1425. }
  1426. ?>
  1427. <?php if ($post->post_type == 'document') { ?>
  1428. <div class="description"><strong>NOTE:</strong> to replace the current file while maintaining the existing URL, click "Edit/Update File" (opens in a new window.) To use a new file with a new URL, use the file uploader below.</div><br />
  1429. <a href="<?=$url?>"><?=$document->post_title?></a> &nbsp; <a target="_blank" class="button-secondary" href="<?=$nonce_edit_url?>">Edit / Update File</a>
  1430. <?php } else { ?>
  1431. <a href="<?=$url?>"><?=$document->post_title?></a>
  1432. <?php } ?>
  1433. <br /><br />
  1434. <?php endif; ?>
  1435. <input type="file" id="file_<?=$post->ID?>" name="<?=$field['id']?>"><br />
  1436. <?php break; case 'help':?><!-- Do nothing for help -->
  1437. <?php break; default:?>
  1438. <p class="error">Don't know how to handle field of type '<?=$field['type']?>'</p>
  1439. <?php break; endswitch;?>
  1440. <td>
  1441. </tr>
  1442. <?php endforeach;?>
  1443. </table>
  1444. <?php if($meta_box['helptxt']):?>
  1445. <p><?=$meta_box['helptxt']?></p>
  1446. <?php endif;?>
  1447. <?php
  1448. }
  1449. /**
  1450. * Returns the Resouce Group taxonomy terms
  1451. *
  1452. * @return array of terms where key = term name and value = term slug
  1453. *
  1454. * @author Brandon Groves
  1455. **/
  1456. function get_resource_groups() {
  1457. $tax_terms = array();
  1458. $taxes = get_terms( 'resource_groups' );
  1459. foreach ($taxes as $tax) {
  1460. $tax_terms[$tax->name] = $tax->slug;
  1461. }
  1462. return $tax_terms;
  1463. }
  1464. ?>