Ask your WordPress questions! Pay money and get answers fast! Comodo Trusted Site Seal
Official PayPal Seal

Metabox - update Post - save duplicated rows to database / post via Ajax WordPress

  • SOLVED

I have created a custom_post_type with a Metabox where i can duplicate rows / items with jquery and i can sortable them. Now i want when i save the post, that the content (input fields) are saved. When the page reload, the new items still be there... I know I need ajax for this, but I don't have a real idea how to start...



I use only Wordpress editor. Its only styled by jqueryUI and CSS... For the Content Elements (Rows) i use the following Extension from Codecanyon: https://codecanyon.net/item/easy-row-duplication-jquery-plugin/10756407

With it i can click on Add Row and the Div will completely duplicated. I also can sortable the divs. The Extension allows me to have callbacks for "Add Row" or "Delete Row" and for sortable start and stop...
When i add a row or delete, the results should be saved as a normal input or textfield in the metabox.
I save a field with following code:
if ( isset($_POST['arti_carousel_tab_formattings_items_button_texttransform'])){
update_post_meta( $post_id, 'arti_carousel_tab_formattings_items_button_texttransform', $_POST['arti_carousel_tab_formattings_items_button_texttransform']);
};



Here a bit Code of my Metabox.php, the whole Code would be a bit to much for this site...

<?php
/* Security Check */
if (!defined('ABSPATH')) {
return;
}

// Register Custom Post Type
function arti_carousel_add_post_type() {

$labels = array(
'name' => _x( 'Carousels', 'Post Type General Name', 'arti-carousel' ),
'singular_name' => _x( 'Carousel', 'Post Type Singular Name', 'arti-carousel' ),
'menu_name' => __( 'Arti-Carousels', 'arti-carousel' ),
'name_admin_bar' => __( 'Arti-Carousels', 'arti-carousel' ),
'archives' => __( 'Item Archives', 'arti-carousel' ),
'attributes' => __( 'Item Attributes', 'arti-carousel' ),
'parent_item_colon' => __( 'Parent Item:', 'arti-carousel' ),
'all_items' => __( 'All Items', 'arti-carousel' ),
'add_new_item' => __( 'Add New Item', 'arti-carousel' ),
'add_new' => __( 'Add New', 'arti-carousel' ),
'new_item' => __( 'New Item', 'arti-carousel' ),
'edit_item' => __( 'Edit Item', 'arti-carousel' ),
'update_item' => __( 'Update Item', 'arti-carousel' ),
'view_item' => __( 'View Item', 'arti-carousel' ),
'view_items' => __( 'View Items', 'arti-carousel' ),
'search_items' => __( 'Search Item', 'arti-carousel' ),
'not_found' => __( 'Not found', 'arti-carousel' ),
'not_found_in_trash' => __( 'Not found in Trash', 'arti-carousel' ),
'featured_image' => __( 'Featured Image', 'arti-carousel' ),
'set_featured_image' => __( 'Set featured image', 'arti-carousel' ),
'remove_featured_image' => __( 'Remove featured image', 'arti-carousel' ),
'use_featured_image' => __( 'Use as featured image', 'arti-carousel' ),
'insert_into_item' => __( 'Insert into item', 'arti-carousel' ),
'uploaded_to_this_item' => __( 'Uploaded to this item', 'arti-carousel' ),
'items_list' => __( 'Items list', 'arti-carousel' ),
'items_list_navigation' => __( 'Items list navigation', 'arti-carousel' ),
'filter_items_list' => __( 'Filter items list', 'arti-carousel' ),
);
$args = array(
'label' => __( 'Carousel', 'arti-carousel' ),
'description' => __( 'Post Type Description', 'arti-carousel' ),
'labels' => $labels,
'supports' => false,
'hierarchical' => false,
'supports' => array( 'title' ),
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'can_export' => true,
'has_archive' => true,
'exclude_from_search' => false,
'publicly_queryable' => true,
'capability_type' => 'post',
);
register_post_type( 'arti_carousel', $args );

}

add_action( 'init', 'arti_carousel_add_post_type', 0 );
//Show Metabox
add_action( 'add_meta_boxes', 'arti_carousel_add_custom_meta_box' );
function arti_carousel_add_custom_meta_box (){
add_meta_box(
'arti_carousel_editor',
__('Carousel', 'arti-carousel'),
'arti_carousel_editor',
'arti_carousel',
'normal',
'high'
);
}


function arti_carousel_editor( $post )
{
wp_nonce_field('arti_carousel_save_meta_box_data', 'arti_carousel_meta_box_nonce');
$output = '
<div id="arti-carousel-tabs-5">' /* Carousel Items */ .'
<div class="easyRowDuplicationContainer container">
<div class="arti-carousel-admin-item-holder rowDuplication columns">
<div class="column col-4">
<div class="arti-carousel-admin-item arti-carousel-item-admin-headline">
<label for="arti_carousel_tab_items_headline">'.__('Image', 'arti-carousel').'</label>
<input type="text" name="arti_carousel_image" class="arti_carousel_image" value="'.esc_html(get_post_meta($post->ID, 'arti_carousel_image', true)).'"/>
<input type="button" class="arti_carousel_image_button" value="'.__('Upload','arti-carousel').'" data-uploader_title="'.__('File Upload','arti-carousel').'" data-uploader_button_text="'.__('Choose File','arti-carousel').'" />
</div>
</div>
<div class="column col-4">
<div class="arti-carousel-admin-item arti-carousel-item-admin-headline">
<label for="arti_carousel_tab_items_headline">'.__('Headline', 'arti-carousel').'</label>
<input placeholder="'.__('Headline 1', 'arti-carousel').'" name="arti_carousel_tab_items_headline" value="'.esc_html(get_post_meta($post->ID, 'arti_carousel_tab_items_headline', true)).'">
</div>
<div class="arti-carousel-admin-item arti-carousel-item-admin-textarea">
<label for="arti_carousel_tab_items_textarea">'.__('Text', 'arti-carousel').'</label>
<textarea rows="15" placeholder="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." name="arti_carousel_tab_items_textarea">'.esc_html(get_post_meta($post->ID, 'arti_carousel_tab_items_textarea', true)).'</textarea>
</div>
</div>
<div class="column col-4">

</div>
</div>
</div>
</div>
';
echo $output;
};

add_action('save_post','arti_carousel_save'); //Save Code
function arti_carousel_save( $post_id )
{
//Security
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
};
//Nonce-Field Check
if ( ! isset($_POST['arti_carousel_meta_box_nonce'])){
return;
}
if( ! wp_verify_nonce($_POST['arti_carousel_meta_box_nonce'], 'arti_carousel_save_meta_box_data')){
return;
}
//Nonce-Field Check END
if ( 'arti_carousel' == $_POST['post_type']){
if( !current_user_can( 'edit_page', $post_id) || !current_user_can( 'edit_post', $post_id)){
return;
};
};
//Security END

//Fields - Basic Settings
include('metabox-save/fields-basic-setings.php');
//Fields - Formattings
include('metabox-save/fields-formattings.php');
//Load CSS Code for File
include('metabox-save/getCSS.php');

cssfile($post_id,$cssFile);

}

Answers (3)

2019-09-21

timDesain Nanang answers:

the textarea is using basic textarea or wp_editor function?


timDesain Nanang comments:

if use basic textarea, then it's more simpler


User183722 comments:

Yes its only a basic textarea for text without formattings and without html code...


User183722 comments:

I'm not sure if we understood each other right, what do you mean by basic textarea? Your picture looks interesting, how would that work? Can I integrate it into my tabs from jqueryUI?


timDesain Nanang comments:

yes, i understand whar do you mean.
sure, i am using sortable by jqueryui and without ajax.


User183722 comments:

Could you give me an example with add row and delete row and sortable that i can use in my save function?

I've been working with php and javascript for many years now, but with wordpress plugins I'm still at the beginning regarding the wordpress functions...


timDesain Nanang comments:

sure


User183722 comments:

ok, thats nice. i'm using this site for the first time. what's the procedure?


timDesain Nanang comments:

wait a minute, please. i am still working on it.


User183722 comments:

Sure i will waiting. Your solution sounds good for me...


timDesain Nanang comments:

put the following code in the functions.php

//Add Metabox
add_action( 'add_meta_boxes', 'arti_carousel_add_custom_meta_box' );
function arti_carousel_add_custom_meta_box (){
add_meta_box(
'arti_carousel_editor',
__('Carousel', 'arti-carousel'),
'arti_carousel_form',
'arti_carousel',
'normal',
'high'
);

global $post_type;
if( 'arti_carousel' == $post_type ) {
//enqueue
add_action('admin_head', 'arti_carousel_form_style', 50 );
add_action('admin_footer', 'arti_carousel_form_script', 50 );
}
}


function arti_carousel_form( $post ){
wp_nonce_field('arti_carousel_save_meta_box_data', 'arti_carousel_meta_box_nonce');

wp_enqueue_media();

$sections = get_post_meta($post->ID, '_anti_carousels_editor', true);
?>
<div id="carousel-tabs-5">
<ul id="carousel-loop" class="carousel-loop clearfix">
<?php
$now = 0;
foreach($sections as $key=>$item) {
$now++;
$item_title = esc_attr($item['title']);
$item_image = intval($item['image']);
$item_content = esc_html($item['content']);

echo arti_carousel_item($item_title, $item_image, $item_content);
} //endforeach
?>
</ul>
</div>

<input name="addnew" class="button button-primary button-large" id="carousel-addnew" value="Add New" />
<?php
};

add_action('save_post','arti_carousel_save'); //Save Code
function arti_carousel_save( $post_id ){
//Security
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; };
//Nonce-Field Check
if ( ! isset($_POST['arti_carousel_meta_box_nonce'])){ return; }
if( ! wp_verify_nonce($_POST['arti_carousel_meta_box_nonce'], 'arti_carousel_save_meta_box_data')){ return; }
//Nonce-Field Check END
if ( 'arti_carousel' == $_POST['post_type']){
if( !current_user_can( 'edit_page', $post_id) || !current_user_can( 'edit_post', $post_id)){
return;
};
}
else{
return; //another post_type
}
//Security END

$titles = (array) $_POST['carousel_title'];
$images = (array) $_POST['carousel_image'];
$contents = (array) $_POST['carousel_content'];

$_anti_carousels = array();
foreach($titles as $key=>$val){
$_anti_carousels[] = array(
'title' => sanitize_text_field($titles[$key]),
'image' => intval($images[$key]),
'content' => sanitize_textarea_field($contents[$key]),
);
}

update_post_meta($post_id, '_anti_carousels_editor', ($_anti_carousels));

}

function arti_carousel_item($item_title='', $item_image=0, $item_content='') {
$img_src = $item_image>0 ? wp_get_attachment_image( $item_image, 'medium' ) : '';
$item_new = '
<li class="carousel-item clearfix open">
<div class="carousel-header">
<input name="carousel_title[]" class="carousel-title large-text" type="text" value="'.$item_title.'" placeholder="Title" />
<div class="carousel-menu">
<span class="action remove dashicons dashicons-trash"></span>
<span class="action move handle dashicons dashicons-editor-ol"></span>
</div>
</div>

<div class="carousel-body">
<div class="carousel-image photo-item clearfix">
<div class="photo-preview ">'.$img_src.'</div>
<button type="button" class="photo-change button button-secondary">Select Image</button>
<input name="carousel_image[]" class="photo-id" type="hidden" value="'.$item_image.'" />
</div>
<textarea name="carousel_content[]" class="carousel-content large-text" rows="8" placeholder="Write Your Content">'.$item_content.'</textarea>
</div>
</li>';
$item_new = trim(preg_replace('/\s\s+/', ' ', $item_new));

return $item_new;
}

function arti_carousel_form_style() {
?>
<style type="text/css">
#arti_carousel_editor *{-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;}

.carousel-loop{display:block;margin:0;padding:0;list-style:none;}
.carousel-item{display:block;position:relative;background-color:#fff;margin-bottom:12px;border:1px solid #ddd;}

.carousel-header{height:48px;padding:10px 12px;border-bottom:1px solid #ddd;position:relative;box-shadow: 0 2px 6px rgba(0,0,0,.1);}
.carousel-title{margin-right:64px;height:28px;line-height:28px;}

.carousel-body{padding:12px;display:flex;flex-direction: row;flex-wrap: wrap;justify-content: flex-start;justify-content: space-between;}
.carousel-image{flex: 4;}
.carousel-image .photo-preview{background-color:#eee;min-height:180px;margin:0 12px 12px 0;}
.carousel-image img{max-width:100%;height:auto;}
.carousel-item textarea{flex: 6;}

.carousel-menu{position:absolute;right:12px;top:10px;height:28px;}
.carousel-menu .action{display: block;float: left;width: 28px;height: 28px;padding: 3px;border: 1px solid rgba(0,0,0,0.05); margin: 0 0 0 1px; text-align: center;background-color:rgba(200,200,200,0.6)}
.carousel-menu .action{cursor:pointer;}
.carousel-menu .move{cursor:move;}
</style>
<?php
}

function arti_carousel_form_script() {
$item_new = arti_carousel_item();
?>
<script type="text/javascript">
jQuery(document).ready(function($){
//add-item
$('#carousel-addnew').click(function() {
$('#carousel-loop').append( '<?php echo $item_new;?>' );
});
//remove-item
$('.carousel-header .remove').live('click', function() {
if( confirm('Are you sure?') ) {
$(this).closest('.carousel-item').fadeOut(500, function(){$(this).remove();});
}
});
//sortable
$('#carousel-loop').sortable({handle: '.handle'});

//media upload
$( document ).on( 'click', '.photo-change', function() {
var parent = $(this).closest('.photo-item');
file_frame = wp.media.frames.file_frame = wp.media({
frame: 'select',
multiple: false,
library: { type: 'image' },
});

file_frame.on( 'select', function() {
var json = file_frame.state().get('selection').first().toJSON();
console.log( json );
var att_id = json.id;

if(json.sizes.hasOwnProperty('medium')){
var att_url = json.sizes.medium.url;
}else{
var att_url = json.sizes.full.url;
}

//sent-to-form
parent.children('.photo-id').val(att_id);
parent.children('.photo-preview').html('<img src="'+att_url+'" />');
});

file_frame.open();
});
});//jQuery
</script>
<?php
}


User183722 comments:

I am very positively surprised by the complexity of the script. But I will need some time to embed it. If I understand it correctly another Metabox will be created where the sortable elements are. Just briefly, can I continue to use the other Metabox for all the other settings I have already programmed?


timDesain Nanang comments:

I am very positively surprised by the complexity of the script.
the script contains 5 functions: form, saving, new item, style and script.

Just briefly, can I continue to use the other Metabox for all the other settings I have already programmed?
should be no problem


User183722 comments:

Many thanks for the quick answer, it would have cost me a lot of research until I found a practicable solution. Tomorrow i will include it in my Plugin... But i have one short question. Is it still possible to save or update the post securely via Ajax in a simple way? So that the page is not reloaded every time a change is made?


timDesain Nanang comments:

but it will be more complicated

2019-09-21

Arnav Joy answers:

What code you are using ?
Can you show full code ?


User183722 comments:

I have explain a bit more in my question and a bit of code. Full Code would be a bit to much... I need only to know how i can save the new boxes that are duplicated with jquery and a script to the php variables. After that i can use the post informations for the shortcode in frontend... Did you understand what i mean? Here the link for the Script that i use to duplicate the div box with input fields: https://codecanyon.net/item/easy-row-duplication-jquery-plugin/10756407

2019-09-21

User183722 answers:

I use only Wordpress editor. Its only styled by jqueryUI and CSS... For the Content Elements (Rows) i use the following Extension from Codecanyon: https://codecanyon.net/item/easy-row-duplication-jquery-plugin/10756407

With it i can click on Add Row and the Div will completely duplicated. I also can sortable the divs. The Extension allows me to have callbacks for "Add Row" or "Delete Row" and for sortable start and stop...
When i add a row or delete, the results should be saved as a normal input or textfield in the metabox.
I save a field with following code:
if ( isset($_POST['arti_carousel_tab_formattings_items_button_texttransform'])){
update_post_meta( $post_id, 'arti_carousel_tab_formattings_items_button_texttransform', $_POST['arti_carousel_tab_formattings_items_button_texttransform']);
};


Here a bit Code of my Metabox.php, the whole Code would be a bit to much for this site...

<?php
/* Security Check */
if (!defined('ABSPATH')) {
return;
}

// Register Custom Post Type
function arti_carousel_add_post_type() {

$labels = array(
'name' => _x( 'Carousels', 'Post Type General Name', 'arti-carousel' ),
'singular_name' => _x( 'Carousel', 'Post Type Singular Name', 'arti-carousel' ),
'menu_name' => __( 'Arti-Carousels', 'arti-carousel' ),
'name_admin_bar' => __( 'Arti-Carousels', 'arti-carousel' ),
'archives' => __( 'Item Archives', 'arti-carousel' ),
'attributes' => __( 'Item Attributes', 'arti-carousel' ),
'parent_item_colon' => __( 'Parent Item:', 'arti-carousel' ),
'all_items' => __( 'All Items', 'arti-carousel' ),
'add_new_item' => __( 'Add New Item', 'arti-carousel' ),
'add_new' => __( 'Add New', 'arti-carousel' ),
'new_item' => __( 'New Item', 'arti-carousel' ),
'edit_item' => __( 'Edit Item', 'arti-carousel' ),
'update_item' => __( 'Update Item', 'arti-carousel' ),
'view_item' => __( 'View Item', 'arti-carousel' ),
'view_items' => __( 'View Items', 'arti-carousel' ),
'search_items' => __( 'Search Item', 'arti-carousel' ),
'not_found' => __( 'Not found', 'arti-carousel' ),
'not_found_in_trash' => __( 'Not found in Trash', 'arti-carousel' ),
'featured_image' => __( 'Featured Image', 'arti-carousel' ),
'set_featured_image' => __( 'Set featured image', 'arti-carousel' ),
'remove_featured_image' => __( 'Remove featured image', 'arti-carousel' ),
'use_featured_image' => __( 'Use as featured image', 'arti-carousel' ),
'insert_into_item' => __( 'Insert into item', 'arti-carousel' ),
'uploaded_to_this_item' => __( 'Uploaded to this item', 'arti-carousel' ),
'items_list' => __( 'Items list', 'arti-carousel' ),
'items_list_navigation' => __( 'Items list navigation', 'arti-carousel' ),
'filter_items_list' => __( 'Filter items list', 'arti-carousel' ),
);
$args = array(
'label' => __( 'Carousel', 'arti-carousel' ),
'description' => __( 'Post Type Description', 'arti-carousel' ),
'labels' => $labels,
'supports' => false,
'hierarchical' => false,
'supports' => array( 'title' ),
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'can_export' => true,
'has_archive' => true,
'exclude_from_search' => false,
'publicly_queryable' => true,
'capability_type' => 'post',
);
register_post_type( 'arti_carousel', $args );

}

add_action( 'init', 'arti_carousel_add_post_type', 0 );
//Show Metabox
add_action( 'add_meta_boxes', 'arti_carousel_add_custom_meta_box' );
function arti_carousel_add_custom_meta_box (){
add_meta_box(
'arti_carousel_editor',
__('Carousel', 'arti-carousel'),
'arti_carousel_editor',
'arti_carousel',
'normal',
'high'
);
}


function arti_carousel_editor( $post )
{
wp_nonce_field('arti_carousel_save_meta_box_data', 'arti_carousel_meta_box_nonce');
$output = '
<div id="arti-carousel-tabs-5">' /* Carousel Items */ .'
<div class="easyRowDuplicationContainer container">
<div class="arti-carousel-admin-item-holder rowDuplication columns">
<div class="column col-4">
<div class="arti-carousel-admin-item arti-carousel-item-admin-headline">
<label for="arti_carousel_tab_items_headline">'.__('Image', 'arti-carousel').'</label>
<input type="text" name="arti_carousel_image" class="arti_carousel_image" value="'.esc_html(get_post_meta($post->ID, 'arti_carousel_image', true)).'"/>
<input type="button" class="arti_carousel_image_button" value="'.__('Upload','arti-carousel').'" data-uploader_title="'.__('File Upload','arti-carousel').'" data-uploader_button_text="'.__('Choose File','arti-carousel').'" />
</div>
</div>
<div class="column col-4">
<div class="arti-carousel-admin-item arti-carousel-item-admin-headline">
<label for="arti_carousel_tab_items_headline">'.__('Headline', 'arti-carousel').'</label>
<input placeholder="'.__('Headline 1', 'arti-carousel').'" name="arti_carousel_tab_items_headline" value="'.esc_html(get_post_meta($post->ID, 'arti_carousel_tab_items_headline', true)).'">
</div>
<div class="arti-carousel-admin-item arti-carousel-item-admin-textarea">
<label for="arti_carousel_tab_items_textarea">'.__('Text', 'arti-carousel').'</label>
<textarea rows="15" placeholder="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." name="arti_carousel_tab_items_textarea">'.esc_html(get_post_meta($post->ID, 'arti_carousel_tab_items_textarea', true)).'</textarea>
</div>
</div>
<div class="column col-4">

</div>
</div>
</div>
</div>
';
echo $output;
};

add_action('save_post','arti_carousel_save'); //Save Code
function arti_carousel_save( $post_id )
{
//Security
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
};
//Nonce-Field Check
if ( ! isset($_POST['arti_carousel_meta_box_nonce'])){
return;
}
if( ! wp_verify_nonce($_POST['arti_carousel_meta_box_nonce'], 'arti_carousel_save_meta_box_data')){
return;
}
//Nonce-Field Check END
if ( 'arti_carousel' == $_POST['post_type']){
if( !current_user_can( 'edit_page', $post_id) || !current_user_can( 'edit_post', $post_id)){
return;
};
};
//Security END

//Fields - Basic Settings
include('metabox-save/fields-basic-setings.php');
//Fields - Formattings
include('metabox-save/fields-formattings.php');
//Load CSS Code for File
include('metabox-save/getCSS.php');

cssfile($post_id,$cssFile);

}