/** * Init the Table model by instantiating a Post model and loading the list of tables option. * * @since 1.0.0 */ public function __construct() { parent::__construct(); $this->model_post = TablePress::load_model('post'); $params = array('option_name' => 'tablepress_tables', 'default_value' => $this->default_tables); $this->tables = TablePress::load_class('TablePress_WP_Option', 'class-wp_option.php', 'classes', $params); }
/** * Init Options Model by creating the object instances for the Plugin and User Options. * * @since 1.0.0 */ public function __construct() { parent::__construct(); $params = array('option_name' => 'tablepress_plugin_options', 'default_value' => $this->default_plugin_options); $this->plugin_options = TablePress::load_class('TablePress_WP_Option', 'class-wp_option.php', 'classes', $params); $params = array('option_name' => 'tablepress_user_options', 'default_value' => $this->default_user_options); $this->user_options = TablePress::load_class('TablePress_WP_User_Option', 'class-wp_user_option.php', 'classes', $params); // Filter to map Meta capabilities to Primitive Capabilities. add_filter('map_meta_cap', array($this, 'map_tablepress_meta_caps'), 10, 4); }
/** * Set up the view with data and do things that are specific for this view. * * @param string $action Action for this view. * @param array $data Data for this view. */ public function setup($action, array $data) { $params = array('option_name' => 'tablepress_stockflock_config', 'default_value' => array()); $this->stockflock_config = TablePress::load_class('TablePress_WP_Option', 'class-wp_option.php', 'classes', $params); parent::setup($action, $data); $this->add_header_message('<span>' . __('Please contact stockflock if you get any issue with this plugin.', 'tablepress') . '</span>', 'notice-info'); $this->process_action_messages(array('success_save' => __('Stockflock Changes saved successfully.', 'tablepress'), 'error_save' => __('Error: Stockflock Changes could not be saved.', 'tablepress'))); $this->add_meta_box('stockflock-options', __('Stockflock Options', 'tablepress'), array($this, 'stockflock_plugin_options'), 'normal'); $this->add_text_box('submit', array($this, 'textbox_submit_button'), 'submit'); }
/** * Initialize all controllers, by loading Plugin and User Options, and performing an update check * * @since 1.0.0 */ public function __construct() { $this->model_options = TablePress::load_model('options'); $this->model_table = TablePress::load_model('table'); // update check, in all controllers (frontend and admin), to make sure we always have up-to-date options $this->plugin_update_check(); // should be done very early // Admin Page Menu entry, needed for construction of plugin URLs $this->parent_page = apply_filters('tablepress_admin_menu_parent_page', $this->model_options->get('admin_menu_parent_page')); $this->is_top_level_page = in_array($this->parent_page, array('top', 'middle', 'bottom'), true); }
/** * Print the content of the "No tables found" post meta box * * @since 1.0.0 */ public function postbox_no_tables($data, $box) { $add_url = TablePress::url(array('action' => 'add')); $import_url = TablePress::url(array('action' => 'import')); ?> <p><?php _e('No tables found.', 'tablepress'); ?> </p> <p><?php printf(__('You should <a href="%s">add</a> or <a href="%s">import</a> a table to get started!', 'tablepress'), $add_url, $import_url); ?> </p> <?php }
/** * Minify a string of CSS code, that should have been sanitized/tidied before * * @since 1.1.0 * * @uses CSSTidy * * @param string $css CSS code * @return string Minified CSS code */ function minify_css($css) { $csstidy = TablePress::load_class('csstidy', 'class.csstidy.php', 'libraries/csstidy'); $csstidy->optimise = new csstidy_custom_sanitize($csstidy); $csstidy->set_cfg('remove_bslash', false); $csstidy->set_cfg('compress_colors', true); $csstidy->set_cfg('compress_font-weight', true); $csstidy->set_cfg('lowercase_s', false); $csstidy->set_cfg('optimise_shorthands', 1); $csstidy->set_cfg('remove_last_;', true); $csstidy->set_cfg('case_properties', false); $csstidy->set_cfg('sort_properties', false); $csstidy->set_cfg('sort_selectors', false); $csstidy->set_cfg('discard_invalid_selectors', false); $csstidy->set_cfg('discard_invalid_properties', true); $csstidy->set_cfg('merge_selectors', false); $csstidy->set_cfg('css_level', 'CSS3.0'); $csstidy->set_cfg('preserve_css', false); $csstidy->set_cfg('timestamp', false); $csstidy->set_cfg('template', 'highest'); $csstidy->parse($css); return $csstidy->print->plain(); }
/** * Render the navigation menu with links to the possible actions, highlighting the current one. * * @since 1.0.0 */ protected function print_nav_tab_menu() { ?> <h1 id="tablepress-nav" class="nav-tab-wrapper"> <?php echo '<span class="plugin-name">' . __('TablePress', 'tablepress') . '</span><span class="separator"></span>'; foreach ($this->data['view_actions'] as $action => $entry) { // Special case: Add a separator before the group that starts with "Plugin Options", for some spacing. if ('options' === $action) { echo '<span class="separator"></span><span class="separator"></span>'; } if ('' === $entry['nav_tab_title']) { continue; } if (!current_user_can($entry['required_cap'])) { continue; } $url = esc_url(TablePress::url(array('action' => $action))); $active = $action === $this->action ? ' nav-tab-active' : ''; echo "<a class=\"nav-tab{$active}\" href=\"{$url}\">{$entry['nav_tab_title']}</a>"; } ?> </h1> <?php }
/** * Return the live preview data of table that has non-saved changes. * * @since 1.0.0 */ public function ajax_action_preview_table() { if (empty($_POST['tablepress']) || empty($_POST['tablepress']['id'])) { wp_die('-1'); } else { $preview_table = wp_unslash($_POST['tablepress']); } // Check if the submitted nonce matches the generated nonce we created earlier, dies -1 on failure. TablePress::check_nonce('preview_table', $preview_table['id'], '_ajax_nonce', true); // Ignore the request if the current user doesn't have sufficient permissions. if (!current_user_can('tablepress_preview_table', $preview_table['id'])) { wp_die('-1'); } // Default response data. $success = false; do { // to be able to "break;" (allows for better readable code) // Load table, without table data, but with options and visibility settings. $existing_table = TablePress::$model_table->load($preview_table['id'], false, true); if (is_wp_error($existing_table)) { // maybe somehow load a new table here? (TablePress::$model_table->get_table_template())? break; } // Check and convert data that was transmitted as JSON. if (empty($preview_table['data']) || empty($preview_table['options']) || empty($preview_table['visibility'])) { break; } $preview_table['data'] = (array) json_decode($preview_table['data'], true); $preview_table['options'] = (array) json_decode($preview_table['options'], true); $preview_table['visibility'] = (array) json_decode($preview_table['visibility'], true); // Check consistency of new table, and then merge with existing table. $table = TablePress::$model_table->prepare_table($existing_table, $preview_table, true, true); if (is_wp_error($table)) { break; } // DataTables Custom Commands can only be edit by trusted users. if (!current_user_can('unfiltered_html')) { $table['options']['datatables_custom_commands'] = $existing_table['options']['datatables_custom_commands']; } // If the ID has changed, and the new ID is valid, render with the new ID (important e.g. for CSS classes/HTML ID). if ($table['id'] !== $table['new_id'] && 0 === preg_match('/[^a-zA-Z0-9_-]/', $table['new_id'])) { $table['id'] = $table['new_id']; } // Sanitize all table data to remove unsafe HTML from the preview output. $table = TablePress::$model_table->sanitize($table); // At this point, the table data is valid and sanitized and can be rendered. $success = true; } while (false); // Do-while-loop through this exactly once, to be able to "break;" early. // Initialize i18n support, load plugin's textdomain, to retrieve correct translations for the description of the preview. load_plugin_textdomain('tablepress', false, dirname(TABLEPRESS_BASENAME) . '/i18n'); if ($success) { // Create a render class instance. $_render = TablePress::load_class('TablePress_Render', 'class-render.php', 'classes'); // Merge desired options with default render options (see TablePress_Controller_Frontend::shortcode_table()). $default_render_options = $_render->get_default_render_options(); /** This filter is documented in controllers/controller-frontend.php */ $default_render_options = apply_filters('tablepress_shortcode_table_default_shortcode_atts', $default_render_options); $render_options = shortcode_atts($default_render_options, $table['options']); /** This filter is documented in controllers/controller-frontend.php */ $render_options = apply_filters('tablepress_shortcode_table_shortcode_atts', $render_options); $_render->set_input($table, $render_options); $head_html = $_render->get_preview_css(); $custom_css = TablePress::$model_options->get('custom_css'); if (!empty($custom_css)) { $head_html .= "<style type=\"text/css\">\n{$custom_css}\n</style>\n"; } $body_html = '<div id="tablepress-page"><p>' . __('This is a preview of your table.', 'tablepress') . ' ' . __('Because of CSS styling in your theme, the table might look different on your page!', 'tablepress') . ' ' . __('The features of the DataTables JavaScript library are also not available or visible in this preview!', 'tablepress') . '<br />' . sprintf(__('To insert the table into a page, post, or text widget, copy the Shortcode %s and paste it into the editor.', 'tablepress'), '<input type="text" class="table-shortcode table-shortcode-inline" value="' . esc_attr('[' . TablePress::$shortcode . " id={$table['id']} /]") . '" readonly="readonly" />') . '</p>' . $_render->get_output() . '</div>'; } else { $head_html = ''; $body_html = __('The preview could not be loaded.', 'tablepress'); } // Generate the response. $response = array('success' => $success, 'head_html' => $head_html, 'body_html' => $body_html); // Buffer all outputs, to prevent errors/warnings being printed that make the JSON invalid. $output_buffer = ob_get_clean(); if (!empty($output_buffer)) { $response['output_buffer'] = $output_buffer; } // Send the response. wp_send_json($response); }
/** * Handle Shortcode [table-info id=<ID> field=<name> /] in the_content() * * @since 1.0.0 * * @param array $atts list of attributes that where included in the Shortcode * @return string Text that replaces the Shortcode (error message or asked-for information) */ public function shortcode_table_info($shortcode_atts) { // parse Shortcode attributes, only allow those that are specified $default_shortcode_atts = array('id' => 0, 'field' => '', 'format' => ''); $default_shortcode_atts = apply_filters('tablepress_shortcode_table_info_default_shortcode_atts', $default_shortcode_atts); $shortcode_atts = shortcode_atts($default_shortcode_atts, $shortcode_atts); $shortcode_atts = apply_filters('tablepress_shortcode_table_info_shortcode_atts', $shortcode_atts); // allow a filter to determine behavior of this function, by overwriting its behavior, just need to return something other than false $overwrite = apply_filters('tablepress_shortcode_table_info_overwrite', false, $shortcode_atts); if ($overwrite) { return $overwrite; } // check, if a table with the given ID exists $table_id = preg_replace('/[^a-zA-Z0-9_-]/', '', $shortcode_atts['id']); if (!$this->model_table->table_exists($table_id)) { $message = "[table “{$table_id}” not found /]<br />\n"; $message = apply_filters('tablepress_table_not_found_message', $message, $table_id); return $message; } // load the table $table = $this->model_table->load($table_id); if (false === $table) { $message = "[table “{$table_id}” could not be loaded /]<br />\n"; $message = apply_filters('tablepress_table_load_error_message', $message, $table_id); return $message; } $field = preg_replace('/[^a-z_]/', '', strtolower($shortcode_atts['field'])); $format = 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': $output = $table['last_modified']; break 2; case 'mysql': $output = TablePress::format_datetime($table['last_modified'], 'mysql', ' '); break 2; case 'human': $modified_timestamp = strtotime($table['last_modified']); $current_timestamp = current_time('timestamp'); $time_diff = $current_timestamp - $modified_timestamp; if ($time_diff >= 0 && $time_diff < DAY_IN_SECONDS) { // time difference is only shown up to one day $output = sprintf(__('%s ago', 'tablepress'), human_time_diff($modified_timestamp, $current_timestamp)); } else { $output = TablePress::format_datetime($table['last_modified'], 'mysql', '<br />'); } break 2; default: $output = TablePress::format_datetime($table['last_modified'], 'mysql', ' '); } 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; default: $output = "[table-info field “{$field}” not found in table “{$table_id}” /]<br />\n"; $output = apply_filters('tablepress_table_info_not_found_message', $output, $table, $field, $format); } $output = apply_filters('tablepress_shortcode_table_info_output', $output, $table, $shortcode_atts); return $output; }
/** * Test that the screen URLs for toplevel admin menu entries are correct. * * @since 1.1.0 */ public function test_url_toplevel() { TablePress::$controller->is_top_level_page = true; TablePress::$controller->parent_page = 'middle'; $this->assertSame('http://example.org/wp-admin/admin.php?page=tablepress', TablePress::url()); $this->assertSame('http://example.org/wp-admin/admin.php?page=tablepress', TablePress::url(array(), false)); }
/** * Save changes on the Stockflock screen. * */ public function handle_post_action_stockflock() { if (!isset($_POST['stockflock'])) { return; } TablePress::check_nonce('stockflock'); if (!current_user_can('manage_options')) { wp_die(__('You do not have sufficient permissions to access this page.')); } if (empty($_POST['stockflock']) || !is_array($_POST['stockflock'])) { TablePress::redirect(array('action' => 'stockflock', 'message' => 'error_save')); } else { $stockflock = stripslashes_deep($_POST['stockflock']); } $params = array('option_name' => 'tablepress_stockflock_config', 'default_value' => array()); $stockflock_config = TablePress::load_class('TablePress_WP_Option', 'class-wp_option.php', 'classes', $params); //trim and restrict array length to be not more than 20 $raw_companies = explode(',', $stockflock['companies']); $valid_companies = array_slice(array_map('trim', $raw_companies), 0, $this->company_limit); $stockflock['companies'] = strtoupper(implode(',', $valid_companies)); //give default value to data_points $data_point_list = ['short_name', 'price_value', 'industry_name', 'dividend_yield', 'earning_value', 'dividend_per_share', 'book_value', 'debt_assets', 'net_asset_value', 'gearing_ratio', 'property_yield_ratio']; if (is_array($stockflock['data_points'])) { foreach ($data_point_list as $key => $value) { if (!array_key_exists($value, $stockflock['data_points'])) { $stockflock['data_points'][$value] = "false"; } } } //store to wp_options $stockflock_config->update($stockflock); TablePress::redirect(array('action' => 'stockflock', 'message' => 'success_save')); }
/** * Print a notification about a corrupted table * * @since 1.4.0 */ public function textbox_corrupted_table($data, $box) { ?> <div class="error"> <p><strong><?php _e('Attention: Unfortunately, an error occured.', 'tablepress'); ?> </strong></p> <p> <?php printf(__('The internal data of table “%1$s” (ID %2$s) is corrupted.', 'tablepress'), esc_html($data['table']['name']), esc_html($data['table']['id'])); echo ' '; printf(__('The following error was registered: <code>%s</code>.', 'tablepress'), esc_html($data['table']['json_error'])); ?> </p> <p> <?php _e('Because of this error, the table can not be edited at this time, to prevent possible further data loss.', 'tablepress'); echo ' '; printf(__('Please see the <a href="%s">TablePress FAQ page</a> for further instructions.', 'tablepress'), 'http://tablepress.org/faq/corrupted-tables/'); ?> </p> <p> <?php echo '<a href="' . TablePress::url(array('action' => 'list')) . '" class="button">' . __('Back to the List of Tables', 'tablepress') . '</a>'; ?> </p> </div> <?php }
/** * Handle Shortcode [table-info id=<ID> field=<name> /] in the_content() * * @since 1.0.0 * * @param array $shortcode_atts List of attributes that where included in the Shortcode * @return string Text that replaces the Shortcode (error message or asked-for information) */ public function shortcode_table_info($shortcode_atts) { // For empty Shortcodes like [table-info] or [table-info /], an empty string is passed, see Core #26927 $shortcode_atts = (array) $shortcode_atts; // parse Shortcode attributes, only allow those that are specified $default_shortcode_atts = array('id' => '', 'field' => '', 'format' => ''); /** * Filter 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. /** * Filter 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); /** * Filter whether the output of the [table-info] Shortcode is overwritten/short-circuited. * * @since 1.0.0 * * @param bool|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 ($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 /]<br />\n"; /** This filter is documented in controllers/controller-frontend.php */ $message = apply_filters('tablepress_table_not_found_message', $message, $table_id); return $message; } // load the table $table = TablePress::$model_table->load($table_id, true, true); // Load table, with table data, options, and visibility settings if (is_wp_error($table)) { $message = "[table “{$table_id}” could not be loaded /]<br />\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 = preg_replace('/[^a-z_]/', '', strtolower($shortcode_atts['field'])); $format = 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': $output = $table['last_modified']; break 2; case 'human': $modified_timestamp = strtotime($table['last_modified']); $current_timestamp = current_time('timestamp'); $time_diff = $current_timestamp - $modified_timestamp; if ($time_diff >= 0 && $time_diff < DAY_IN_SECONDS) { // time difference is only shown up to one day $output = sprintf(__('%s ago', 'tablepress'), human_time_diff($modified_timestamp, $current_timestamp)); } else { $output = TablePress::format_datetime($table['last_modified'], 'mysql', '<br />'); } break 2; case 'mysql': default: $output = TablePress::format_datetime($table['last_modified'], 'mysql', ' '); break 2; } 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 = $output - 1; } if ($table['options']['table_foot']) { $output = $output - 1; } } break; case 'number_columns': $output = count($table['data'][0]); break; default: $output = "[table-info field “{$field}” not found in table “{$table_id}” /]<br />\n"; /** * Filter 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 ID. * @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); } /** * Filter 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; }
function load_tablepress_in_the_admin() { if (is_admin() && defined('DOING_AJAX') && DOING_AJAX) { TablePress::load_controller('frontend'); // работает на дефолтной теме // TablePress::$controller = TablePress::load_controller( 'admin_ajax' ); } }
/** * Save "Custom CSS" to a file, or return HTML for the credentials form * * @since 1.0.0 * * @return string (if necessary) HTML for the credentials form for the WP_Filesystem API */ public function save_custom_css_to_file() { // Set current screen to get Screen Icon to have a custom HTML ID, so that we can hide it with CSS set_current_screen('tablepress_options_invisible'); // Start capturing the output, to get HTML of the credentials form (if needed) ob_start(); $url = ''; // same page $credentials = request_filesystem_credentials($url, '', false, false, null); // do we have credentials already? (Otherwise the form will have been rendered already.) if (false === $credentials) { $form_data = ob_get_contents(); ob_end_clean(); $form_data = str_replace('name="upgrade" id="upgrade" class="button"', 'name="upgrade" id="upgrade" class="button button-primary button-large"', $form_data); return $form_data; } // we have received credentials, but don't know if they are valid yet if (!WP_Filesystem($credentials)) { // credentials failed, so ask again (with $error flag true) request_filesystem_credentials($url, '', true, false, null); $form_data = ob_get_contents(); ob_end_clean(); $form_data = str_replace('name="upgrade" id="upgrade" class="button"', 'name="upgrade" id="upgrade" class="button button-primary button-large"', $form_data); return $form_data; } // we have valid access to the filesystem now -> try to save the file $filename = WP_CONTENT_DIR . '/tablepress-custom.css'; $filename = apply_filters('tablepress_custom_css_file_name', $filename); $filename_min = WP_CONTENT_DIR . '/tablepress-custom.min.css'; $filename_min = apply_filters('tablepress_custom_css_minified_file_name', $filename_min); // Check if file name is valid (0 means yes) if (0 !== validate_file($filename) || 0 !== validate_file($filename_min)) { TablePress::redirect(array('action' => 'options', 'message' => 'success_save_error_custom_css')); } global $wp_filesystem; // WP_CONTENT_DIR and (FTP-)Content-Dir can be different (e.g. if FTP working dir is /) // We need to account for that by replacing the path difference in the filename $path_difference = str_replace($wp_filesystem->wp_content_dir(), '', trailingslashit(WP_CONTENT_DIR)); if ('' != $path_difference) { $filename = str_replace($path_difference, '', $filename); $filename_min = str_replace($path_difference, '', $filename_min); } $custom_css = $this->get('custom_css'); $custom_css_minified = $this->get('custom_css_minified'); $result = $wp_filesystem->put_contents($filename, $custom_css, FS_CHMOD_FILE); $result_min = $wp_filesystem->put_contents($filename_min, $custom_css_minified, FS_CHMOD_FILE); if (!$result || !$result_min) { TablePress::redirect(array('action' => 'options', 'message' => 'success_save_error_custom_css')); } // at this point, saving was successful, so enable the checkbox again // (if it was not enabled before, we would never have tried to save) // and also increase the "Custom CSS" version number (for cache busting) $this->update(array('use_custom_css_file' => true, 'custom_css_version' => $this->get('custom_css_version') + 1)); TablePress::redirect(array('action' => 'options', 'message' => 'success_save')); }
/** * Callback to determine whether the given $item contains the search term. * * @since 1.0.0 * * @param string $item Table ID that shall be searched. * @return bool Whether the search term was found or not. */ protected function _search_callback($item) { static $term, $json_encoded_term; if (is_null($term) || is_null($json_encoded_term)) { $term = wp_unslash($_GET['s']); $json_encoded_term = substr(json_encode($term), 1, -1); } // Load table again, with table data, but without options and visibility settings. $item = TablePress::$model_table->load($item, true, false); if (isset($item['is_corrupted']) && $item['is_corrupted']) { return false; // Don't search corrupted tables } // Search from easy to hard, so that "expensive" code maybe doesn't have to run. if (false !== stripos($item['id'], $term) || false !== stripos($item['name'], $term) || false !== stripos($item['description'], $term) || false !== stripos(TablePress::get_user_display_name($item['author']), $term) || false !== stripos(TablePress::format_datetime($item['last_modified'], 'mysql', ' '), $term) || false !== stripos(json_encode($item['data']), $json_encoded_term)) { return true; } return false; }
/** * Print the content of the "Admin Options" post meta box. * * @since 1.0.0 * * @param array $data Data for this screen. * @param array $box Information about the text box. */ public function textbox_uninstall_tablepress(array $data, array $box) { ?> <h1 style="margin-top:40px;"><?php _e('Uninstall TablePress', 'tablepress'); ?> </h1> <p><?php echo __('Uninstalling <strong>will permanently delete</strong> all TablePress tables and options from the database.', 'tablepress') . '<br />' . __('It is recommended that you create a backup of the tables (by exporting the tables in the JSON format), in case you later change your mind.', 'tablepress') . '<br />' . __('You will manually need to remove the plugin’s files from the plugin folder afterwards.', 'tablepress') . '<br />' . __('Be very careful with this and only click the button if you know what you are doing!', 'tablepress'); ?> </p> <p><a href="<?php echo TablePress::url(array('action' => 'uninstall_tablepress'), true, 'admin-post.php'); ?> " id="uninstall-tablepress" class="button"><?php _e('Uninstall TablePress', 'tablepress'); ?> </a></p> <?php }
/** * Remove all cells from the data set that shall not be rendered, because they are hidden. * * @since 1.0.0 */ protected function _prepare_render_data() { $orig_table = $this->table; $num_rows = count($this->table['data']); $num_columns = $num_rows > 0 ? count($this->table['data'][0]) : 0; // Evaluate show/hide_rows/columns parameters. $actions = array('show', 'hide'); $elements = array('rows', 'columns'); foreach ($actions as $action) { foreach ($elements as $element) { if (empty($this->render_options["{$action}_{$element}"])) { $this->render_options["{$action}_{$element}"] = array(); continue; } // Add all rows/columns to array if "all" value set for one of the four parameters. if ('all' === $this->render_options["{$action}_{$element}"]) { $this->render_options["{$action}_{$element}"] = range(0, ${'num_' . $element} - 1); continue; } // We have a list of rows/columns (possibly with ranges in it). $this->render_options["{$action}_{$element}"] = explode(',', $this->render_options["{$action}_{$element}"]); // Support for ranges like 3-6 or A-BA. $range_cells = array(); foreach ($this->render_options["{$action}_{$element}"] as $key => $value) { $range_dash = strpos($value, '-'); if (false !== $range_dash) { unset($this->render_options["{$action}_{$element}"][$key]); $start = substr($value, 0, $range_dash); if (!is_numeric($start)) { $start = TablePress::letter_to_number($start); } $end = substr($value, $range_dash + 1); if (!is_numeric($end)) { $end = TablePress::letter_to_number($end); } $current_range = range($start, $end); $range_cells = array_merge($range_cells, $current_range); } } $this->render_options["{$action}_{$element}"] = array_merge($this->render_options["{$action}_{$element}"], $range_cells); /* * Parse single letters and change from regular numbering to zero-based numbering, * as rows/columns are indexed from 0 internally, but from 1 externally */ foreach ($this->render_options["{$action}_{$element}"] as $key => $value) { if (!is_numeric($value)) { $value = TablePress::letter_to_number($value); } $this->render_options["{$action}_{$element}"][$key] = (int) $value - 1; } // Remove duplicate entries and sort the array. $this->render_options["{$action}_{$element}"] = array_unique($this->render_options["{$action}_{$element}"]); sort($this->render_options["{$action}_{$element}"], SORT_NUMERIC); } } // Load information about hidden rows and columns. // Get indexes of hidden rows (array value of 0). $hidden_rows = array_keys($this->table['visibility']['rows'], 0); $hidden_rows = array_merge($hidden_rows, $this->render_options['hide_rows']); $hidden_rows = array_diff($hidden_rows, $this->render_options['show_rows']); // Get indexes of hidden columns (array value of 0). $hidden_columns = array_keys($this->table['visibility']['columns'], 0); $hidden_columns = array_merge($hidden_columns, $this->render_options['hide_columns']); $hidden_columns = array_merge(array_diff($hidden_columns, $this->render_options['show_columns'])); // Remove hidden rows and re-index. foreach ($hidden_rows as $row_idx) { unset($this->table['data'][$row_idx]); } $this->table['data'] = array_merge($this->table['data']); // Remove hidden columns and re-index. foreach ($this->table['data'] as $row_idx => $row) { foreach ($hidden_columns as $col_idx) { unset($row[$col_idx]); } $this->table['data'][$row_idx] = array_merge($row); } /** * Filter the table after processing the table visibility information. * * @since 1.0.0 * * @param array $table The processed table. * @param array $orig_table The unprocessed table. * @param array $render_options The render options for the table. */ $this->table = apply_filters('tablepress_table_render_data', $this->table, $orig_table, $this->render_options); }
/** * Show a list of tables in the Editor toolbar Thickbox (opened by TinyMCE or Quicktags button) * * @since 1.0.0 */ public function handle_get_action_editor_button_thickbox() { TablePress::check_nonce('editor_button_thickbox'); $this->init_i18n_support(); $view_data = array('tables' => $this->model_table->load_all()); set_current_screen('tablepress_editor_button_thickbox'); // Prepare, initialize, and render the view $this->view = TablePress::load_view('editor_button_thickbox', $view_data); $this->view->render(); }
/** * Callback to for the array sort function * * @since 1.0.0 * * @param array $item_a First item that shall be compared to... * @param array $item_b the second item * @return int (-1, 0, 1) depending on which item sorts "higher" */ protected function _order_callback($item_a, $item_b) { global $orderby, $order; if ('last_modified_by' != $orderby) { if ($item_a[$orderby] == $item_b[$orderby]) { return 0; } } else { if ($item_a['options']['last_editor'] == $item_b['options']['last_editor']) { return 0; } } // certain fields require some extra work before being sortable switch ($orderby) { case 'last_modified': // Compare UNIX timestamps for "last modified", which actually is a mySQL datetime string $result = strtotime($item_a['last_modified']) > strtotime($item_b['last_modified']) ? 1 : -1; break; case 'author': // Get the actual author name, plain value is just the user ID $result = strnatcasecmp(TablePress::get_user_display_name($item_a['author']), TablePress::get_user_display_name($item_b['author'])); break; case 'last_modified_by': // Get the actual last editor name, plain value is just the user ID $result = strnatcasecmp(TablePress::get_user_display_name($item_a['options']['last_editor']), TablePress::get_user_display_name($item_b['options']['last_editor'])); break; default: // other fields (ID, name, description) are sorted as strings $result = strnatcasecmp($item_a[$orderby], $item_b[$orderby]); } return 'asc' == $order ? $result : -$result; }
/** * Uninstall TablePress, and delete all tables and options. * * @since 1.0.0 */ public function handle_get_action_uninstall_tablepress() { TablePress::check_nonce('uninstall_tablepress'); $plugin = TABLEPRESS_BASENAME; if (!current_user_can('activate_plugins') || !current_user_can('tablepress_edit_options') || !current_user_can('tablepress_delete_tables') || is_plugin_active_for_network($plugin)) { wp_die(__('You do not have sufficient permissions to access this page.', 'default'), 403); } // Deactivate TablePress for the site (but not for the network). deactivate_plugins($plugin, false, false); update_option('recently_activated', array($plugin => time()) + (array) get_option('recently_activated', array())); // Delete all tables, "Custom CSS" files, and options. TablePress::$model_table->delete_all(); $tablepress_css = TablePress::load_class('TablePress_CSS', 'class-css.php', 'classes'); $css_files_deleted = $tablepress_css->delete_custom_css_files(); TablePress::$model_options->remove_access_capabilities(); TablePress::$model_table->destroy(); TablePress::$model_options->destroy(); $this->init_i18n_support(); $output = '<strong>' . __('TablePress was uninstalled successfully.', 'tablepress') . '</strong><br /><br />'; $output .= __('All tables, data, and options were deleted.', 'tablepress'); if (is_multisite()) { $output .= ' ' . __('You may now ask the network admin to delete the plugin’s folder <code>tablepress</code> from the server, if no other site in the network uses it.', 'tablepress'); } else { $output .= ' ' . __('You may now manually delete the plugin’s folder <code>tablepress</code> from the <code>plugins</code> directory on your server or use the “Delete” link for TablePress on the WordPress “Plugins” page.', 'tablepress'); } if ($css_files_deleted) { $output .= ' ' . __('Your TablePress “Custom CSS” files have been deleted automatically.', 'tablepress'); } else { if (is_multisite()) { $output .= ' ' . __('Please also ask him to delete your TablePress “Custom CSS” files from the server.', 'tablepress'); } else { $output .= ' ' . __('You may now also delete your TablePress “Custom CSS” files in the <code>wp-content</code> folder.', 'tablepress'); } } $output .= "</p>\n<p>"; if (!is_multisite() || is_super_admin()) { $output .= '<a class="button" href="' . esc_url(admin_url('plugins.php')) . '">' . __('Go to “Plugins” page', 'tablepress') . '</a> '; } $output .= '<a class="button" href="' . esc_url(admin_url('index.php')) . '">' . __('Go to Dashboard', 'tablepress') . '</a>'; wp_die($output, __('Uninstall TablePress', 'tablepress'), array('response' => 200, 'back_link' => false)); }
/** * Callback to determine whether the given $item contains the search term * * @since 1.0.0 * * @param array $item Item that shall be searched * @return bool Whether the search term was found or not */ protected function _search_callback($item) { static $term; if (is_null($term)) { $term = stripslashes($_GET['s']); } $item = TablePress::$controller->model_table->load($item['id']); // load table again, with data // search from easy to hard, so that "expensive" code maybe doesn't have to run if (false !== stripos($item['id'], $term) || false !== stripos($item['name'], $term) || false !== stripos($item['description'], $term) || false !== stripos(TablePress::get_user_display_name($item['author']), $term) || false !== stripos(TablePress::format_datetime($item['last_modified'], 'mysql', ' '), $term) || false !== stripos(json_encode($item['data']), $term)) { return true; } return false; }
/** * Generates the content tokens and puts them into the tokens array * * @param object $the_post the post object * @param array $tokens tokens array * * @return int keywords count */ private function tokenizeContent($the_post, &$tokens) { $args = $this->args; $content = $the_post->post_content; if ($args['extract_shortcodes']) { // WP Table Reloaded support if (defined('WP_TABLE_RELOADED_ABSPATH')) { include_once WP_TABLE_RELOADED_ABSPATH . 'controllers/controller-frontend.php'; $wpt_reloaded = new WP_Table_Reloaded_Controller_Frontend(); } // TablePress support if (defined('TABLEPRESS_ABSPATH')) { $tp_controller = TablePress::load_controller('frontend'); $tp_controller->init_shortcodes(); } // Remove user defined shortcodes $shortcodes = explode(',', $args['exclude_shortcodes']); foreach ($shortcodes as $shortcode) { remove_shortcode(trim($shortcode)); add_shortcode(trim($shortcode), array($this, 'return_empty_string')); } // Remove some shortcodes remove_shortcode('wpdreams_ajaxsearchpro'); add_shortcode('wpdreams_ajaxsearchpro', array($this, 'return_empty_string')); remove_shortcode('wpdreams_ajaxsearchpro_results'); add_shortcode('wpdreams_ajaxsearchpro_results', array($this, 'return_empty_string')); remove_shortcode('wpdreams_asp_settings'); add_shortcode('wpdreams_asp_settings', array($this, 'return_empty_string')); remove_shortcode('contact-form'); add_shortcode('contact-form', array($this, 'return_empty_string')); remove_shortcode('starrater'); add_shortcode('starrater', array($this, 'return_empty_string')); remove_shortcode('responsive-flipbook'); add_shortcode('responsive-flipbook', array($this, 'return_empty_string')); remove_shortcode('avatar_upload'); add_shortcode('avatar_upload', array($this, 'return_empty_string')); remove_shortcode('product_categories'); add_shortcode('product_categories', array($this, 'return_empty_string')); remove_shortcode('recent_products'); add_shortcode('recent_products', array($this, 'return_empty_string')); $content = do_shortcode($content); // WP 4.2 emoji strip if (function_exists('wp_encode_emoji')) { $content = wp_encode_emoji($content); } if (defined('TABLEPRESS_ABSPATH')) { unset($tp_controller); } if (defined('WP_TABLE_RELOADED_ABSPATH')) { unset($wpt_reloaded); } } // Strip the remaining shortcodes $content = strip_shortcodes($content); $content = preg_replace('/<[a-zA-Z\\/][^>]*>/', ' ', $content); $content = strip_tags($content); $filtered_content = apply_filters('asp_post_content_before_tokenize', $content); if ($filtered_content == "") { return 0; } $content_keywords = $this->tokenize($filtered_content); foreach ($content_keywords as $keyword) { $this->insertToken($tokens, $keyword[0], $keyword[1], 'content'); } return count($content_keywords); }
function relevanssi_index_doc($indexpost, $remove_first = false, $custom_fields = false, $bypassglobalpost = false) { global $wpdb, $post, $relevanssi_variables; $relevanssi_table = $relevanssi_variables['relevanssi_table']; $post_was_null = false; $previous_post = NULL; // Check if this is a Jetpack Contact Form entry if (isset($_REQUEST['contact-form-id'])) { return; } if ($bypassglobalpost) { // if $bypassglobalpost is set, relevanssi_index_doc() will index the post object or post // ID as specified in $indexpost isset($post) ? $previous_post = $post : ($post_was_null = true); is_object($indexpost) ? $post = $indexpost : ($post = get_post($indexpost)); } else { // Quick edit has an array in the global $post, so fetch the post ID for the post to edit. if (is_array($post)) { $post = get_post($post['ID']); } if (empty($post)) { // No $post set, so we need to use $indexpost, if it's a post object $post_was_null = true; if (is_object($indexpost)) { $post = $indexpost; } else { $post = get_post($indexpost); } } else { // $post was set, let's grab the previous value in case we need it $previous_post = $post; } } if ($post == NULL) { // At this point we should have something in $post; if not, quit. if ($post_was_null) { $post = null; } if ($previous_post) { $post = $previous_post; } return; } // Finally fetch the post again by ID. Complicated, yes, but unless we do this, we might end // up indexing the post before the updates come in. $post = get_post($post->ID); if (function_exists('relevanssi_hide_post')) { if (relevanssi_hide_post($post->ID)) { if ($post_was_null) { $post = null; } if ($previous_post) { $post = $previous_post; } return; } } $index_this_post = false; $post->indexing_content = true; $index_types = get_option('relevanssi_index_post_types'); if (!is_array($index_types)) { $index_types = array(); } if (in_array($post->post_type, $index_types)) { $index_this_post = true; } if (true == apply_filters('relevanssi_do_not_index', false, $post->ID)) { // filter says no $index_this_post = false; } if ($remove_first) { // we are updating a post, so remove the old stuff first relevanssi_remove_doc($post->ID, true); if (function_exists('relevanssi_remove_item')) { relevanssi_remove_item($post->ID, 'post'); } } // This needs to be here, after the call to relevanssi_remove_doc(), because otherwise // a post that's in the index but shouldn't be there won't get removed. if (!$index_this_post) { if ($post_was_null) { $post = null; } if ($previous_post) { $post = $previous_post; } return; } $n = 0; $post = apply_filters('relevanssi_post_to_index', $post); $min_word_length = get_option('relevanssi_min_word_length', 3); $insert_data = array(); //Added by OdditY - INDEX COMMENTS of the POST -> if ("none" != get_option("relevanssi_index_comments")) { $pcoms = relevanssi_get_comments($post->ID); if ($pcoms != "") { $pcoms = relevanssi_strip_invisibles($pcoms); $pcoms = preg_replace('/<[a-zA-Z\\/][^>]*>/', ' ', $pcoms); $pcoms = strip_tags($pcoms); $pcoms = relevanssi_tokenize($pcoms, true, $min_word_length); if (count($pcoms) > 0) { foreach ($pcoms as $pcom => $count) { $n++; $insert_data[$pcom]['comment'] = $count; } } } } //Added by OdditY END <- $taxonomies = get_option("relevanssi_index_taxonomies_list"); // Then process all taxonomies, if any. foreach ($taxonomies as $taxonomy) { $insert_data = relevanssi_index_taxonomy_terms($post, $taxonomy, $insert_data); } // index author if ("on" == get_option("relevanssi_index_author")) { $auth = $post->post_author; $display_name = $wpdb->get_var("SELECT display_name FROM {$wpdb->users} WHERE ID={$auth}"); $names = relevanssi_tokenize($display_name, false, $min_word_length); foreach ($names as $name => $count) { isset($insert_data[$name]['author']) ? $insert_data[$name]['author'] += $count : ($insert_data[$name]['author'] = $count); } } if ($custom_fields) { $remove_underscore_fields = false; if ($custom_fields == 'all') { $custom_fields = get_post_custom_keys($post->ID); } if ($custom_fields == 'visible') { $custom_fields = get_post_custom_keys($post->ID); $remove_underscore_fields = true; } $custom_fields = apply_filters('relevanssi_index_custom_fields', $custom_fields); if (is_array($custom_fields)) { foreach ($custom_fields as $field) { if ($remove_underscore_fields) { if (substr($field, 0, 1) == '_') { continue; } } $values = get_post_meta($post->ID, $field, false); if ("" == $values) { continue; } foreach ($values as $value) { $value_tokens = relevanssi_tokenize($value, true, $min_word_length); foreach ($value_tokens as $token => $count) { isset($insert_data[$token]['customfield']) ? $insert_data[$token]['customfield'] += $count : ($insert_data[$token]['customfield'] = $count); if (function_exists('relevanssi_customfield_detail')) { $insert_data = relevanssi_customfield_detail($insert_data, $token, $count, $field); } } } } } } if (isset($post->post_excerpt) && ("on" == get_option("relevanssi_index_excerpt") || "attachment" == $post->post_type)) { // include excerpt for attachments which use post_excerpt for captions - modified by renaissancehack $excerpt_tokens = relevanssi_tokenize($post->post_excerpt, true, $min_word_length); foreach ($excerpt_tokens as $token => $count) { isset($insert_data[$token]['excerpt']) ? $insert_data[$token]['excerpt'] += $count : ($insert_data[$token]['excerpt'] = $count); } } if (function_exists('relevanssi_index_mysql_columns')) { $insert_data = relevanssi_index_mysql_columns($insert_data, $post->ID); } $index_titles = true; if (apply_filters('relevanssi_index_titles', $index_titles)) { $filtered_title = apply_filters('relevanssi_post_title_before_tokenize', $post->post_title, $post); $titles = relevanssi_tokenize(apply_filters('the_title', $filtered_title)); if (count($titles) > 0) { foreach ($titles as $title => $count) { $n++; isset($insert_data[$title]['title']) ? $insert_data[$title]['title'] += $count : ($insert_data[$title]['title'] = $count); } } } $index_content = true; if (apply_filters('relevanssi_index_content', $index_content)) { remove_shortcode('noindex'); add_shortcode('noindex', 'relevanssi_noindex_shortcode_indexing'); $contents = apply_filters('relevanssi_post_content', $post->post_content, $post); // Allow user to add extra content for Relevanssi to index // Thanks to Alexander Gieg $additional_content = trim(apply_filters('relevanssi_content_to_index', '', $post)); if ('' != $additional_content) { $contents .= ' ' . $additional_content; } if ('on' == get_option('relevanssi_expand_shortcodes')) { if (function_exists("do_shortcode")) { // WP Table Reloaded support if (defined('WP_TABLE_RELOADED_ABSPATH')) { include_once WP_TABLE_RELOADED_ABSPATH . 'controllers/controller-frontend.php'; $My_WP_Table_Reloaded = new WP_Table_Reloaded_Controller_Frontend(); } // TablePress support if (defined('TABLEPRESS_ABSPATH')) { $My_TablePress_Controller = TablePress::load_controller('frontend'); $My_TablePress_Controller->init_shortcodes(); } $disable_shortcodes = get_option('relevanssi_disable_shortcodes'); $shortcodes = explode(',', $disable_shortcodes); foreach ($shortcodes as $shortcode) { remove_shortcode(trim($shortcode)); } remove_shortcode('contact-form'); // Jetpack Contact Form causes an error message remove_shortcode('starrater'); // GD Star Rating rater shortcode causes problems remove_shortcode('responsive-flipbook'); // Responsive Flipbook causes problems remove_shortcode('avatar_upload'); // WP User Avatar is incompatible remove_shortcode('product_categories'); // A problematic WooCommerce shortcode remove_shortcode('recent_products'); // A problematic WooCommerce shortcode remove_shortcode('php'); // PHP Code for Posts $post_before_shortcode = $post; $contents = do_shortcode($contents); $post = $post_before_shortcode; if (defined('TABLEPRESS_ABSPATH')) { unset($My_TablePress_Controller); } if (defined('WP_TABLE_RELOADED_ABSPATH')) { unset($My_WP_Table_Reloaded); } } } else { if (function_exists("strip_shortcodes")) { // WP 2.5 doesn't have the function $contents = strip_shortcodes($contents); } } remove_shortcode('noindex'); add_shortcode('noindex', 'relevanssi_noindex_shortcode'); $contents = relevanssi_strip_invisibles($contents); if (function_exists('relevanssi_process_internal_links')) { $contents = relevanssi_process_internal_links($contents, $post->ID); } $contents = preg_replace('/<[a-zA-Z\\/][^>]*>/', ' ', $contents); $contents = strip_tags($contents); if (function_exists('wp_encode_emoji')) { $contents = wp_encode_emoji($contents); } $contents = apply_filters('relevanssi_post_content_before_tokenize', $contents, $post); $contents = relevanssi_tokenize($contents, true, $min_word_length); if (count($contents) > 0) { foreach ($contents as $content => $count) { $n++; isset($insert_data[$content]['content']) ? $insert_data[$content]['content'] += $count : ($insert_data[$content]['content'] = $count); } } } $type = 'post'; if ($post->post_type == 'attachment') { $type = 'attachment'; } $insert_data = apply_filters('relevanssi_indexing_data', $insert_data, $post); $values = array(); foreach ($insert_data as $term => $data) { $content = 0; $title = 0; $comment = 0; $tag = 0; $link = 0; $author = 0; $category = 0; $excerpt = 0; $taxonomy = 0; $customfield = 0; $taxonomy_detail = ''; $customfield_detail = ''; $mysqlcolumn = 0; extract($data); $term = trim($term); $value = $wpdb->prepare("(%d, %s, REVERSE(%s), %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s, %s, %d)", $post->ID, $term, $term, $content, $title, $comment, $tag, $link, $author, $category, $excerpt, $taxonomy, $customfield, $type, $taxonomy_detail, $customfield_detail, $mysqlcolumn); array_push($values, $value); } $values = apply_filters('relevanssi_indexing_values', $values, $post); if (!empty($values)) { $values = implode(', ', $values); $query = "INSERT IGNORE INTO {$relevanssi_table} (doc, term, term_reverse, content, title, comment, tag, link, author, category, excerpt, taxonomy, customfield, type, taxonomy_detail, customfield_detail, mysqlcolumn)\n\t\t\tVALUES {$values}"; $wpdb->query($query); } if ($post_was_null) { $post = null; } if ($previous_post) { $post = $previous_post; } return $n; }
/** * Parse and evaluate the content of a cell * * @since 1.0.0 * * @param string $content Content of a cell * @param array $parents List of cells that depend on this cell (to prevent circle references) * @return string Result of the parsing/evaluation */ protected function _evaluate_cell($content, array $parents = array()) { if ('' == $content || '=' == $content || '=' != $content[0]) { return $content; } $content = substr($content, 1); // Support putting formulas in strings, like =Total: {A3+A4} $expressions = array(); if (preg_match_all('#{(.+?)}#', $content, $expressions, PREG_SET_ORDER)) { $formula_in_string = true; } else { $formula_in_string = false; $expressions[] = array($content, $content); // fill array so that it has the same structure as if it came from preg_match_all() } foreach ($expressions as $expression) { $orig_expression = $expression[0]; $expression = $expression[1]; $replaced_references = $replaced_ranges = array(); // remove all whitespace characters $expression = preg_replace('#[\\r\\n\\t ]#', '', $expression); // expand cell ranges (like A3:A6) to a list of single cells (like A3,A4,A5,A6) if (preg_match_all('#([A-Z]+)([0-9]+):([A-Z]+)([0-9]+)#', $expression, $referenced_cell_ranges, PREG_SET_ORDER)) { foreach ($referenced_cell_ranges as $cell_range) { if (in_array($cell_range[0], $replaced_ranges, true)) { continue; } $replaced_ranges[] = $cell_range[0]; if (isset($this->known_ranges[$cell_range[0]])) { $expression = preg_replace('#(?<![A-Z])' . preg_quote($cell_range[0], '#') . '(?![0-9])#', $this->known_ranges[$cell_range[0]], $expression); continue; } // no -1 necessary for this transformation, as we don't actually access the table $first_col = TablePress::letter_to_number($cell_range[1]); $first_row = $cell_range[2]; $last_col = TablePress::letter_to_number($cell_range[3]); $last_row = $cell_range[4]; $col_start = min($first_col, $last_col); $col_end = max($first_col, $last_col) + 1; // +1 for loop below $row_start = min($first_row, $last_row); $row_end = max($first_row, $last_row) + 1; // +1 for loop below $cell_list = array(); for ($col = $col_start; $col < $col_end; $col++) { for ($row = $row_start; $row < $row_end; $row++) { $column = TablePress::number_to_letter($col); $cell_list[] = "{$column}{$row}"; } } $cell_list = implode(',', $cell_list); $expression = preg_replace('#(?<![A-Z])' . preg_quote($cell_range[0], '#') . '(?![0-9])#', $cell_list, $expression); $this->known_ranges[$cell_range[0]] = $cell_list; } } // parse and evaluate single cell references (like A3 or XY312), while prohibiting circle references if (preg_match_all('#([A-Z]+)([0-9]+)#', $expression, $referenced_cells, PREG_SET_ORDER)) { foreach ($referenced_cells as $cell_reference) { if (in_array($cell_reference[0], $parents, true)) { return '!ERROR! Circle Reference'; } if (in_array($cell_reference[0], $replaced_references, true)) { continue; } $replaced_references[] = $cell_reference[0]; $ref_col = TablePress::letter_to_number($cell_reference[1]) - 1; $ref_row = $cell_reference[2] - 1; if (!isset($this->table['data'][$ref_row]) || !isset($this->table['data'][$ref_row][$ref_col])) { return "!ERROR! Cell {$cell_reference[0]} does not exist"; } $ref_parents = $parents; $ref_parents[] = $cell_reference[0]; $result = $this->table['data'][$ref_row][$ref_col] = $this->_evaluate_cell($this->table['data'][$ref_row][$ref_col], $ref_parents); // Bail if there was an error already if (false !== strpos($result, '!ERROR!')) { return $result; } // remove all whitespace characters $result = preg_replace('#[\\r\\n\\t ]#', '', $result); // Treat empty cells as 0 if ('' == $result) { $result = 0; } // Bail if the cell does not result in a number (meaning it was a number or expression before being evaluated) if (!is_numeric($result)) { return "!ERROR! {$cell_reference[0]} does not contain a number or expression"; } $expression = preg_replace('#(?<![A-Z])' . $cell_reference[0] . '(?![0-9])#', $result, $expression); } } $result = $this->_evaluate_math_expression($expression); // Support putting formulas in strings, like =Total: {A3+A4} if ($formula_in_string) { $content = str_replace($orig_expression, $result, $content); } else { $content = $result; } } return $content; }
/** * Print the content of the "Cancel Saving" text box. * * @since 1.0.0 * * @param array $data Data for this screen. * @param array $box Information about the text box. */ public function textbox_proceed_no_file_saving(array $data, array $box) { ?> <h3><?php _e('Proceed without saving a file', 'tablepress'); ?> </h3> <p> <?php _e('To proceed without trying to save the “Custom CSS” to a file, click the button below.', 'tablepress'); ?> <?php _e('Your “Custom CSS” will then be loaded inline.', 'tablepress'); ?> </p><p> <a href="<?php echo TablePress::url(array('action' => 'options', 'message' => 'success_save_error_custom_css')); ?> " class="button button-large"><?php _e('Proceed without saving “Custom CSS” to a file', 'tablepress'); ?> </a> </p> <?php }
/** * Import Microsoft Excel 2007-2013 data * * @since 1.1.0 */ protected function import_xlsx() { TablePress::load_file('simplexlsx.class.php', 'libraries'); $simplexlsx = new SimpleXLSX($this->import_data, true); if ($simplexlsx->success() && 0 < $simplexlsx->sheetsCount()) { // Get Worksheet ID of the first Worksheet (not necessarily "1", which is the default in SimpleXLSX) $sheet_ids = array_keys($simplexlsx->sheetNames()); $worksheet_id = $sheet_ids[0]; $this->imported_table = array('data' => $this->pad_array_to_max_cols($simplexlsx->rows($worksheet_id))); } else { $output = '<strong>' . __('The imported file contains errors:', 'tablepress') . '</strong><br /><br />' . $simplexlsx->error() . '<br />'; wp_die($output, 'Import Error', array('response' => 200, 'back_link' => true)); } }
/** * Start-up TablePress (run on WordPress "init") and load the controller for the current state * * @since 1.0.0 * @uses load_controller() */ public static function run() { /** * Fires when TablePress is loaded. * * @since 1.0.0 */ do_action('tablepress_run'); // exit early if TablePress doesn't have to be loaded if ('wp-login.php' === basename($_SERVER['SCRIPT_FILENAME']) || defined('XMLRPC_REQUEST') && XMLRPC_REQUEST || defined('DOING_CRON') && DOING_CRON) { return; } // check if minimum requirements are fulfilled, currently WordPress 3.8 if (version_compare(str_replace('-src', '', $GLOBALS['wp_version']), '3.8', '<')) { // show error notice to admins, if WP is not installed in the minimum required version, in which case TablePress will not work if (current_user_can('update_plugins')) { add_action('admin_notices', array('TablePress', 'show_minimum_requirements_error_notice')); } // and exit TablePress return; } /** * Filter the string that is used as the [table] Shortcode. * * @since 1.0.0 * * @param string $shortcode The [table] Shortcode string. */ self::$shortcode = apply_filters('tablepress_table_shortcode', self::$shortcode); /** * Filter the string that is used as the [table-info] Shortcode. * * @since 1.0.0 * * @param string $shortcode_info The [table-info] Shortcode string. */ self::$shortcode_info = apply_filters('tablepress_table_info_shortcode', self::$shortcode_info); // Load modals for table and options, to be accessible from everywhere via `TablePress::$model_options` and `TablePress::$model_table` self::$model_options = self::load_model('options'); self::$model_table = self::load_model('table'); if (is_admin()) { $controller = 'admin'; if (defined('DOING_AJAX') && DOING_AJAX) { $controller .= '_ajax'; } } else { $controller = 'frontend'; } self::$controller = self::load_controller($controller); }
<?php /** * TablePress WP User Option Wrapper class for WordPress Options * * Wraps the WordPress Options API, so that (especially) arrays are stored as JSON, instead of being serialized by PHP. * * @package TablePress * @subpackage Classes * @author Tobias Bäthge * @since 1.0.0 */ // Prohibit direct script loading. defined('ABSPATH') || die('No direct script access allowed!'); // Load parent class. TablePress::load_file('class-wp_option.php', 'classes'); /** * TablePress WP User Option Wrapper class * @package TablePress * @subpackage Classes * @author Tobias Bäthge * @since 1.0.0 */ class TablePress_WP_User_Option extends TablePress_WP_Option { /** * Get the value of a WP User Option with the WP User Options API. * * @since 1.0.0 * * @param string $option_name Name of the WP User Option.
/** * Check if the plugin was updated and perform necessary actions, like updating the options. * * @since 1.0.0 */ protected function plugin_update_check() { // First activation or plugin update. $current_plugin_options_db_version = TablePress::$model_options->get('plugin_options_db_version'); if ($current_plugin_options_db_version < TablePress::db_version) { // Allow more PHP execution time for update process. @set_time_limit(300); // Add TablePress capabilities to the WP_Roles objects, for new installations and all versions below 12. if ($current_plugin_options_db_version < 12) { TablePress::$model_options->add_access_capabilities(); } if (0 === TablePress::$model_options->get('first_activation')) { // Save initial set of plugin options, and time of first activation of the plugin, on first activation. TablePress::$model_options->update(array('first_activation' => current_time('timestamp'), 'plugin_options_db_version' => TablePress::db_version)); } else { // Update Plugin Options Options, if necessary. TablePress::$model_options->merge_plugin_options_defaults(); $updated_options = array('plugin_options_db_version' => TablePress::db_version, 'prev_tablepress_version' => TablePress::$model_options->get('tablepress_version'), 'tablepress_version' => TablePress::version, 'message_plugin_update' => true); // Only write files, if "Custom CSS" is to be used, and if there is "Custom CSS". if (TablePress::$model_options->get('use_custom_css') && '' !== TablePress::$model_options->get('custom_css')) { // Re-save "Custom CSS" to re-create all files (as TablePress Default CSS might have changed). /** * Load WP file functions to provide filesystem access functions early. */ require_once ABSPATH . 'wp-admin/includes/file.php'; /** * Load WP admin template functions to provide `submit_button()` which is necessary for `request_filesystem_credentials()`. */ require_once ABSPATH . 'wp-admin/includes/template.php'; $tablepress_css = TablePress::load_class('TablePress_CSS', 'class-css.php', 'classes'); $result = $tablepress_css->save_custom_css_to_file(TablePress::$model_options->get('custom_css'), TablePress::$model_options->get('custom_css_minified')); // If saving was successful, use "Custom CSS" file. $updated_options['use_custom_css_file'] = $result; // Increase the "Custom CSS" version number for cache busting. if ($result) { $updated_options['custom_css_version'] = TablePress::$model_options->get('custom_css_version') + 1; } } TablePress::$model_options->update($updated_options); // Clear table caches. if ($current_plugin_options_db_version < 16) { // For pre-0.9-RC, where the arrays are serialized and not JSON encoded. TablePress::$model_table->invalidate_table_output_caches_tp09(); } else { // For 0.9-RC and onwards. TablePress::$model_table->invalidate_table_output_caches(); } // Add mime type field to existing posts with the TablePress Custom Post Type, so that other plugins know that they are not dealing with plain text. if ($current_plugin_options_db_version < 25) { TablePress::$model_table->add_mime_type_to_posts(); } // Convert old parameter names to new ones in DataTables "Custom Commands". if ($current_plugin_options_db_version < 26) { TablePress::$model_table->convert_datatables_parameter_names_tp15(); } } TablePress::$model_options->update(array('message_plugin_update_content' => TablePress::$model_options->plugin_update_message(TablePress::$model_options->get('prev_tablepress_version'), TablePress::version, get_locale()))); } // Maybe update the table scheme in each existing table, independently from updating the plugin options. if (TablePress::$model_options->get('table_scheme_db_version') < TablePress::table_scheme_version) { // Convert parameter "datatables_scrollX" to "datatables_scrollx", has to be done before merge_table_options_defaults() is called! if (TablePress::$model_options->get('table_scheme_db_version') < 3) { TablePress::$model_table->merge_table_options_tp08(); } TablePress::$model_table->merge_table_options_defaults(); // Merge print_name/print_description changes made for 0.6-beta. if (TablePress::$model_options->get('table_scheme_db_version') < 2) { TablePress::$model_table->merge_table_options_tp06(); } TablePress::$model_options->update(array('table_scheme_db_version' => TablePress::table_scheme_version)); } /* * Update User Options, if necessary. * User Options are not saved in DB until first change occurs. */ if (is_user_logged_in() && TablePress::$model_options->get('user_options_db_version') < TablePress::db_version) { TablePress::$model_options->merge_user_options_defaults(); TablePress::$model_options->update(array('user_options_db_version' => TablePress::db_version)); } }