--- a/tablesome/includes/dashboard/cpt-page.php
+++ b/tablesome/includes/dashboard/cpt-page.php
@@ -102,10 +102,12 @@
$html = '<div class="tablesome__fields">';
// $html .= '<label for="tablesome-shortcode">'.__("", "tablesome").'Tablesome Shortcode</label>';
$html .= '<div class="tablesome__field--shortcodeWrapper" title="Table Shortcode">';
- $html .= '<input type="text" id="tablesome__field--shortcode" value="' . $shortcode_in_text . '" readonly class="tablesome__field--shortcode" >';
- $html .= '<span class="tablesome__field--clipboardText" title="' . __( "Copy Shortcode Clipboard", "tablesome" ) . '">' . __( "Copy Shortcode", "tablesome" ) . '</span>';
+ $html .= '<input type="text" id="tablesome__field--shortcode" value="' . esc_attr( $shortcode_in_text ) . '" readonly class="tablesome__field--shortcode" data-table-id="' . esc_attr( $post->ID ) . '" data-initial-shortcode="' . esc_attr( $shortcode_in_text ) . '">';
+ $html .= '<span class="tablesome__field--clipboardText" title="' . esc_attr( __( "Copy Shortcode Clipboard", "tablesome" ) ) . '">' . esc_html( __( "Copy Shortcode", "tablesome" ) ) . '</span>';
+ $html .= '<button type="button" class="tablesome__field--customizeButton" title="' . esc_attr( __( "Customize Shortcode", "tablesome" ) ) . '" data-table-id="' . esc_attr( $post->ID ) . '">' . esc_html( __( "Customize", "tablesome" ) ) . '</button>';
$html .= '</div>';
- $html .= '<p class="description">' . __( "Copy and paste this shortcode in any page or post to display this Table", "tablesome" ) . '</p>';
+ $html .= '<p class="description">' . esc_html( __( "Copy and paste this shortcode in any page or post to display this Table", "tablesome" ) ) . '</p>';
+ $html .= '<div id="tablesome-shortcode-customizer-container"></div>';
$html .= '</div>';
return $html;
}
--- a/tablesome/includes/modules/tablesomedb-rest-api/routes.php
+++ b/tablesome/includes/modules/tablesomedb-rest-api/routes.php
@@ -45,7 +45,7 @@
'type' => 'number',
),
),
- 'permission_callback' => '__return_true',
+ 'permission_callback' => array($tablesome_db, 'api_table_export_permission'),
),
),
@@ -55,7 +55,7 @@
'args' => array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($tablesome_db, 'get_tables'),
- 'permission_callback' => array($tablesome_db, 'api_access_permission'),
+ 'permission_callback' => array($tablesome_db, 'api_table_read_permission'),
),
),
@@ -71,7 +71,7 @@
'type' => 'number',
),
),
- 'permission_callback' => array($tablesome_db, 'api_access_permission'),
+ 'permission_callback' => array($tablesome_db, 'api_table_read_permission'),
),
),
--- a/tablesome/includes/modules/tablesomedb-rest-api/tablesomedb-rest-api.php
+++ b/tablesome/includes/modules/tablesomedb-rest-api/tablesomedb-rest-api.php
@@ -140,6 +140,76 @@
return new WP_Error($error_code, $this->get_error_message($error_code));
}
+ /**
+ * Permission callback for REST API endpoints that read table data.
+ * Requires admin-level access (manage_options capability) to prevent
+ * unauthorized access to sensitive table data like email logs.
+ *
+ * @return bool|WP_Error True if user has permission, WP_Error otherwise
+ */
+ public function api_table_read_permission()
+ {
+ // Require admin-level access for reading table data via REST API
+ if (!current_user_can('manage_options')) {
+ $error_code = "UNAUTHORIZED";
+ return new WP_Error($error_code, $this->get_error_message($error_code));
+ }
+ return true;
+ }
+
+ /**
+ * Permission callback for the table export endpoint.
+ *
+ * Security model:
+ * - If public export is enabled for a table (allow_public_export = true),
+ * anyone may export it (including unauthenticated users).
+ * - If public export is disabled:
+ * - Only Editors/Admins (edit_others_posts / manage_options) may export.
+ * - Contributors and lower roles are blocked, even on their own tables.
+ *
+ * This ensures that the REST export endpoint is restricted to privileged
+ * backend roles while the frontend export button can continue to use
+ * client-side XLSX based on UI permissions.
+ *
+ * @param WP_REST_Request $request
+ * @return bool|WP_Error
+ */
+ public function api_table_export_permission($request)
+ {
+ $table_id = intval($request->get_param('table_id'));
+
+ if (!$table_id) {
+ $error_code = 'REQUIRED_POST_ID';
+ return new WP_Error($error_code, $this->get_error_message($error_code));
+ }
+
+ $post = get_post($table_id);
+ if (!$post || $post->post_type !== TABLESOME_CPT) {
+ $error_code = 'INVALID_POST';
+ return new WP_Error($error_code, $this->get_error_message($error_code));
+ }
+
+ $table_meta = get_tablesome_data($table_id);
+ $access_control = isset($table_meta['options']['access_control']) ? $table_meta['options']['access_control'] : [];
+ $allow_public_export = isset($access_control['allow_public_export']) ? $access_control['allow_public_export'] : false;
+
+ // When public export is enabled, allow anyone to export.
+ if ($allow_public_export) {
+ return true;
+ }
+
+ // When public export is disabled, only Editors/Admins are allowed.
+ $can_edit_others_posts = current_user_can('edit_others_posts');
+ $can_manage_options = current_user_can('manage_options');
+
+ if ($can_manage_options || $can_edit_others_posts) {
+ return true;
+ }
+
+ $error_code = 'UNAUTHORIZED';
+ return new WP_Error($error_code, $this->get_error_message($error_code));
+ }
+
public function get_error_message($error_code)
{
$messages = array(
@@ -707,6 +777,16 @@
public function get_tables($request)
{
+ // Defense-in-depth: Require admin-level access for reading table data via REST API
+ if (!current_user_can('manage_options')) {
+ $error_code = "UNAUTHORIZED";
+ return new WP_Error(
+ $error_code,
+ $this->get_error_message($error_code),
+ array('status' => $this->get_http_status_for_error($error_code))
+ );
+ }
+
$data = array();
/** Get all tablesome posts */
$posts = get_posts(
@@ -782,6 +862,16 @@
}
public function get_table_data($request)
{
+ // Defense-in-depth: Require admin-level access for reading table data via REST API
+ if (!current_user_can('manage_options')) {
+ $error_code = "UNAUTHORIZED";
+ return new WP_Error(
+ $error_code,
+ $this->get_error_message($error_code),
+ array('status' => $this->get_http_status_for_error($error_code))
+ );
+ }
+
$data = array();
$table_id = $request->get_param('table_id');
$post = get_post($table_id);
--- a/tablesome/includes/shortcodes.php
+++ b/tablesome/includes/shortcodes.php
@@ -22,6 +22,12 @@
$defaults = $this->default_args();
$args = array_merge($defaults, $atts);
// $args = shortcode_atts($defaults, $atts);
+
+ // Sanitize exclude_columns_from_search parameter
+ if (isset($args['exclude_columns_from_search'])) {
+ $args['exclude_columns_from_search'] = sanitize_text_field($args['exclude_columns_from_search']);
+ }
+
$is_valid_table = $this->validate($args);
if (!$is_valid_table) {
@@ -41,6 +47,7 @@
'pagination' => true,
// 'page_limit' => Tablesome_Getter::get('num_of_records_per_page'),
// 'exclude_column_ids' => '',
+ 'exclude_columns_from_search' => '',
// 'search' => Tablesome_Getter::get('search'),
// 'hide_table_header' => Tablesome_Getter::get('hide_table_header'),
// 'show_serial_number_column' => Tablesome_Getter::get('show_serial_number_column'),
--- a/tablesome/tablesome.php
+++ b/tablesome/tablesome.php
@@ -5,7 +5,7 @@
Plugin URI: https://tablesomewp.com/
Description: Powerful Tables + Form Automations. Save, Edit, Display (frontend) & Export Form entries, integrate with Notion, Redirection for Forms. Supports Contact Form 7, WPForms, Gravity Forms, Fluent, Elementor and more
Author: Pauple
-Version: 1.2.1
+Version: 1.2.2
Author URI: http://pauple.com
Network: False
Text Domain: tablesome
@@ -46,7 +46,7 @@
{
$constants = [
- 'TABLESOME_VERSION' => '1.2.1',
+ 'TABLESOME_VERSION' => '1.2.2',
'TABLESOME_DOMAIN' => 'tablesome',
'TABLESOME_CPT' => 'tablesome_cpt',
'TABLESOME__FILE__' => __FILE__,
--- a/tablesome/vendor/composer/installed.php
+++ b/tablesome/vendor/composer/installed.php
@@ -3,7 +3,7 @@
'name' => 'pauple/tablesome',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
- 'reference' => '804640f97a84d5e72a5cdf26bb36942d882c568d',
+ 'reference' => '10c5099e3934381946b136e1b9a4081621d77102',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -31,7 +31,7 @@
'pauple/tablesome' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
- 'reference' => '804640f97a84d5e72a5cdf26bb36942d882c568d',
+ 'reference' => '10c5099e3934381946b136e1b9a4081621d77102',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),