home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-admin / includes / class-wp-terms-list-table.php < prev    next >
Encoding:
PHP Script  |  2017-10-02  |  17.5 KB  |  636 lines

  1. <?php
  2. /**
  3.  * List Table API: WP_Terms_List_Table class
  4.  *
  5.  * @package WordPress
  6.  * @subpackage Administration
  7.  * @since 3.1.0
  8.  */
  9.  
  10. /**
  11.  * Core class used to implement displaying terms in a list table.
  12.  *
  13.  * @since 3.1.0
  14.  * @access private
  15.  *
  16.  * @see WP_List_Table
  17.  */
  18. class WP_Terms_List_Table extends WP_List_Table {
  19.  
  20.     public $callback_args;
  21.  
  22.     private $level;
  23.  
  24.     /**
  25.      * Constructor.
  26.      *
  27.      * @since 3.1.0
  28.      *
  29.      * @see WP_List_Table::__construct() for more information on default arguments.
  30.      *
  31.      * @global string $post_type
  32.      * @global string $taxonomy
  33.      * @global string $action
  34.      * @global object $tax
  35.      *
  36.      * @param array $args An associative array of arguments.
  37.      */
  38.     public function __construct( $args = array() ) {
  39.         global $post_type, $taxonomy, $action, $tax;
  40.  
  41.         parent::__construct( array(
  42.             'plural' => 'tags',
  43.             'singular' => 'tag',
  44.             'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
  45.         ) );
  46.  
  47.         $action    = $this->screen->action;
  48.         $post_type = $this->screen->post_type;
  49.         $taxonomy  = $this->screen->taxonomy;
  50.  
  51.         if ( empty( $taxonomy ) )
  52.             $taxonomy = 'post_tag';
  53.  
  54.         if ( ! taxonomy_exists( $taxonomy ) )
  55.             wp_die( __( 'Invalid taxonomy.' ) );
  56.  
  57.         $tax = get_taxonomy( $taxonomy );
  58.  
  59.         // @todo Still needed? Maybe just the show_ui part.
  60.         if ( empty( $post_type ) || !in_array( $post_type, get_post_types( array( 'show_ui' => true ) ) ) )
  61.             $post_type = 'post';
  62.  
  63.     }
  64.  
  65.     /**
  66.      *
  67.      * @return bool
  68.      */
  69.     public function ajax_user_can() {
  70.         return current_user_can( get_taxonomy( $this->screen->taxonomy )->cap->manage_terms );
  71.     }
  72.  
  73.     /**
  74.      */
  75.     public function prepare_items() {
  76.         $tags_per_page = $this->get_items_per_page( 'edit_' . $this->screen->taxonomy . '_per_page' );
  77.  
  78.         if ( 'post_tag' === $this->screen->taxonomy ) {
  79.             /**
  80.              * Filters the number of terms displayed per page for the Tags list table.
  81.              *
  82.              * @since 2.8.0
  83.              *
  84.              * @param int $tags_per_page Number of tags to be displayed. Default 20.
  85.              */
  86.             $tags_per_page = apply_filters( 'edit_tags_per_page', $tags_per_page );
  87.  
  88.             /**
  89.              * Filters the number of terms displayed per page for the Tags list table.
  90.              *
  91.              * @since 2.7.0
  92.              * @deprecated 2.8.0 Use edit_tags_per_page instead.
  93.              *
  94.              * @param int $tags_per_page Number of tags to be displayed. Default 20.
  95.              */
  96.             $tags_per_page = apply_filters( 'tagsperpage', $tags_per_page );
  97.         } elseif ( 'category' === $this->screen->taxonomy ) {
  98.             /**
  99.              * Filters the number of terms displayed per page for the Categories list table.
  100.              *
  101.              * @since 2.8.0
  102.              *
  103.              * @param int $tags_per_page Number of categories to be displayed. Default 20.
  104.              */
  105.             $tags_per_page = apply_filters( 'edit_categories_per_page', $tags_per_page );
  106.         }
  107.  
  108.         $search = !empty( $_REQUEST['s'] ) ? trim( wp_unslash( $_REQUEST['s'] ) ) : '';
  109.  
  110.         $args = array(
  111.             'search' => $search,
  112.             'page' => $this->get_pagenum(),
  113.             'number' => $tags_per_page,
  114.         );
  115.  
  116.         if ( !empty( $_REQUEST['orderby'] ) )
  117.             $args['orderby'] = trim( wp_unslash( $_REQUEST['orderby'] ) );
  118.  
  119.         if ( !empty( $_REQUEST['order'] ) )
  120.             $args['order'] = trim( wp_unslash( $_REQUEST['order'] ) );
  121.  
  122.         $this->callback_args = $args;
  123.  
  124.         $this->set_pagination_args( array(
  125.             'total_items' => wp_count_terms( $this->screen->taxonomy, compact( 'search' ) ),
  126.             'per_page' => $tags_per_page,
  127.         ) );
  128.     }
  129.  
  130.     /**
  131.      *
  132.      * @return bool
  133.      */
  134.     public function has_items() {
  135.         // todo: populate $this->items in prepare_items()
  136.         return true;
  137.     }
  138.  
  139.     /**
  140.      */
  141.     public function no_items() {
  142.         echo get_taxonomy( $this->screen->taxonomy )->labels->not_found;
  143.     }
  144.  
  145.     /**
  146.      *
  147.      * @return array
  148.      */
  149.     protected function get_bulk_actions() {
  150.         $actions = array();
  151.  
  152.         if ( current_user_can( get_taxonomy( $this->screen->taxonomy )->cap->delete_terms ) ) {
  153.             $actions['delete'] = __( 'Delete' );
  154.         }
  155.  
  156.         return $actions;
  157.     }
  158.  
  159.     /**
  160.      *
  161.      * @return string
  162.      */
  163.     public function current_action() {
  164.         if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['delete_tags'] ) && ( 'delete' === $_REQUEST['action'] || 'delete' === $_REQUEST['action2'] ) )
  165.             return 'bulk-delete';
  166.  
  167.         return parent::current_action();
  168.     }
  169.  
  170.     /**
  171.      *
  172.      * @return array
  173.      */
  174.     public function get_columns() {
  175.         $columns = array(
  176.             'cb'          => '<input type="checkbox" />',
  177.             'name'        => _x( 'Name', 'term name' ),
  178.             'description' => __( 'Description' ),
  179.             'slug'        => __( 'Slug' ),
  180.         );
  181.  
  182.         if ( 'link_category' === $this->screen->taxonomy ) {
  183.             $columns['links'] = __( 'Links' );
  184.         } else {
  185.             $columns['posts'] = _x( 'Count', 'Number/count of items' );
  186.         }
  187.  
  188.         return $columns;
  189.     }
  190.  
  191.     /**
  192.      *
  193.      * @return array
  194.      */
  195.     protected function get_sortable_columns() {
  196.         return array(
  197.             'name'        => 'name',
  198.             'description' => 'description',
  199.             'slug'        => 'slug',
  200.             'posts'       => 'count',
  201.             'links'       => 'count'
  202.         );
  203.     }
  204.  
  205.     /**
  206.      */
  207.     public function display_rows_or_placeholder() {
  208.         $taxonomy = $this->screen->taxonomy;
  209.  
  210.         $args = wp_parse_args( $this->callback_args, array(
  211.             'page' => 1,
  212.             'number' => 20,
  213.             'search' => '',
  214.             'hide_empty' => 0
  215.         ) );
  216.  
  217.         $page = $args['page'];
  218.  
  219.         // Set variable because $args['number'] can be subsequently overridden.
  220.         $number = $args['number'];
  221.  
  222.         $args['offset'] = $offset = ( $page - 1 ) * $number;
  223.  
  224.         // Convert it to table rows.
  225.         $count = 0;
  226.  
  227.         if ( is_taxonomy_hierarchical( $taxonomy ) && ! isset( $args['orderby'] ) ) {
  228.             // We'll need the full set of terms then.
  229.             $args['number'] = $args['offset'] = 0;
  230.         }
  231.         $terms = get_terms( $taxonomy, $args );
  232.  
  233.         if ( empty( $terms ) || ! is_array( $terms ) ) {
  234.             echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
  235.             $this->no_items();
  236.             echo '</td></tr>';
  237.             return;
  238.         }
  239.  
  240.         if ( is_taxonomy_hierarchical( $taxonomy ) && ! isset( $args['orderby'] ) ) {
  241.             if ( ! empty( $args['search'] ) ) {// Ignore children on searches.
  242.                 $children = array();
  243.             } else {
  244.                 $children = _get_term_hierarchy( $taxonomy );
  245.             }
  246.             // Some funky recursion to get the job done( Paging & parents mainly ) is contained within, Skip it for non-hierarchical taxonomies for performance sake
  247.             $this->_rows( $taxonomy, $terms, $children, $offset, $number, $count );
  248.         } else {
  249.             foreach ( $terms as $term ) {
  250.                 $this->single_row( $term );
  251.             }
  252.         }
  253.     }
  254.  
  255.     /**
  256.      * @param string $taxonomy
  257.      * @param array $terms
  258.      * @param array $children
  259.      * @param int   $start
  260.      * @param int   $per_page
  261.      * @param int   $count
  262.      * @param int   $parent
  263.      * @param int   $level
  264.      */
  265.     private function _rows( $taxonomy, $terms, &$children, $start, $per_page, &$count, $parent = 0, $level = 0 ) {
  266.  
  267.         $end = $start + $per_page;
  268.  
  269.         foreach ( $terms as $key => $term ) {
  270.  
  271.             if ( $count >= $end )
  272.                 break;
  273.  
  274.             if ( $term->parent != $parent && empty( $_REQUEST['s'] ) )
  275.                 continue;
  276.  
  277.             // If the page starts in a subtree, print the parents.
  278.             if ( $count == $start && $term->parent > 0 && empty( $_REQUEST['s'] ) ) {
  279.                 $my_parents = $parent_ids = array();
  280.                 $p = $term->parent;
  281.                 while ( $p ) {
  282.                     $my_parent = get_term( $p, $taxonomy );
  283.                     $my_parents[] = $my_parent;
  284.                     $p = $my_parent->parent;
  285.                     if ( in_array( $p, $parent_ids ) ) // Prevent parent loops.
  286.                         break;
  287.                     $parent_ids[] = $p;
  288.                 }
  289.                 unset( $parent_ids );
  290.  
  291.                 $num_parents = count( $my_parents );
  292.                 while ( $my_parent = array_pop( $my_parents ) ) {
  293.                     echo "\t";
  294.                     $this->single_row( $my_parent, $level - $num_parents );
  295.                     $num_parents--;
  296.                 }
  297.             }
  298.  
  299.             if ( $count >= $start ) {
  300.                 echo "\t";
  301.                 $this->single_row( $term, $level );
  302.             }
  303.  
  304.             ++$count;
  305.  
  306.             unset( $terms[$key] );
  307.  
  308.             if ( isset( $children[$term->term_id] ) && empty( $_REQUEST['s'] ) )
  309.                 $this->_rows( $taxonomy, $terms, $children, $start, $per_page, $count, $term->term_id, $level + 1 );
  310.         }
  311.     }
  312.  
  313.     /**
  314.      * @global string $taxonomy
  315.      * @param WP_Term $tag Term object.
  316.      * @param int $level
  317.      */
  318.     public function single_row( $tag, $level = 0 ) {
  319.         global $taxonomy;
  320.          $tag = sanitize_term( $tag, $taxonomy );
  321.  
  322.         $this->level = $level;
  323.  
  324.         echo '<tr id="tag-' . $tag->term_id . '">';
  325.         $this->single_row_columns( $tag );
  326.         echo '</tr>';
  327.     }
  328.  
  329.     /**
  330.      * @param WP_Term $tag Term object.
  331.      * @return string
  332.      */
  333.     public function column_cb( $tag ) {
  334.         if ( current_user_can( 'delete_term', $tag->term_id ) ) {
  335.             return '<label class="screen-reader-text" for="cb-select-' . $tag->term_id . '">' . sprintf( __( 'Select %s' ), $tag->name ) . '</label>'
  336.                 . '<input type="checkbox" name="delete_tags[]" value="' . $tag->term_id . '" id="cb-select-' . $tag->term_id . '" />';
  337.         }
  338.  
  339.         return ' ';
  340.     }
  341.  
  342.     /**
  343.      * @param WP_Term $tag Term object.
  344.      * @return string
  345.      */
  346.     public function column_name( $tag ) {
  347.         $taxonomy = $this->screen->taxonomy;
  348.  
  349.         $pad = str_repeat( '— ', max( 0, $this->level ) );
  350.  
  351.         /**
  352.          * Filters display of the term name in the terms list table.
  353.          *
  354.          * The default output may include padding due to the term's
  355.          * current level in the term hierarchy.
  356.          *
  357.          * @since 2.5.0
  358.          *
  359.          * @see WP_Terms_List_Table::column_name()
  360.          *
  361.          * @param string $pad_tag_name The term name, padded if not top-level.
  362.          * @param WP_Term $tag         Term object.
  363.          */
  364.         $name = apply_filters( 'term_name', $pad . ' ' . $tag->name, $tag );
  365.  
  366.         $qe_data = get_term( $tag->term_id, $taxonomy, OBJECT, 'edit' );
  367.  
  368.         $uri = wp_doing_ajax() ? wp_get_referer() : $_SERVER['REQUEST_URI'];
  369.  
  370.         $edit_link = add_query_arg(
  371.             'wp_http_referer',
  372.             urlencode( wp_unslash( $uri ) ),
  373.             get_edit_term_link( $tag->term_id, $taxonomy, $this->screen->post_type )
  374.         );
  375.  
  376.         $out = sprintf(
  377.             '<strong><a class="row-title" href="%s" aria-label="%s">%s</a></strong><br />',
  378.             esc_url( $edit_link ),
  379.             /* translators: %s: taxonomy term name */
  380.             esc_attr( sprintf( __( '“%s” (Edit)' ), $tag->name ) ),
  381.             $name
  382.         );
  383.  
  384.         $out .= '<div class="hidden" id="inline_' . $qe_data->term_id . '">';
  385.         $out .= '<div class="name">' . $qe_data->name . '</div>';
  386.  
  387.         /** This filter is documented in wp-admin/edit-tag-form.php */
  388.         $out .= '<div class="slug">' . apply_filters( 'editable_slug', $qe_data->slug, $qe_data ) . '</div>';
  389.         $out .= '<div class="parent">' . $qe_data->parent . '</div></div>';
  390.  
  391.         return $out;
  392.     }
  393.  
  394.     /**
  395.      * Gets the name of the default primary column.
  396.      *
  397.      * @since 4.3.0
  398.      *
  399.      * @return string Name of the default primary column, in this case, 'name'.
  400.      */
  401.     protected function get_default_primary_column_name() {
  402.         return 'name';
  403.     }
  404.  
  405.     /**
  406.      * Generates and displays row action links.
  407.      *
  408.      * @since 4.3.0
  409.      *
  410.      * @param WP_Term $tag         Tag being acted upon.
  411.      * @param string  $column_name Current column name.
  412.      * @param string  $primary     Primary column name.
  413.      * @return string Row actions output for terms.
  414.      */
  415.     protected function handle_row_actions( $tag, $column_name, $primary ) {
  416.         if ( $primary !== $column_name ) {
  417.             return '';
  418.         }
  419.  
  420.         $taxonomy = $this->screen->taxonomy;
  421.         $tax = get_taxonomy( $taxonomy );
  422.         $uri = wp_doing_ajax() ? wp_get_referer() : $_SERVER['REQUEST_URI'];
  423.  
  424.         $edit_link = add_query_arg(
  425.             'wp_http_referer',
  426.             urlencode( wp_unslash( $uri ) ),
  427.             get_edit_term_link( $tag->term_id, $taxonomy, $this->screen->post_type )
  428.         );
  429.  
  430.         $actions = array();
  431.         if ( current_user_can( 'edit_term', $tag->term_id ) ) {
  432.             $actions['edit'] = sprintf(
  433.                 '<a href="%s" aria-label="%s">%s</a>',
  434.                 esc_url( $edit_link ),
  435.                 /* translators: %s: taxonomy term name */
  436.                 esc_attr( sprintf( __( 'Edit “%s”' ), $tag->name ) ),
  437.                 __( 'Edit' )
  438.             );
  439.             $actions['inline hide-if-no-js'] = sprintf(
  440.                 '<a href="#" class="editinline aria-button-if-js" aria-label="%s">%s</a>',
  441.                 /* translators: %s: taxonomy term name */
  442.                 esc_attr( sprintf( __( 'Quick edit “%s” inline' ), $tag->name ) ),
  443.                 __( 'Quick Edit' )
  444.             );
  445.         }
  446.         if ( current_user_can( 'delete_term', $tag->term_id ) ) {
  447.             $actions['delete'] = sprintf(
  448.                 '<a href="%s" class="delete-tag aria-button-if-js" aria-label="%s">%s</a>',
  449.                 wp_nonce_url( "edit-tags.php?action=delete&taxonomy=$taxonomy&tag_ID=$tag->term_id", 'delete-tag_' . $tag->term_id ),
  450.                 /* translators: %s: taxonomy term name */
  451.                 esc_attr( sprintf( __( 'Delete “%s”' ), $tag->name ) ),
  452.                 __( 'Delete' )
  453.             );
  454.         }
  455.         if ( $tax->public ) {
  456.             $actions['view'] = sprintf(
  457.                 '<a href="%s" aria-label="%s">%s</a>',
  458.                 get_term_link( $tag ),
  459.                 /* translators: %s: taxonomy term name */
  460.                 esc_attr( sprintf( __( 'View “%s” archive' ), $tag->name ) ),
  461.                 __( 'View' )
  462.             );
  463.         }
  464.  
  465.         /**
  466.          * Filters the action links displayed for each term in the Tags list table.
  467.          *
  468.          * @since 2.8.0
  469.          * @deprecated 3.0.0 Use {$taxonomy}_row_actions instead.
  470.          *
  471.          * @param array  $actions An array of action links to be displayed. Default
  472.          *                        'Edit', 'Quick Edit', 'Delete', and 'View'.
  473.          * @param WP_Term $tag    Term object.
  474.          */
  475.         $actions = apply_filters( 'tag_row_actions', $actions, $tag );
  476.  
  477.         /**
  478.          * Filters the action links displayed for each term in the terms list table.
  479.          *
  480.          * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
  481.          *
  482.          * @since 3.0.0
  483.          *
  484.          * @param array  $actions An array of action links to be displayed. Default
  485.          *                        'Edit', 'Quick Edit', 'Delete', and 'View'.
  486.          * @param WP_Term $tag    Term object.
  487.          */
  488.         $actions = apply_filters( "{$taxonomy}_row_actions", $actions, $tag );
  489.  
  490.         return $this->row_actions( $actions );
  491.     }
  492.  
  493.     /**
  494.      * @param WP_Term $tag Term object.
  495.      * @return string
  496.      */
  497.     public function column_description( $tag ) {
  498.         if ( $tag->description ) {
  499.             return $tag->description;
  500.         } else {
  501.             return '<span aria-hidden="true">—</span><span class="screen-reader-text">' . __( 'No description' ) . '</span>';
  502.         }
  503.     }
  504.  
  505.     /**
  506.      * @param WP_Term $tag Term object.
  507.      * @return string
  508.      */
  509.     public function column_slug( $tag ) {
  510.         /** This filter is documented in wp-admin/edit-tag-form.php */
  511.         return apply_filters( 'editable_slug', $tag->slug, $tag );
  512.     }
  513.  
  514.     /**
  515.      * @param WP_Term $tag Term object.
  516.      * @return string
  517.      */
  518.     public function column_posts( $tag ) {
  519.         $count = number_format_i18n( $tag->count );
  520.  
  521.         $tax = get_taxonomy( $this->screen->taxonomy );
  522.  
  523.         $ptype_object = get_post_type_object( $this->screen->post_type );
  524.         if ( ! $ptype_object->show_ui )
  525.             return $count;
  526.  
  527.         if ( $tax->query_var ) {
  528.             $args = array( $tax->query_var => $tag->slug );
  529.         } else {
  530.             $args = array( 'taxonomy' => $tax->name, 'term' => $tag->slug );
  531.         }
  532.  
  533.         if ( 'post' != $this->screen->post_type )
  534.             $args['post_type'] = $this->screen->post_type;
  535.  
  536.         if ( 'attachment' === $this->screen->post_type )
  537.             return "<a href='" . esc_url ( add_query_arg( $args, 'upload.php' ) ) . "'>$count</a>";
  538.  
  539.         return "<a href='" . esc_url ( add_query_arg( $args, 'edit.php' ) ) . "'>$count</a>";
  540.     }
  541.  
  542.     /**
  543.      * @param WP_Term $tag Term object.
  544.      * @return string
  545.      */
  546.     public function column_links( $tag ) {
  547.         $count = number_format_i18n( $tag->count );
  548.         if ( $count )
  549.             $count = "<a href='link-manager.php?cat_id=$tag->term_id'>$count</a>";
  550.         return $count;
  551.     }
  552.  
  553.     /**
  554.      * @param WP_Term $tag Term object.
  555.      * @param string $column_name
  556.      * @return string
  557.      */
  558.     public function column_default( $tag, $column_name ) {
  559.         /**
  560.          * Filters the displayed columns in the terms list table.
  561.          *
  562.          * The dynamic portion of the hook name, `$this->screen->taxonomy`,
  563.          * refers to the slug of the current taxonomy.
  564.          *
  565.          * @since 2.8.0
  566.          *
  567.          * @param string $string      Blank string.
  568.          * @param string $column_name Name of the column.
  569.          * @param int    $term_id     Term ID.
  570.          */
  571.         return apply_filters( "manage_{$this->screen->taxonomy}_custom_column", '', $column_name, $tag->term_id );
  572.     }
  573.  
  574.     /**
  575.      * Outputs the hidden row displayed when inline editing
  576.      *
  577.      * @since 3.1.0
  578.      */
  579.     public function inline_edit() {
  580.         $tax = get_taxonomy( $this->screen->taxonomy );
  581.  
  582.         if ( ! current_user_can( $tax->cap->edit_terms ) )
  583.             return;
  584. ?>
  585.  
  586.     <form method="get"><table style="display: none"><tbody id="inlineedit">
  587.         <tr id="inline-edit" class="inline-edit-row" style="display: none"><td colspan="<?php echo $this->get_column_count(); ?>" class="colspanchange">
  588.  
  589.             <fieldset>
  590.                 <legend class="inline-edit-legend"><?php _e( 'Quick Edit' ); ?></legend>
  591.                 <div class="inline-edit-col">
  592.                 <label>
  593.                     <span class="title"><?php _ex( 'Name', 'term name' ); ?></span>
  594.                     <span class="input-text-wrap"><input type="text" name="name" class="ptitle" value="" /></span>
  595.                 </label>
  596.     <?php if ( !global_terms_enabled() ) { ?>
  597.                 <label>
  598.                     <span class="title"><?php _e( 'Slug' ); ?></span>
  599.                     <span class="input-text-wrap"><input type="text" name="slug" class="ptitle" value="" /></span>
  600.                 </label>
  601.     <?php } ?>
  602.             </div></fieldset>
  603.     <?php
  604.  
  605.         $core_columns = array( 'cb' => true, 'description' => true, 'name' => true, 'slug' => true, 'posts' => true );
  606.  
  607.         list( $columns ) = $this->get_column_info();
  608.  
  609.         foreach ( $columns as $column_name => $column_display_name ) {
  610.             if ( isset( $core_columns[$column_name] ) )
  611.                 continue;
  612.  
  613.             /** This action is documented in wp-admin/includes/class-wp-posts-list-table.php */
  614.             do_action( 'quick_edit_custom_box', $column_name, 'edit-tags', $this->screen->taxonomy );
  615.         }
  616.  
  617.     ?>
  618.  
  619.         <div class="inline-edit-save submit">
  620.             <button type="button" class="cancel button alignleft"><?php _e( 'Cancel' ); ?></button>
  621.             <button type="button" class="save button button-primary alignright"><?php echo $tax->labels->update_item; ?></button>
  622.             <span class="spinner"></span>
  623.             <?php wp_nonce_field( 'taxinlineeditnonce', '_inline_edit', false ); ?>
  624.             <input type="hidden" name="taxonomy" value="<?php echo esc_attr( $this->screen->taxonomy ); ?>" />
  625.             <input type="hidden" name="post_type" value="<?php echo esc_attr( $this->screen->post_type ); ?>" />
  626.             <br class="clear" />
  627.             <div class="notice notice-error notice-alt inline hidden">
  628.                 <p class="error"></p>
  629.             </div>
  630.         </div>
  631.         </td></tr>
  632.         </tbody></table></form>
  633.     <?php
  634.     }
  635. }
  636.