$render_options The render options for the table.
*/
$js_options = apply_filters( 'tablepress_table_js_options', $js_options, $table_id, $render_options );
$this->shown_tables[ $table_id ]['instances'][ (string) $render_options['html_id'] ] = $js_options;
$this->_enqueue_datatables();
}
// Maybe print a list of used render options.
if ( $render_options['shortcode_debug'] && is_user_logged_in() ) {
$output .= '' . var_export( $render_options, true ) . '
'; // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export
}
return $output;
}
/**
* Handle Shortcode [table-info id= field= /].
*
* @since 1.0.0
*
* @param array|string $shortcode_atts List of attributes that where included in the Shortcode. An empty string for empty Shortcodes like [table] or [table /].
* @return string Text that replaces the Shortcode (error message or asked-for information).
*/
public function shortcode_table_info( /* array|string */ $shortcode_atts ): string {
$shortcode_atts = (array) $shortcode_atts;
// Parse Shortcode attributes, only allow those that are specified.
$default_shortcode_atts = array(
'id' => '',
'field' => '',
'format' => '',
);
/**
* Filters the available/default attributes for the [table-info] Shortcode.
*
* @since 1.0.0
*
* @param array $default_shortcode_atts The [table-info] Shortcode default attributes.
*/
$default_shortcode_atts = apply_filters( 'tablepress_shortcode_table_info_default_shortcode_atts', $default_shortcode_atts );
$shortcode_atts = shortcode_atts( $default_shortcode_atts, $shortcode_atts ); // Optional third argument left out on purpose. Use filter in the next line instead.
/**
* Filters the attributes that were passed to the [table-info] Shortcode.
*
* @since 1.0.0
*
* @param array $shortcode_atts The attributes passed to the [table-info] Shortcode.
*/
$shortcode_atts = apply_filters( 'tablepress_shortcode_table_info_shortcode_atts', $shortcode_atts );
/**
* Filters whether the output of the [table-info] Shortcode is overwritten/short-circuited.
*
* @since 1.0.0
*
* @param false|string $overwrite Whether the [table-info] output is overwritten. Return false for the regular content, and a string to overwrite the output.
* @param array $shortcode_atts The attributes passed to the [table-info] Shortcode.
*/
$overwrite = apply_filters( 'tablepress_shortcode_table_info_overwrite', false, $shortcode_atts );
if ( is_string( $overwrite ) ) {
return $overwrite;
}
// Check, if a table with the given ID exists.
$table_id = preg_replace( '/[^a-zA-Z0-9_-]/', '', $shortcode_atts['id'] );
if ( ! TablePress::$model_table->table_exists( $table_id ) ) {
$message = "[table “{$table_id}” not found /]
\n";
/** This filter is documented in controllers/controller-frontend.php */
$message = apply_filters( 'tablepress_table_not_found_message', $message, $table_id );
return $message;
}
// Load table, with table data, options, and visibility settings.
$table = TablePress::$model_table->load( $table_id, true, true );
if ( is_wp_error( $table ) ) {
$message = "[table “{$table_id}” could not be loaded /]
\n";
/** This filter is documented in controllers/controller-frontend.php */
$message = apply_filters( 'tablepress_table_load_error_message', $message, $table_id, $table );
return $message;
}
$field = (string) preg_replace( '/[^a-z_]/', '', strtolower( $shortcode_atts['field'] ) );
$format = (string) preg_replace( '/[^a-z]/', '', strtolower( $shortcode_atts['format'] ) );
// Generate output, depending on what information (field) was asked for.
switch ( $field ) {
case 'name':
case 'description':
$output = $table[ $field ];
break;
case 'last_modified':
switch ( $format ) {
case 'raw':
case 'mysql':
$output = $table['last_modified'];
break;
case 'human':
$modified_timestamp = date_create( $table['last_modified'], wp_timezone() );
$modified_timestamp = $modified_timestamp->getTimestamp(); // @phpstan-ignore-line
$current_timestamp = time();
$time_diff = $current_timestamp - $modified_timestamp;
// Time difference is only shown up to one week.
if ( $time_diff >= 0 && $time_diff < WEEK_IN_SECONDS ) {
$output = sprintf( __( '%s ago', 'default' ), human_time_diff( $modified_timestamp, $current_timestamp ) );
} else {
$output = TablePress::format_datetime( $table['last_modified'], '
' );
}
break;
case 'date':
$output = TablePress::format_datetime( $table['last_modified'], get_option( 'date_format' ) );
break;
case 'time':
$output = TablePress::format_datetime( $table['last_modified'], get_option( 'time_format' ) );
break;
default:
$output = TablePress::format_datetime( $table['last_modified'] );
break;
}
break;
case 'last_editor':
$output = TablePress::get_user_display_name( $table['options']['last_editor'] );
break;
case 'author':
$output = TablePress::get_user_display_name( $table['author'] );
break;
case 'number_rows':
$output = count( $table['data'] );
if ( 'raw' !== $format ) {
if ( $table['options']['table_head'] ) {
--$output;
}
if ( $table['options']['table_foot'] ) {
--$output;
}
}
break;
case 'number_columns':
$output = count( $table['data'][0] );
break;
default:
$output = "[table-info field “{$field}” not found in table “{$table_id}” /]
\n";
/**
* Filters the "table info field not found" message.
*
* @since 1.0.0
*
* @param string $output The "table info field not found" message.
* @param array $table The current table.
* @param string $field The field that was not found.
* @param string $format The return format for the field.
*/
$output = apply_filters( 'tablepress_table_info_not_found_message', $output, $table, $field, $format );
}
/**
* Filters the output of the [table-info] Shortcode.
*
* @since 1.0.0
*
* @param string $output The output of the [table-info] Shortcode.
* @param array $table The current table.
* @param array $shortcode_atts The attributes passed to the [table-info] Shortcode.
*/
$output = apply_filters( 'tablepress_shortcode_table_info_output', $output, $table, $shortcode_atts );
return $output;
}
/**
* Expand WP Search to also find posts and pages that have a search term in a table that is shown in them.
*
* This is done by looping through all search terms and TablePress tables and searching there for the search term,
* saving all tables's IDs that have a search term and then expanding the WP query to search for posts or pages that have the
* Shortcode for one of these tables in their content.
*
* @since 1.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $search_sql Current part of the "WHERE" clause of the SQL statement used to get posts/pages from the WP database that is related to searching.
* @return string Eventually extended SQL "WHERE" clause, to also find posts/pages with Shortcodes in them.
*/
public function posts_search_filter( /* string */ $search_sql ): string {
// Don't use a type hint in the method declaration as there can be cases where `null` is passed to the filter hook callback somehow.
global $wpdb;
// Protect against cases where `null` is somehow passed to the filter hook callback.
if ( ! is_string( $search_sql ) ) {
return '';
}
if ( ! is_search() || ! is_main_query() ) {
return $search_sql;
}
// Get variable that contains all search terms, parsed from $_GET['s'] by WP.
$search_terms = get_query_var( 'search_terms' );
if ( empty( $search_terms ) || ! is_array( $search_terms ) ) {
return $search_sql;
}
// Load all table IDs and prime post meta cache for cached access to options and visibility settings of the tables, don't run filter hook.
$table_ids = TablePress::$model_table->load_all( true, false );
// Array of all search words that were found, and the table IDs where they were found.
$query_result = array();
foreach ( $table_ids as $table_id ) {
// Load table, with table data, options, and visibility settings.
$table = TablePress::$model_table->load( $table_id, true, true );
if ( isset( $table['is_corrupted'] ) && $table['is_corrupted'] ) {
// Do not search in corrupted tables.
continue;
}
foreach ( $search_terms as $search_term ) {
if ( ( $table['options']['print_name'] && false !== stripos( $table['name'], $search_term ) ) // @phpstan-ignore-line
|| ( $table['options']['print_description'] && false !== stripos( $table['description'], $search_term ) ) ) { // @phpstan-ignore-line
// Found the search term in the name or description (and they are shown).
$query_result[ $search_term ][] = $table_id; // Add table ID to result list.
// No need to continue searching this search term in this table.
continue;
}
// Search search term in visible table cells (without taking Shortcode parameters into account!).
foreach ( $table['data'] as $row_idx => $table_row ) { // @phpstan-ignore-line
if ( 0 === $table['visibility']['rows'][ $row_idx ] ) {
// Row is hidden, so don't search in it.
continue;
}
foreach ( $table_row as $col_idx => $table_cell ) {
if ( 0 === $table['visibility']['columns'][ $col_idx ] ) {
// Column is hidden, so don't search in it.
continue;
}
// @todo Cells are not evaluated here, so math formulas are searched.
if ( false !== stripos( $table_cell, $search_term ) ) {
// Found the search term in the cell content.
$query_result[ $search_term ][] = $table_id; // Add table ID to result list
// No need to continue searching this search term in this table.
continue 3;
}
}
}
}
}
// For all found table IDs for each search term, add additional OR statement to the SQL "WHERE" clause.
// If $_GET['exact'] is set, WordPress doesn't use % in SQL LIKE clauses.
$exact = get_query_var( 'exact' );
$n = ( empty( $exact ) ) ? '%' : '';
$search_sql = $wpdb->remove_placeholder_escape( $search_sql );
foreach ( $query_result as $search_term => $table_ids ) {
$search_term = esc_sql( $wpdb->esc_like( $search_term ) );
$old_or = "OR ({$wpdb->posts}.post_content LIKE '{$n}{$search_term}{$n}')"; // @phpstan-ignore-line
$table_ids = implode( '|', $table_ids );
$regexp = '\\\\[' . TablePress::$shortcode . ' id=(["\\\']?)(' . $table_ids . ')([\]"\\\' /])'; // ' needs to be single escaped, [ double escaped (with \\) in mySQL
$new_or = $old_or . " OR ({$wpdb->posts}.post_content REGEXP '{$regexp}')";
$search_sql = str_replace( $old_or, $new_or, $search_sql );
}
$search_sql = $wpdb->add_placeholder_escape( $search_sql );
return $search_sql;
}
/**
* Callback function for rendering the tablepress/table block.
*
* @since 2.0.0
*
* @param array $block_attributes List of attributes that where included in the block settings.
* @return string Resulting HTML code for the table.
*/
public function table_block_render_callback( array $block_attributes ): string {
// Don't return anything if no table was selected.
if ( '' === $block_attributes['id'] ) {
return '';
}
if ( '' !== trim( $block_attributes['parameters'] ) ) {
$render_attributes = shortcode_parse_atts( $block_attributes['parameters'] );
} else {
$render_attributes = array();
}
$render_attributes['id'] = $block_attributes['id']; // @phpstan-ignore-line
return $this->shortcode_table( $render_attributes );
}
} // class TablePress_Frontend_Controller