| 1 |
<?php |
| 2 |
|
| 3 |
/** |
| 4 |
* Suppress "error - 0 - No summary was found for this file" on phpdoc generation |
| 5 |
* |
| 6 |
* @package WPDataAccess\Data_Publisher |
| 7 |
*/ |
| 8 |
namespace WPDataAccess\Data_Publisher; |
| 9 |
|
| 10 |
use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Exist; |
| 11 |
use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Lists; |
| 12 |
use WPDataAccess\Data_Tables\WPDA_Data_Tables; |
| 13 |
use WPDataAccess\List_Table\WPDA_List_Table; |
| 14 |
use WPDataAccess\Plugin_Table_Models\WPDA_Publisher_Model; |
| 15 |
use WPDataAccess\Utilities\WPDA_Message_Box; |
| 16 |
use WPDataAccess\WPDA; |
| 17 |
/** |
| 18 |
* Class WPDA_Publisher_List_Table extends WPDA_List_Table |
| 19 |
* |
| 20 |
* List table to support Data Tables. |
| 21 |
* |
| 22 |
* @author Peter Schulz |
| 23 |
* @since 2.0.15 |
| 24 |
*/ |
| 25 |
class WPDA_Publisher_List_Table extends WPDA_List_Table { |
| 26 |
public function __construct( $args = array() ) { |
| 27 |
$args['column_headers'] = self::column_headers_labels(); |
| 28 |
$args['title'] = 'Data Tables'; |
| 29 |
$args['subtitle'] = ''; |
| 30 |
parent::__construct( $args ); |
| 31 |
WPDA_Data_Tables::enqueue_styles_and_script(); |
| 32 |
} |
| 33 |
|
| 34 |
public function get_columns() { |
| 35 |
if ( is_array( $this->wpda_cached_columns ) ) { |
| 36 |
return $this->wpda_cached_columns; |
| 37 |
} |
| 38 |
$columns = parent::get_columns(); |
| 39 |
// Remove data source column. |
| 40 |
unset($columns['pub_data_source']); |
| 41 |
// Add data source column after schema name. |
| 42 |
$columns = WPDA::array_insert_after( $columns, 'pub_schema_name', array( |
| 43 |
'pub_data_source' => __( 'Data Source', 'wp-data-access' ), |
| 44 |
) ); |
| 45 |
return $columns; |
| 46 |
} |
| 47 |
|
| 48 |
/** |
| 49 |
* Overwrite method column_default |
| 50 |
* |
| 51 |
* Column pub_responsive should return 'Flat' or 'Responsive'. |
| 52 |
*/ |
| 53 |
public function column_default( $item, $column_name ) { |
| 54 |
if ( 'pub_id' === $column_name ) { |
| 55 |
// Validate schema, table and column names |
| 56 |
$warning = WPDA::validate_names( $item['pub_schema_name'], $item['pub_table_name'] ); |
| 57 |
if ( '' !== $warning ) { |
| 58 |
return $item['pub_id'] . $warning . substr( parent::column_default( $item, $column_name ), strlen( $item['pub_id'] ) ); |
| 59 |
} |
| 60 |
} |
| 61 |
if ( 'pub_schema_name' === $column_name ) { |
| 62 |
if ( 'CPT' === $item['pub_data_source'] ) { |
| 63 |
return ''; |
| 64 |
} |
| 65 |
global $wpdb; |
| 66 |
if ( $wpdb->dbname === $item[$column_name] ) { |
| 67 |
return "WordPress database ({$item[$column_name]})"; |
| 68 |
} |
| 69 |
} |
| 70 |
if ( 'pub_data_source' === $column_name ) { |
| 71 |
switch ( $item[$column_name] ) { |
| 72 |
case 'Query': |
| 73 |
// Show SQL query. |
| 74 |
return '<div>' . 'Custom query ' . '<i class="fas fa-eye wpda_tooltip_cq" title="' . $this->render_column_content( $item, 'pub_query', false ) . '"></i>' . '</div>'; |
| 75 |
case 'CPT': |
| 76 |
// Show CPT query. |
| 77 |
return 'Custom post type: ' . $this->render_column_content( $item, 'pub_cpt' ); |
| 78 |
default: |
| 79 |
// Show database table. |
| 80 |
return $this->render_column_content( $item, 'pub_table_name' ); |
| 81 |
} |
| 82 |
} |
| 83 |
if ( 'pub_table_name' === $column_name ) { |
| 84 |
if ( 'Query' === $item['pub_data_source'] ) { |
| 85 |
return ''; |
| 86 |
} |
| 87 |
} |
| 88 |
if ( 'pub_responsive' === $column_name ) { |
| 89 |
if ( 'Yes' === $item[$column_name] ) { |
| 90 |
return 'Responsive'; |
| 91 |
} else { |
| 92 |
return 'Flat'; |
| 93 |
} |
| 94 |
} |
| 95 |
if ( 'pub_table_options_searching' === $column_name || 'pub_table_options_ordering' === $column_name || 'pub_table_options_paging' === $column_name || 'pub_table_options_serverside' === $column_name ) { |
| 96 |
if ( 'on' === $item[$column_name] ) { |
| 97 |
return 'Yes'; |
| 98 |
} else { |
| 99 |
return 'No'; |
| 100 |
} |
| 101 |
} |
| 102 |
return parent::column_default( $item, $column_name ); |
| 103 |
} |
| 104 |
|
| 105 |
/** |
| 106 |
* Overwrites method column_default_add_action |
| 107 |
* |
| 108 |
* Add a link to show the shortcode of a data table. |
| 109 |
* |
| 110 |
* @param array $item |
| 111 |
* @param string $column_name |
| 112 |
* @param array $actions |
| 113 |
*/ |
| 114 |
public function column_default_add_action( $item, $column_name, &$actions ) { |
| 115 |
parent::column_default_add_action( $item, $column_name, $actions ); |
| 116 |
// Add copy data table to actions |
| 117 |
$wp_nonce_action = "wpda-copy-{$this->table_name}"; |
| 118 |
$wp_nonce = wp_create_nonce( $wp_nonce_action ); |
| 119 |
$form_id = '_' . (self::$list_number - 1); |
| 120 |
$esc_attr = 'esc_attr'; |
| 121 |
$input_fields = $this->get_key_input_fields( $item ); |
| 122 |
$page_field = $this->page_number_item; |
| 123 |
// phpcs:ignore PluginCheck.CodeAnalysis.Heredoc.NotAllowed |
| 124 |
$copy_form = <<<EOT |
| 125 |
\t\t\t\t<form id='copy_form{$esc_attr( $form_id )}' method='post' |
| 126 |
\t\t\t\t\t action='?page={$esc_attr( $this->page )}' |
| 127 |
\t\t\t\t> |
| 128 |
\t\t\t\t\t{$input_fields} |
| 129 |
\t\t\t\t\t<input type='hidden' name='table_name' value='{$esc_attr( $this->table_name )}'> |
| 130 |
\t\t\t\t\t<input type='hidden' name='action' value='copy' /> |
| 131 |
\t\t\t\t\t<input type='hidden' name='_wpnonce' value='{$esc_attr( $wp_nonce )}'> |
| 132 |
\t\t\t\t\t{$page_field} |
| 133 |
\t\t\t\t</form> |
| 134 |
EOT; |
| 135 |
?> |
| 136 |
|
| 137 |
<script type='text/javascript'> |
| 138 |
jQuery("#wpda_invisible_container").append("<?php |
| 139 |
// phpcs:disable WordPress.Security.EscapeOutput |
| 140 |
echo str_replace( array("\n", "\r"), '', $copy_form ); |
| 141 |
// phpcs:enable WordPress.Security.EscapeOutput |
| 142 |
?>"); |
| 143 |
</script> |
| 144 |
|
| 145 |
<?php |
| 146 |
$copy_warning = __( "Copy table options set?\\n\\'Cancel\\' to stop, \\'OK\\' to copy.", 'wp-data-access' ); |
| 147 |
$actions['copy'] = sprintf( |
| 148 |
'<a href="javascript:void(0)" |
| 149 |
title="%s" |
| 150 |
class="edit wpda_tooltip" |
| 151 |
onclick="if (confirm(\'%s\')) jQuery(\'#%s\').submit()"> |
| 152 |
<span style="white-space: nowrap"> |
| 153 |
<i class="fas fa-copy wpda_icon_on_button"></i> |
| 154 |
%s |
| 155 |
</span> |
| 156 |
</a> |
| 157 |
', |
| 158 |
__( 'Copy: new table name = old table name_ + n', 'wp-data-access' ), |
| 159 |
$copy_warning, |
| 160 |
"copy_form{$form_id}", |
| 161 |
__( 'Copy', 'wp-data-access' ) |
| 162 |
); |
| 163 |
// Show Data Table shortcode directly from Data Tables main page |
| 164 |
$shortcode_enabled = 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_WPDATAACCESS_POST ) && 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_WPDATAACCESS_PAGE ); |
| 165 |
?> |
| 166 |
<div id="wpda_publication_<?php |
| 167 |
echo esc_attr( $item['pub_id'] ); |
| 168 |
?>" |
| 169 |
title="<?php |
| 170 |
echo esc_attr__( 'Shortcode', 'wp-data-access' ); |
| 171 |
?>" |
| 172 |
style="display:none" |
| 173 |
> |
| 174 |
<p class="wpda_shortcode_content"> |
| 175 |
Copy the shortcode below into your post or page to make this data table available on your website. |
| 176 |
</p> |
| 177 |
<p class="wpda_shortcode_text"> |
| 178 |
<strong> |
| 179 |
[wpdataaccess pub_id="<?php |
| 180 |
echo esc_attr( $item['pub_id'] ); |
| 181 |
?>"] |
| 182 |
</strong> |
| 183 |
</p> |
| 184 |
<p class="wpda_shortcode_buttons"> |
| 185 |
<button class="button wpda_shortcode_clipboard wpda_shortcode_button" |
| 186 |
type="button" |
| 187 |
data-clipboard-text='[wpdataaccess pub_id="<?php |
| 188 |
echo esc_attr( $item['pub_id'] ); |
| 189 |
?>"]' |
| 190 |
onclick="jQuery.notify('<?php |
| 191 |
echo esc_attr__( 'Shortcode successfully copied to clipboard!', 'wp-data-access' ); |
| 192 |
?>','info')" |
| 193 |
> |
| 194 |
<?php |
| 195 |
echo esc_attr__( 'Copy', 'wp-data-access' ); |
| 196 |
?> |
| 197 |
</button> |
| 198 |
<button class="button button-primary wpda_shortcode_button" |
| 199 |
type="button" |
| 200 |
onclick="jQuery('.ui-dialog-content').dialog('close')" |
| 201 |
> |
| 202 |
<?php |
| 203 |
echo esc_attr__( 'Close', 'wp-data-access' ); |
| 204 |
?> |
| 205 |
</button> |
| 206 |
</p> |
| 207 |
<?php |
| 208 |
if ( !$shortcode_enabled ) { |
| 209 |
?> |
| 210 |
<p> |
| 211 |
Shortcode wpdataaccess is not enabled for all output types. |
| 212 |
<a href="<?php |
| 213 |
echo esc_url( admin_url( 'options-general.php' ) ); |
| 214 |
?>?page=wpdataaccess" class="wpda_shortcode_link">» Manage settings</a> |
| 215 |
</p> |
| 216 |
<?php |
| 217 |
} |
| 218 |
?> |
| 219 |
</div> |
| 220 |
<?php |
| 221 |
$actions['shortcode'] = sprintf( |
| 222 |
'<a href="javascript:void(0)" |
| 223 |
class="view wpda_tooltip" |
| 224 |
title="%s" |
| 225 |
onclick="jQuery(\'#wpda_publication_%s\').dialog()" |
| 226 |
<span style="white-space:nowrap"> |
| 227 |
<i class="fas fa-code wpda_icon_on_button"></i> |
| 228 |
%s |
| 229 |
</span> |
| 230 |
</a> |
| 231 |
', |
| 232 |
__( 'Get shortcode', 'wp-data-access' ), |
| 233 |
esc_attr( $item['pub_id'] ), |
| 234 |
__( 'Shortcode', 'wp-data-access' ) |
| 235 |
); |
| 236 |
$actions['test'] = sprintf( |
| 237 |
'<a href="javascript:void(0)" |
| 238 |
class="view wpda_tooltip" |
| 239 |
title="%s" |
| 240 |
onclick="test_publication(\'%s\', \'%s\')" |
| 241 |
<span style="white-space:nowrap"> |
| 242 |
<i class="fas fa-bug wpda_icon_on_button"></i> |
| 243 |
%s |
| 244 |
</span> |
| 245 |
</a> |
| 246 |
', |
| 247 |
__( 'Test', 'wp-data-access' ), |
| 248 |
esc_attr( wp_create_nonce( "wpda-publication-{$item['pub_id']}" ) ), |
| 249 |
esc_attr( $item['pub_id'] ), |
| 250 |
__( 'Test', 'wp-data-access' ) |
| 251 |
); |
| 252 |
} |
| 253 |
|
| 254 |
public function process_bulk_action() { |
| 255 |
if ( 'copy' === $this->current_action() ) { |
| 256 |
$wp_nonce_action = "wpda-copy-{$this->table_name}"; |
| 257 |
$wp_nonce = ( isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '' ); |
| 258 |
// input var okay. |
| 259 |
if ( !wp_verify_nonce( $wp_nonce, $wp_nonce_action ) ) { |
| 260 |
die( esc_attr__( 'ERROR: Not authorized', 'wp-data-access' ) ); |
| 261 |
} |
| 262 |
if ( isset( $_REQUEST['pub_id'] ) ) { |
| 263 |
$pub_id = sanitize_text_field( wp_unslash( $_REQUEST['pub_id'] ) ); |
| 264 |
// input var okay. |
| 265 |
} |
| 266 |
$unique_pu_name = $this->get_unique_pub_name( $pub_id ); |
| 267 |
global $wpdb; |
| 268 |
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQLPlaceholders |
| 269 |
$pub_raw = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM `%1s` WHERE pub_id = %d', array(WPDA::remove_backticks( $this->table_name ), $pub_id) ), 'ARRAY_A' ); |
| 270 |
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQLPlaceholders |
| 271 |
if ( $wpdb->num_rows > 0 ) { |
| 272 |
$pub_raw[0]['pub_name'] = $unique_pu_name; |
| 273 |
unset($pub_raw[0]['pub_id']); |
| 274 |
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery |
| 275 |
$rows_inserted = $wpdb->insert( $this->table_name, $pub_raw[0] ); |
| 276 |
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery |
| 277 |
switch ( $rows_inserted ) { |
| 278 |
case 0: |
| 279 |
$msg = new WPDA_Message_Box(array( |
| 280 |
'message_text' => __( 'Could not copy data table [source not found]', 'wp-data-access' ), |
| 281 |
'message_type' => 'error', |
| 282 |
'message_is_dismissible' => false, |
| 283 |
)); |
| 284 |
$msg->box(); |
| 285 |
break; |
| 286 |
case 1: |
| 287 |
$msg = new WPDA_Message_Box(array( |
| 288 |
'message_text' => __( 'Data table copied', 'wp-data-access' ), |
| 289 |
)); |
| 290 |
$msg->box(); |
| 291 |
break; |
| 292 |
default: |
| 293 |
$msg = new WPDA_Message_Box(array( |
| 294 |
'message_text' => __( 'Could not copy data table [too many rows]', 'wp-data-access' ), |
| 295 |
'message_type' => 'error', |
| 296 |
'message_is_dismissible' => false, |
| 297 |
)); |
| 298 |
$msg->box(); |
| 299 |
} |
| 300 |
} |
| 301 |
} else { |
| 302 |
parent::process_bulk_action(); |
| 303 |
} |
| 304 |
} |
| 305 |
|
| 306 |
protected function get_unique_pub_name( $pub_id ) { |
| 307 |
global $wpdb; |
| 308 |
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQLPlaceholders |
| 309 |
$db_pub_name = $wpdb->get_results( $wpdb->prepare( 'select pub_name from `%1s` where pub_id = %d', array(WPDA::remove_backticks( WPDA_Publisher_Model::get_base_table_name() ), $pub_id) ), 'ARRAY_A' ); |
| 310 |
if ( $wpdb->num_rows !== 1 ) { |
| 311 |
wp_die( esc_attr__( 'ERROR: Data table not found', 'wp-data-access' ) ); |
| 312 |
} |
| 313 |
$i = 2; |
| 314 |
$pub_name = $db_pub_name[0]['pub_name']; |
| 315 |
$unique_pub_name = "{$pub_name}_{$i}"; |
| 316 |
$wpdb->get_results( $wpdb->prepare( "select 'x' from `%1s` where pub_name = %s", array(WPDA::remove_backticks( WPDA_Publisher_Model::get_base_table_name() ), $unique_pub_name) ) ); |
| 317 |
while ( $wpdb->num_rows > 0 ) { |
| 318 |
// Search until a free options set is found |
| 319 |
$i++; |
| 320 |
$unique_pub_name = "{$pub_name}_{$i}"; |
| 321 |
$wpdb->get_results( $wpdb->prepare( "select 'x' from `%1s` where pub_name = %s", array(WPDA::remove_backticks( WPDA_Publisher_Model::get_base_table_name() ), $unique_pub_name) ) ); |
| 322 |
} |
| 323 |
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQLPlaceholders |
| 324 |
return $unique_pub_name; |
| 325 |
} |
| 326 |
|
| 327 |
public static function column_headers_labels() { |
| 328 |
return array( |
| 329 |
'pub_id' => __( 'ID', 'wp-data-access' ), |
| 330 |
'pub_name' => __( 'Name', 'wp-data-access' ), |
| 331 |
'pub_schema_name' => __( 'Database', 'wp-data-access' ), |
| 332 |
'pub_data_source' => __( 'Data Source', 'wp-data-access' ), |
| 333 |
'pub_table_name' => __( 'Table/View Name', 'wp-data-access' ), |
| 334 |
'pub_column_names' => __( 'Column Names', 'wp-data-access' ), |
| 335 |
'pub_format' => __( 'Format', 'wp-data-access' ), |
| 336 |
'pub_query' => __( 'Query', 'wp-data-access' ), |
| 337 |
'pub_sort_icons' => __( 'Sort Icons', 'wp-data-access' ), |
| 338 |
'pub_styles' => __( 'Styling', 'wp-data-access' ), |
| 339 |
'pub_style_premium' => __( 'Enable Premium Styling', 'wp-data-access' ), |
| 340 |
'pub_style_user' => __( 'Custom Style', 'wp-data-access' ), |
| 341 |
'pub_style_color' => __( 'Style Color', 'wp-data-access' ), |
| 342 |
'pub_style_space' => __( 'Style Spacing', 'wp-data-access' ), |
| 343 |
'pub_style_corner' => __( 'Style Corner', 'wp-data-access' ), |
| 344 |
'pub_style_modal_width' => __( 'Modal Width', 'wp-data-access' ), |
| 345 |
'pub_responsive' => __( 'Output', 'wp-data-access' ), |
| 346 |
'pub_table_options_searching' => __( 'Searching?', 'wp-data-access' ), |
| 347 |
'pub_table_options_ordering' => __( 'Ordering?', 'wp-data-access' ), |
| 348 |
'pub_table_options_paging' => __( 'Paging?', 'wp-data-access' ), |
| 349 |
'pub_table_options_serverside' => __( 'Server Side Processing?', 'wp-data-access' ), |
| 350 |
'pub_table_options_nl2br' => __( 'NL > BR', 'wp-data-access' ), |
| 351 |
'pub_table_options_advanced' => __( 'Advanced Options', 'wp-data-access' ), |
| 352 |
'pub_default_where' => __( 'Default Where', 'wp-data-access' ), |
| 353 |
'pub_default_orderby' => __( 'Default Order By', 'wp-data-access' ), |
| 354 |
'pub_responsive_popup_title' => __( 'Popup Title', 'wp-data-access' ), |
| 355 |
'pub_responsive_cols' => __( 'Responsive Cols', 'wp-data-access' ), |
| 356 |
'pub_responsive_type' => __( 'Responsive Type', 'wp-data-access' ), |
| 357 |
'pub_responsive_modal_hyperlinks' => __( 'Modal Hyperlinks', 'wp-data-access' ), |
| 358 |
'pub_responsive_icon' => __( 'Responsive Icon?', 'wp-data-access' ), |
| 359 |
'pub_flat_scrollx' => __( 'Horizontal Scrollbar', 'wp-data-access' ), |
| 360 |
'pub_extentions' => __( 'Extensions', 'wp-data-access' ), |
| 361 |
'pub_cpt' => __( 'Custom post type', 'wp-data-access' ), |
| 362 |
'pub_cpt_fields' => __( 'Custom fields', 'wp-data-access' ), |
| 363 |
'pub_cpt_query' => __( 'CPT query', 'wp-data-access' ), |
| 364 |
'pub_cpt_format' => __( 'Field labels', 'wp-data-access' ), |
| 365 |
); |
| 366 |
} |
| 367 |
|
| 368 |
// Overwrite method |
| 369 |
public function show() { |
| 370 |
parent::show(); |
| 371 |
WPDA::shortcode_popup(); |
| 372 |
?> |
| 373 |
<script type="application/javascript"> |
| 374 |
function test_publication(wpnonce, pub_id) { |
| 375 |
if (jQuery('#data_publisher_test_container_' + pub_id).length>0) { |
| 376 |
jQuery('#data_publisher_test_container_' + pub_id).show(); |
| 377 |
} else { |
| 378 |
jQuery.ajax({ |
| 379 |
type: "POST", |
| 380 |
url: "<?php |
| 381 |
echo esc_url( admin_url( 'admin-ajax.php?action=wpda_test_publication' ) ); |
| 382 |
?>", |
| 383 |
data: { |
| 384 |
wpnonce: wpnonce, |
| 385 |
pub_id: pub_id |
| 386 |
} |
| 387 |
}).done( |
| 388 |
function (html) { |
| 389 |
jQuery("body").append(html); |
| 390 |
jQuery('#data_publisher_test_container_' + pub_id).show(); |
| 391 |
} |
| 392 |
); |
| 393 |
} |
| 394 |
} |
| 395 |
jQuery(function() { |
| 396 |
jQuery(".wpda_tooltip_cq").tooltip({ |
| 397 |
tooltipClass: "wpda_tooltip_cq wpda_tooltip_dashboard" |
| 398 |
}); |
| 399 |
}); |
| 400 |
</script> |
| 401 |
<style> |
| 402 |
table.wp-list-table td.pub_data_source div { |
| 403 |
overflow-x: hidden; |
| 404 |
max-height: 70px; |
| 405 |
overflow-y: auto; |
| 406 |
} |
| 407 |
.row-actions { |
| 408 |
white-space: nowrap; |
| 409 |
} |
| 410 |
.wpda_tooltip_cq { |
| 411 |
max-width: max-content; |
| 412 |
} |
| 413 |
</style> |
| 414 |
<?php |
| 415 |
} |
| 416 |
|
| 417 |
} |
| 418 |
|