Sanitize Wordpress Metabox Fields (POST array) - The right way - php

I´m working on a wordpress plugin with Metaboxes. The plugin got rejected because of the Sanitize of metabox fields.
My save_fields function
public function save_fields( $post_id ) {
if ( ! isset( $_POST['modalsettings_nonce'] ) )
return $post_id;
$nonce = $_POST['modalsettings_nonce'];
if ( !wp_verify_nonce( $nonce, 'modalsettings_data' ) )
return $post_id;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
foreach ( $this->meta_fields as $meta_field ) {
$userInput = $_POST[ $meta_field['id'] ];
if ( isset( $userInput ) ) {
switch ( $meta_field['type'] ) {
case 'email':
$userInput = sanitize_email( $_POST[ $meta_field['id'] ] );
break;
case 'text':
$userInput = sanitize_text_field( $_POST[ $meta_field['id'] ] );
break;
}
update_post_meta( $post_id, $meta_field['id'], $userInput );
} else if ( $meta_field['type'] === 'checkbox' ) {
update_post_meta( $post_id, $meta_field['id'], '0' );
}
}
}
The comment from wordpress review team
Data Must be Sanitized, Escaped, and Validated
When you include POST/GET/REQUEST/FILE calls in your plugin, it's
important to sanitize, validate, and escape them. The goal here is to
prevent a user from accidentally sending trash data through the
system, as well as protecting them from potential security issues.
SANITIZE: Data that is input (either by a user or automatically) must
be sanitized as soon as possible. This lessens the possibility of XSS
vulnerabilities and MITM attacks where posted data is subverted.
VALIDATE: All data should be validated, no matter what. Even when you
sanitize, remember that you don’t want someone putting in ‘dog’ when
the only valid values are numbers.
ESCAPE: Data that is output must be escaped properly when it is
echo'd, so it can't hijack admin screens. There are many esc_*()
functions you can use to make sure you don't show people the wrong
data.
To help you with this, WordPress comes with a number of sanitization
and escaping functions. You can read about those here:
https://developer.wordpress.org/plugins/security/securing-input/
https://developer.wordpress.org/plugins/security/securing-output/
Remember: You must use the most appropriate functions for the context.
If you’re sanitizing email, use sanitize_email(), if you’re outputting
HTML, use esc_html(), and so on.
An easy mantra here is this:
Sanitize early Escape Late Always Validate
Clean everything, check everything, escape everything, and never trust
the users to always have input sane data. After all, users come from
all walks of life.
Example(s) from your plugin:
stylistic-modals/admin/metaboxes.php:202: $userInput = $_POST[
$meta_field['id'] ]; if ( isset( $userInput ) ) { switch (
$meta_field['type'] ) { case 'email': $userInput = sanitize_email(
$_POST[ $meta_field['id'] ] ); break; case 'text': $userInput =
sanitize_text_field( $_POST[ $meta_field['id'] ] ); break; }
update_post_meta( $post_id, $meta_field['id'], $userInput );
Because you save $userInput later down, you must sanitize it.
What can I do?
I have no more ideas what Wordpress want from me and when should I sanitize the fields...also if I search for examples I find just this way to sanitize $_POST arrays....
Do you have any idea?
Edit: Will this work?
public function save_fields( $post_id ) {
if ( ! isset( $_POST['modalsettings_nonce'] ) )
return $post_id;
$nonce = $_POST['modalsettings_nonce'];
if ( !wp_verify_nonce( $nonce, 'modalsettings_data' ) )
return $post_id;
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
foreach ( $this->meta_fields as $meta_field ) {
if ( isset( $_POST[ $meta_field['id'] ] ) ) {
$sanitizedUserInput = "";
$sanitizedMetaFieldID = "";
switch ( $meta_field['type'] ) {
case 'email':
$sanitizedUserInput = sanitize_email( $_POST[ $meta_field['id'] ] );
$sanitizedMetaFieldID = sanitize_email( $meta_field['id']);
break;
case 'text':
$sanitizedUserInput = sanitize_text_field( $_POST[ $meta_field['id'] ] );
$sanitizedMetaFieldID = sanitize_text_field( $meta_field['id']);
break;
default:
$sanitizedUserInput = sanitize_text_field( $_POST[ $meta_field['id'] ] );
$sanitizedMetaFieldID = sanitize_text_field( $meta_field['id']);
}
update_post_meta( $post_id, $sanitizedMetaFieldID, $sanitizedUserInput );
} else if ( $meta_field['type'] === 'checkbox' ) {
$sanitizedMetaFieldID = sanitize_text_field( $meta_field['id']);
update_post_meta( $post_id, $sanitizedMetaFieldID, '0' );
}
}
}

Well, you have this assigning $userInput = $_POST[ $meta_field['id'] ]; there before the if statement. Then you've a switch statement. Now, say, on some reasons, the php execution flow doesn't access to switch statement.
Next up, the php execution flow reaches here:
update_post_meta( $post_id, $meta_field['id'], $userInput );
That means the $userInput variable is NOT being then sanitized. This may be the reason. I hope this would help you.

Related

Form validations for non-required fields

I'm trying to add some form validations to a site I'm working on. I was able to get the validations to work on the fields that are required but as I'm trying to adjust the code for the non-required fields that still need to be validated when there is user-input I'm running into some issues.
This works pretty flawlessly if the field is required but when I make the field not required, the form doesn't submit and puts out an error message if I leave the field blank.
add_action( 'elementor_pro/forms/validation', function ( $record, $ajax_handler ) {
$fields = $record->get_field( [
'id' => 'dot',
] );
if ( empty( $fields ) ) {
return;
}
$field = current( $fields );
if ( 1 !== preg_match( '/[1-9]{1}[0-9]{5,7}/', $field['value'] ) || $field['value'] == '123456' || $field['value'] == '12345678' ) {
$ajax_handler->add_error( $field['id'], 'Invalid DOT#' );
}
}, 10, 2 );

Update a database value if a video is selected?

I will try to explain this, I have a button where I can upload and select a video to add to a post. And I have a input field which I can put in a duration (in seconds). I have made a function which pulls the length of the video from the database, and this length I want to put in the database under slide_duration. And if a video isn't selected I want it to work as it usually do, you can put in a custom value (in seconds) or you can leave this input empty (which makes it revert to the standard value).
The related PHP looks like this:
if ( isset( $_POST['slide_duration'] ) && is_numeric( $_POST['slide_duration'] ) && $_POST['slide_duration'] >= 1 ) {
$slide_duration = intval($_POST['slide_duration']);
update_post_meta( $post_id, 'slide_duration', $slide_duration );
}
else {
delete_post_meta( $post_id, 'slide_duration' );
}
This is how it looked before I touched it. It deletes slide_duration if no value is entered, this is how I need to keep it, to make it revert to the default value if nothing is put there.
I now added this part after the above code:
if ( isset( $_POST['background-video'] ) ) {
update_post_meta( $post_id, 'slide_duration', $video_meta['length'] );
}
This will update the slide_duration in the database when a video is selected. But I cannot manually set the time in the input field, it always reverts to 0 when saving/updating the post. If I put the code above the original, I can put in whatever value I want in the input, but selecting a video won't update slide_duration any longer.
For more context, this is how the input looks:
<?php
$slide_duration = isset( $theme_stored_meta['slide_duration'] ) ? intval($theme_stored_meta['slide_duration'][0]) : '';
?>
<input type="number" name="slide_duration" value="<?=$slide_duration?>" min="1" step="1" style="width: 70px;" /> <?=__('seconds', 'theme')?>
Hope I have explained well enough and provided enough of the code to get a clear picture of this.
EDIT: Tried this too:
if ( isset( $_POST['slide_duration'] ) && is_numeric( $_POST['slide_duration'] ) && $_POST['slide_duration'] >= 1 ) {
$slide_duration = intval($_POST['slide_duration']);
update_post_meta( $post_id, 'slide_duration', $slide_duration );
}
elseif ( isset( $_POST['slide_duration'] ) ) {
update_post_meta( $post_id, 'slide_duration', $video_meta['length'] );
}
if ( is_null( $_POST['slide_duration'] ) ) {
delete_post_meta( $post_id, 'slide_duration' );
}
Got it working finally!
I don't really know what did it, but this is working:
if ( $_POST['slide_duration'] == NULL ) {
delete_post_meta( $post_id, 'slide_duration' );
}
if ( isset( $_POST['slide_duration'] ) && is_numeric( $_POST['slide_duration'] ) && $_POST['slide_duration'] >= 1 ) {
update_post_meta( $post_id, 'slide_duration', (int) $_POST['slide_duration'] );
}
if( isset( $_POST[ 'background-video' ] ) && $video_meta['length'] >= 1 ) {
update_post_meta( $post_id, 'slide_duration', $video_meta['length'] );
}
Thank you very much Sally CJ

How to save meta checkbox WordPress

I want to save a meta with a checkbox for all my posts, here's my code :
add_action( 'save_post','save_metaboxes' );
function save_metaboxes( $post_ID ) {
if( isset( $_POST['is_viewpay'] ) ) {
if( !empty( $_POST['is_viewpay'] ) ) {
update_post_meta( $post_ID, '_is_viewpay', 'active' );
} else {
update_post_meta( $post_ID, '_is_viewpay', '' );
}
}
}
The problem is when I uncheck the checkbox and save my post, It always stay checked. I don't know why.
Thanks for your help !
When you uncheck the checkbox, isset($_POST['is_viewpay']) will evaluate to false so it skips over your remaining code.
Instead you could do:
if(isset($_POST['is_viewpay'])) {
update_post_meta($post_ID, '_is_viewpay', 'active');
} else {
update_post_meta($post_ID, '_is_viewpay', '');
}
As a side note, it's highly recommended to use Nonces (which will help protect your page from malicious attacks).

How to make the custom meta boxes support for the visual composer in WordPress?

I am using the visual composer for the WordPress posts and pages actually for over all. But I want to make some custom meta boxes under the screen of the post editor. Actually already I have made the fields. But now I want to make those fields available in the visual composer. Actually I want to add those fields in the visual editor. How can I do that? Please help me with your valuable knowledge.
Here is my code of the meta boxes
<?php
function myplugin_add_meta_box() {
$screens = array( 'post', 'page' );
foreach ( $screens as $screen ) {
add_meta_box(
'myplugin_sectionid',
__( 'My Post Section Title', 'myplugin_textdomain' ),
'myplugin_meta_box_callback',
$screen
);
}
}
add_action( 'add_meta_boxes', 'myplugin_add_meta_box' );
function myplugin_meta_box_callback( $post ) {
wp_nonce_field( 'myplugin_save_meta_box_data', 'myplugin_meta_box_nonce' );
$value = get_post_meta( $post->ID, '_my_meta_value_key', true );
echo '<label for="myplugin_new_field">';
_e( 'Description for this field', 'myplugin_textdomain' );
echo '</label> ';
echo '<input type="text" id="myplugin_new_field" name="myplugin_new_field" value="' . esc_attr( $value ) . '" size="25" />';
}
function myplugin_save_meta_box_data( $post_id ) {
if ( ! isset( $_POST['myplugin_meta_box_nonce'] ) ) {
return;
}
// Verify that the nonce is valid.
if ( ! wp_verify_nonce( $_POST['myplugin_meta_box_nonce'], 'myplugin_save_meta_box_data' ) ) {
return;
}
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// Check the user's permissions.
if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {
if ( ! current_user_can( 'edit_page', $post_id ) ) {
return;
}
} else {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
}
/* OK, it's safe for us to save the data now. */
// Make sure that it is set.
if ( ! isset( $_POST['myplugin_new_field'] ) ) {
return;
}
// Sanitize user input.
$my_data = sanitize_text_field( $_POST['myplugin_new_field'] );
// Update the meta field in the database.
update_post_meta( $post_id, '_my_meta_value_key', $my_data );
}
add_action( 'save_post', 'myplugin_save_meta_box_data' );
I see that you are echoing your fields as inputs. You need to use the wp_editor() function instead. It will take care of the wysiwyg (visual editor) field creation for you.

Insert data of custom metabox to database

How can I insert data values of custom metaboxes into a database to the corresponding field in a table?
This is how I tried to get the values for each form:
$l = $_POST['liens'];
$post_id = $_POST['post_ID'];
$langue = $_POST['lang'];
$qual = $_POST['qual'];
$type = $_POST['type'];
if (isset($l) and !empty($l) )
mysql_query("insert into blog_liens values('','".$post_id."','".$l."','".$langue."','".$qual."','".$type."',now(),'','1') ");
But it's not working.
Always use $wpdb when handling database in WordPress but that's not applicable here anyway.
Add this to the same file as your metabox.
function my_metabox_save_value( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
if ( ! current_user_can( 'edit_post' ) ) return;
if ( isset( $_POST['lang'] ) )
update_post_meta( $post_id, 'lang', sanitize_text_field( $_POST['lang'] ) );
}
add_action( 'save_post', 'my_metabox_save_value' );
Repeat update_post_meta for each value you want to save and add your own checks if needed such as ! empty().
Ideally you would also be using a nonce but that's beyond the scope of the question. For further info please see: http://codex.wordpress.org/WordPress_Nonces and http://codex.wordpress.org/Function_Reference/add_meta_box
please escape the post parameters for example with mysql_real_escape_string
dont use mysql_* functions -> use mysqli or PDO for your Queries
Have you tried to debug? ;)
$result = mysql_query('SELECT foo FROM bar');
if(!$result ){
echo mysql_error();
exit;
}

Categories