326 lines
15 KiB
PHP
326 lines
15 KiB
PHP
<?php
|
|
/*
|
|
Plugin Name: TablePress Extension: Pods tables
|
|
Plugin URI: https://code.studioinfinity.org/glen/tablepress-pods
|
|
Description: Custom Extension for TablePress to incorporate Pods information in tables
|
|
Version: 0.2.8
|
|
Author: Glen Whitney
|
|
Author URI: http://studioinfinity.org/
|
|
*/
|
|
|
|
/* Copyright (C) 2018-2019 Glen Whitney
|
|
|
|
This program is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
Foundation; either version 2 of the License, or (at your option) any later
|
|
version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
|
Street, Fifth Floor, Boston, MA 02110-1301 , USA.
|
|
|
|
*/
|
|
|
|
/*
|
|
* Usage and possible parameters:
|
|
* [table id=1 pod_name="mypod" pod_where="t.myfield = 'important'" /]
|
|
*
|
|
* Each row of the table which contains a Pods "magic tag" anywhere is expanded
|
|
* into one row for each of the pod records returned by
|
|
* pods(<pod_name>)->find(<pod_where>), with all of the magic tags in the row
|
|
* expanded for the corresponding record.
|
|
*
|
|
* The expansion can be controlled by the following "pseudo-shortcodes" which
|
|
* must occur at the beginning of the first column of the row (you may want to
|
|
* dedicate a hidden column just for this purpose if you are making use of these)
|
|
* [once] -- this row expands only into a single row (corresponding to the
|
|
* first record returned by the find() call), with magic
|
|
* tags expanded
|
|
* [literal] -- do not expand this row, except for removing the [literal]
|
|
* designation, even though it contains magic tags; hence, the
|
|
* magic tags will appear in the result.
|
|
*
|
|
* [table id=1 pod_name="mypod" pod_dump=true pod_where="t.myfield = 3" /]
|
|
*
|
|
* *Ignores* the contents of the table altogether, and replaces it with a
|
|
* simple dump of the ID, date, title, author, permalink, and all custom
|
|
* Pods fields for each record in a Pods custom post type. Note that the
|
|
* taxonomies, if any, of the post type will not be shown. Useful mainly for
|
|
* seeing what is present in your Pod; for any presentation tables you will
|
|
* most likely want to use the first form.
|
|
*
|
|
*/
|
|
|
|
add_filter( 'tablepress_shortcode_table_default_shortcode_atts',
|
|
'playground_add_shortcode_parameter_pods' );
|
|
add_filter( 'tablepress_table_raw_render_data', 'playground_expand_pod', 10, 2 );
|
|
add_filter( 'tablepress_admin_view_actions', 'playground_add_export_pod_action');
|
|
add_filter( 'tablepress_load_file_full_path', 'playground_exportpods_path', 10, 3);
|
|
add_filter( 'tablepress_view_data', 'playground_exportpods_data', 10, 2);
|
|
add_action( 'admin_post_tablepress_exportpods', 'playground_handle_exportpods');
|
|
|
|
function playground_add_shortcode_parameter_pods( $default_atts ) {
|
|
$default_atts['pod_name'] = '';
|
|
$default_atts['pod_dump'] = '';
|
|
$default_atts['pod_where'] = '';
|
|
return $default_atts;
|
|
}
|
|
|
|
function playground_add_export_pod_action( $view_actions ) {
|
|
$view_actions['exportpods'] = array(
|
|
'show_entry' => true,
|
|
'page_title' => __( 'Export Pods Table', 'tablepress' ),
|
|
'admin_menu_title' => __( 'Export Pods Table', 'tablepress' ),
|
|
'nav_tab_title' => _x( 'Export Pods', 'navigation bar', 'tablepress' ),
|
|
'required_cap' => 'tablepress_export_tables',
|
|
);
|
|
return $view_actions;
|
|
}
|
|
|
|
function playground_exportpods_path( $fullpath, $filename, $directory ) {
|
|
if ($filename !== 'view-exportpods.php') return $fullpath;
|
|
return plugin_dir_path( __FILE__ ) . $filename;
|
|
}
|
|
|
|
function playground_exportpods_data( $data, $act ) {
|
|
if ($act !== 'exportpods') return $data;
|
|
// Load all table IDs without priming the post meta cache, as table options/visibility are not needed.
|
|
$data['table_ids'] = TablePress::$model_table->load_all( false );
|
|
$data['tables_count'] = TablePress::$model_table->count_tables();
|
|
if ( ! empty( $_GET['table_id'] ) ) {
|
|
$data['export_ids'] = explode( ',', $_GET['table_id'] );
|
|
} else {
|
|
// Just show empty export form.
|
|
$data['export_ids'] = array();
|
|
}
|
|
$exporter = TablePress::load_class( 'TablePress_Export', 'class-export.php', 'classes' );
|
|
$data['zip_support_available'] = $exporter->zip_support_available;
|
|
$data['export_formats'] = $exporter->export_formats;
|
|
$data['csv_delimiters'] = $exporter->csv_delimiters;
|
|
$data['export_format'] = ( ! empty( $_GET['export_format'] ) ) ? $_GET['export_format'] : false;
|
|
$data['csv_delimiter'] = ( ! empty( $_GET['csv_delimiter'] ) ) ? $_GET['csv_delimiter'] : _x( ',', 'Default CSV delimiter in the translated language (";", ",", or "tab")', 'tablepress' );
|
|
return $data;
|
|
}
|
|
|
|
function playground_expand_pod( $table, $render_options) {
|
|
if (empty($render_options['pod_name'])) return $table;
|
|
$pod_params = array('limit'=>-1);
|
|
if (!empty($render_options['pod_where'])) {
|
|
$pod_params['where'] = $render_options['pod_where'];
|
|
}
|
|
$pod = pods($render_options['pod_name'], $pod_params);
|
|
$ndata = array();
|
|
$rvis = array();
|
|
$cvis = array();
|
|
if (empty($render_options['pod_dump'])) {
|
|
# Standard case: expand rows with magic tags into multiple rows,
|
|
# one for each record in $pod, controlled by the pseudo-shortcodes
|
|
$cvis = $table['visibility']['columns'];
|
|
$orig_rvis = $table['visibility']['rows'];
|
|
foreach ($table['data'] as $row_idx => $row) {
|
|
# First, check for the [literal] code since nothing much to do then
|
|
if (0 === strpos($row[0], '[literal]')) {
|
|
$row[0] = substr($row[0], 9);
|
|
$ndata[] = $row;
|
|
$rvis[] = $orig_rvis[$row_idx];
|
|
continue;
|
|
}
|
|
# Similarly, if no magic tags, just copy the row.
|
|
$wholerow = implode('',$row);
|
|
if (!preg_match('/{@.*}/', $wholerow)) {
|
|
$ndata[] = $row;
|
|
$rvis[] = $orig_rvis[$row_idx];
|
|
continue;
|
|
}
|
|
# OK, we need to expand magic tags in the row. First check for
|
|
# the [once] pseudo-shortcode:
|
|
$one_timer = FALSE;
|
|
if (0 === strpos($row[0], '[once]')) {
|
|
$row[0] = substr($row[0], 6);
|
|
$one_timer = TRUE;
|
|
}
|
|
# Here's the expansion loop
|
|
$pod->reset();
|
|
while ($pod->fetch()) {
|
|
$ndata[] = array_map(function($c) use($pod) {
|
|
return $pod->do_magic_tags($c);
|
|
}, $row);
|
|
$rvis[] = $orig_rvis[$row_idx];
|
|
if ($one_timer) { break; }
|
|
}
|
|
} # for each row of the original table
|
|
} else { # pod_dump is specified.
|
|
$flds = $pod->fields();
|
|
$hrow = array('ID','Date','Title','Author','Permalink');
|
|
$cvis = array(TRUE, TRUE, TRUE, TRUE, TRUE);
|
|
$frow = array();
|
|
foreach ($flds as $fkey => $finfo) {
|
|
$hrow[] = $finfo['label'];
|
|
$cvis[] = TRUE;
|
|
$frow[] = $fkey;
|
|
}
|
|
$ndata[] = $hrow;
|
|
$rvis = array(TRUE);
|
|
while ($pod->fetch()) {
|
|
$nrow = array();
|
|
$nrow[] = $pod->field('id');
|
|
$nrow[] = $pod->field('post_date');
|
|
$nrow[] = $pod->field('title');
|
|
$nrow[] = get_the_author_meta('display_name', $pod->field('author'));
|
|
$nrow[] = $pod->field('permalink');
|
|
foreach ($frow as $field_slug) {
|
|
$nrow[] = $pod->display($field_slug);
|
|
}
|
|
$ndata[] = $nrow;
|
|
$rvis[] = TRUE;
|
|
}
|
|
} # do a pod dump
|
|
# OK, install the new table information
|
|
$table['data'] = $ndata;
|
|
$table['visibility']['rows'] = $rvis;
|
|
$table['visibility']['columns'] = $cvis;
|
|
return $table;
|
|
}
|
|
|
|
function playground_handle_exportpods () {
|
|
TablePress::check_nonce( 'export' );
|
|
|
|
if ( ! current_user_can( 'tablepress_export_tables' ) ) {
|
|
wp_die( __( 'Sorry, you are not allowed to access this page.', 'default' ), 403 );
|
|
}
|
|
|
|
if ( empty( $_POST['export'] ) || ! is_array( $_POST['export'] ) ) {
|
|
TablePress::redirect( array( 'action' => 'export', 'message' => 'error_export' ) );
|
|
} else {
|
|
$export = wp_unslash( $_POST['export'] );
|
|
}
|
|
|
|
$exporter = TablePress::load_class( 'TablePress_Export', 'class-export.php', 'classes' );
|
|
|
|
if ( empty( $export['tables'] ) ) {
|
|
TablePress::redirect( array( 'action' => 'export', 'message' => 'error_export' ) );
|
|
}
|
|
if ( empty( $export['format'] ) || ! isset( $exporter->export_formats[ $export['format'] ] ) ) {
|
|
TablePress::redirect( array( 'action' => 'export', 'message' => 'error_export' ) );
|
|
}
|
|
if ( empty( $export['csv_delimiter'] ) ) {
|
|
// Set a value, so that the variable exists.
|
|
$export['csv_delimiter'] = '';
|
|
}
|
|
if ( 'csv' === $export['format'] && ! isset( $exporter->csv_delimiters[ $export['csv_delimiter'] ] ) ) {
|
|
TablePress::redirect( array( 'action' => 'export', 'message' => 'error_export' ) );
|
|
}
|
|
|
|
// Use list of tables from concatenated field if available (as that's hopefully not truncated by Suhosin, which is possible for $export['tables']).
|
|
$tables = ( ! empty( $export['tables_list'] ) ) ? explode( ',', $export['tables_list'] ) : $export['tables'];
|
|
|
|
// Determine if ZIP file support is available.
|
|
if ( $exporter->zip_support_available
|
|
&& ( ( isset( $export['zip_file'] ) && 'true' === $export['zip_file'] ) || count( $tables ) > 1 ) ) {
|
|
// Export to ZIP only if ZIP is desired or if more than one table were selected (mandatory then).
|
|
$export_to_zip = true;
|
|
} else {
|
|
$export_to_zip = false;
|
|
}
|
|
|
|
if ( ! $export_to_zip ) {
|
|
// This is only possible for one table, so take the first one.
|
|
if ( ! current_user_can( 'tablepress_export_table', $tables[0] ) ) {
|
|
wp_die( __( 'Sorry, you are not allowed to access this page.', 'default' ), 403 );
|
|
}
|
|
// Load table, with table data, options, and visibility settings.
|
|
$table = TablePress::$model_table->load( $tables[0], true, true );
|
|
if ( is_wp_error( $table ) ) {
|
|
TablePress::redirect( array( 'action' => 'export', 'message' => 'error_load_table', 'export_format' => $export['format'], 'csv_delimiter' => $export['csv_delimiter'] ) );
|
|
}
|
|
if ( isset( $table['is_corrupted'] ) && $table['is_corrupted'] ) {
|
|
TablePress::redirect( array( 'action' => 'export', 'message' => 'error_table_corrupted', 'export_format' => $export['format'], 'csv_delimiter' => $export['csv_delimiter'] ) );
|
|
}
|
|
$download_filename = sprintf( '%1$s-%2$s-%3$s.%4$s', $table['id'], $table['name'], date( 'Y-m-d' ), $export['format'] );
|
|
$download_filename = sanitize_file_name( $download_filename );
|
|
// Export the table.
|
|
$export_data = $exporter->export_table( $table, $export['format'], $export['csv_delimiter'] );
|
|
/**
|
|
* Filter the exported table data.
|
|
*
|
|
* @since 1.6.0
|
|
*
|
|
* @param string $export_data The exported table data.
|
|
* @param array $table Table to be exported.
|
|
* @param string $export_format Format for the export ('csv', 'html', 'json').
|
|
* @param string $csv_delimiter Delimiter for CSV export.
|
|
*/
|
|
$export_data = apply_filters( 'tablepress_export_data', $export_data, $table, $export['format'], $export['csv_delimiter'] );
|
|
$download_data = $export_data;
|
|
} else {
|
|
// Zipping can use a lot of memory and execution time, but not this much hopefully.
|
|
/** This filter is documented in the WordPress file wp-admin/admin.php */
|
|
@ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
|
|
@set_time_limit( 300 );
|
|
|
|
$zip_file = new ZipArchive();
|
|
$download_filename = sprintf( 'tablepress-export-%1$s-%2$s.zip', date_i18n( 'Y-m-d-H-i-s' ), $export['format'] );
|
|
$download_filename = sanitize_file_name( $download_filename );
|
|
$full_filename = wp_tempnam( $download_filename );
|
|
if ( true !== $zip_file->open( $full_filename, ZIPARCHIVE::OVERWRITE ) ) {
|
|
@unlink( $full_filename );
|
|
TablePress::redirect( array( 'action' => 'export', 'message' => 'error_create_zip_file', 'export_format' => $export['format'], 'csv_delimiter' => $export['csv_delimiter'] ) );
|
|
}
|
|
|
|
foreach ( $tables as $table_id ) {
|
|
// Don't export tables for which the user doesn't have the necessary export rights.
|
|
if ( ! current_user_can( 'tablepress_export_table', $table_id ) ) {
|
|
continue;
|
|
}
|
|
// Load table, with table data, options, and visibility settings.
|
|
$table = TablePress::$model_table->load( $table_id, true, true );
|
|
// Don't export if the table could not be loaded.
|
|
if ( is_wp_error( $table ) ) {
|
|
continue;
|
|
}
|
|
// Don't export if the table is corrupted.
|
|
if ( isset( $table['is_corrupted'] ) && $table['is_corrupted'] ) {
|
|
continue;
|
|
}
|
|
$export_data = $exporter->export_table( $table, $export['format'], $export['csv_delimiter'] );
|
|
/** This filter is documented in controllers/controller-admin.php */
|
|
$export_data = apply_filters( 'tablepress_export_data', $export_data, $table, $export['format'], $export['csv_delimiter'] );
|
|
$export_filename = sprintf( '%1$s-%2$s-%3$s.%4$s', $table['id'], $table['name'], date( 'Y-m-d' ), $export['format'] );
|
|
$export_filename = sanitize_file_name( $export_filename );
|
|
$zip_file->addFromString( $export_filename, $export_data );
|
|
}
|
|
|
|
// If something went wrong, or no files were added to the ZIP file, bail out.
|
|
if ( ! ZIPARCHIVE::ER_OK === $zip_file->status || 0 === $zip_file->numFiles ) {
|
|
$zip_file->close();
|
|
@unlink( $full_filename );
|
|
TablePress::redirect( array( 'action' => 'export', 'message' => 'error_create_zip_file', 'export_format' => $export['format'], 'csv_delimiter' => $export['csv_delimiter'] ) );
|
|
}
|
|
$zip_file->close();
|
|
|
|
// Load contents of the ZIP file, to send it as a download.
|
|
$download_data = file_get_contents( $full_filename );
|
|
@unlink( $full_filename );
|
|
}
|
|
|
|
// Send download headers for export file.
|
|
header( 'Content-Description: File Transfer' );
|
|
header( 'Content-Type: application/octet-stream' );
|
|
header( "Content-Disposition: attachment; filename=\"{$download_filename}\"" );
|
|
header( 'Content-Transfer-Encoding: binary' );
|
|
header( 'Expires: 0' );
|
|
header( 'Cache-Control: must-revalidate' );
|
|
header( 'Pragma: public' );
|
|
header( 'Content-Length: ' . strlen( $download_data ) );
|
|
// $filetype = text/csv, text/html, application/json
|
|
// header( 'Content-Type: ' . $filetype. '; charset=' . get_option( 'blog_charset' ) );
|
|
@ob_end_clean();
|
|
flush();
|
|
echo $download_data;
|
|
exit;
|
|
}
|