How to add new panel under "document" in Gutenberg - wordpress

I am trying to add a new component panel under document tab, like categories, featured image etc.

They've added the PluginDocumentSettingPanel SlotFill now.
const { registerPlugin } = wp.plugins
const { PluginDocumentSettingPanel } = wp.editPost
const PluginDocumentSettingPanelDemo = () => (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
Custom Panel Contents
</PluginDocumentSettingPanel>
)
registerPlugin('plugin-document-setting-panel-demo', {
render: PluginDocumentSettingPanelDemo
})

add_meta_box will do the trick, but only if you add the context-argument with a value of 'side':
add_meta_box(
'box-id-here',
'Box Title Here',
'createBoxHtml',
'post',
'side' ); // <-- this is important
Arrrh, two days for nothing!
Old answer
According to this tutorial, we can add our custom sidebar and fill it with customized form inputs.
Here is a working example in a React JSX version. This adds a meta field country:
const { registerPlugin } = wp.plugins;
const { PluginSidebar } = wp.editPost;
const { TextControl } = wp.components;
const { withSelect, withDispatch } = wp.data;
// Customized TextControl
const CustomMetaField = withDispatch( ( dispatch, props ) => {
return {
updateMetaValue: ( v ) => {
dispatch( 'core/editor' ).editPost( {
meta: {
[ props.metaFieldName ]: v
}
});
}
};
})( withSelect( ( select, props ) => {
return {
[ props.metaFieldName ]: select( 'core/editor' ).getEditedPostAttribute( 'meta' )[ props.metaFieldName ]
};
} )( ( props ) => (
<TextControl
value={props[ props.metaFieldName ] }
label="Country"
onChange={( v ) => {
props.updateMetaValue( v );
}}
/> )
) );
// Our custom sidebar
registerPlugin( 'custom-sidebar', {
render() {
return (
<PluginSidebar
name="project-meta-sidebar"
title="Project Meta">
<div className="plugin-sidebar-content">
<CustomMetaField metaFieldName="country" />
</div>
</PluginSidebar>
);
},
} );
And in PHP, register the meta field in the init-hook:
register_meta( 'post', 'country', [
'show_in_rest' => TRUE,
'single' => TRUE,
'type' => 'string'
] );
I know:
This is still not the required solution, but nearly.

You can now use the newer useSelect and useDispatch custom hooks. They are similar to withSelect and withDispatch, but utilize custom hooks from React 16.8 for a slightly more concise dev experience:
(Also, using #wordpress/scripts, so the imports are from the npm packages instead of the wp object directly, but either would work.)
import { __ } from '#wordpress/i18n';
import { useSelect, useDispatch } from '#wordpress/data';
import { PluginDocumentSettingPanel } from '#wordpress/edit-post';
import { TextControl } from '#wordpress/components';
const TextController = (props) => {
const meta = useSelect(
(select) =>
select('core/editor').getEditedPostAttribute('meta')['_myprefix_text_metafield']
);
const { editPost } = useDispatch('core/editor');
return (
<TextControl
label={__("Text Meta", "textdomain")}
value={meta}
onChange={(value) => editPost({ meta: { _myprefix_text_metafield: value } })}
/>
);
};
const PluginDocumentSettingPanelDemo = () => {
return (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
<TextController />
</PluginDocumentSettingPanel>
);
};
export default PluginDocumentSettingPanelDemo;
Along with registering your meta field as usual:
function myprefix_register_meta()
{
register_post_meta('post', '_myprefix_text_metafield', array(
'show_in_rest' => true,
'type' => 'string',
'single' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => function () {
return current_user_can('edit_posts');
}
));
}
add_action('init', 'myprefix_register_meta');
And make sure if using for a custom post type, that you include custom-fields in the array of supports:
'supports' => array('title', 'editor', 'thumbnail', 'revisions', 'custom-fields'),
Hopefully that helps.

You can add this code to your function.php. This code create new tab and add text field to this tab. Text field save to database like custom field in post_meta table and you can output this like default WP post meta.
1. Create tab Настройки UTM.
2. Create custom text field utm_post_class
3. To output in website use $utm = get_post_meta( $post->ID, 'utm_post_class', true );
//Article UTM Link
add_action( 'load-post.php', 'utm_post_meta_boxes_setup' );
add_action( 'load-post-new.php', 'utm_post_meta_boxes_setup' );
function utm_post_meta_boxes_setup() {
add_action( 'add_meta_boxes', 'utm_add_post_meta_boxes' );
add_action( 'save_post', 'utm_save_post_class_meta', 10, 2 );
}
function utm_add_post_meta_boxes() {
add_meta_box(
'utm-post-class',
'Настройки UTM',
'utm_post_class_meta_box',
'post',
'side',
'default'
);
}
function utm_post_class_meta_box( $post ) {
wp_nonce_field( basename( __FILE__ ), 'utm_post_class_nonce' );?>
<div class="components-base-control editor-post-excerpt__textarea">
<div class="components-base-control__field">
<label class="components-base-control__label" for="utm-post-class">UTM ссылка (необязательно)</label>
<input type="text" name="utm-post-class" id="utm-post-class" class="edit-post-post-schedule" value="<?php echo esc_attr( get_post_meta( $post->ID, 'utm_post_class', true ) ); ?>">
</div>
</div>
<?php }
function utm_save_post_class_meta( $post_id, $post ) {
if ( !isset( $_POST['utm_post_class_nonce'] ) || !wp_verify_nonce( $_POST['utm_post_class_nonce'], basename( __FILE__ ) ) )
return $post_id;
$post_type = get_post_type_object( $post->post_type );
if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
return $post_id;
$new_meta_value = ( isset( $_POST['utm-post-class'] ) ? $_POST['utm-post-class'] : '' );
$meta_key = 'utm_post_class';
$meta_value = get_post_meta( $post_id, $meta_key, true );
if ( $new_meta_value && '' == $meta_value )
add_post_meta( $post_id, $meta_key, $new_meta_value, true );
elseif ( $new_meta_value && $new_meta_value != $meta_value )
update_post_meta( $post_id, $meta_key, $new_meta_value );
elseif ( '' == $new_meta_value && $meta_value )
delete_post_meta( $post_id, $meta_key, $meta_value );
}

add_meta_box adds a new panel there for the gutenberg editor

Related

Wordpress plugin can not added to the page

I am new with wordpress, I create a image uploader which followed a youtube video. But I found that it is only showed when I create new page. I can not add the uploader to the new page.
This is my code:
For php file
namespace image_uploader;
function register_metaboxes() {
add_meta_box('image_metabox','Image Uploader', __NAMESPACE__ . '\image_uploader_callback');
}
add_action('add_meta_boxes', __NAMESPACE__ . '\register_metaboxes');
function register_admin_script() {
wp_enqueue_script('wp_img_upload', plugins_url('image-upload.js', __FILE__), array('jquery', 'media-upload'), '1.0', true);
}
add_action('admin_enqueue_scripts', __NAMESPACE__ . '\register_admin_script');
function image_uploader_callback( $post_id ) {
wp_nonce_field( basename( __FILE__ ), 'image_nonce' );
$image_stored_meta = get_post_meta( $post_id );
?>
<div class="image-preview-wrapper">
<img id="image-preview" src="<?php if ( isset ( $image_stored_meta['image_meta'] ) ) echo $image_stored_meta['image_meta'][0]; ?>" style="max-width: 250px;">
<input type="hidden" name="image_meta" id="image-meta">
<button type="button" id="image-upload-button" class="button">Upload Image</button>
<button type="button" id="image-remove-button" class="button">Remove Image</button>
</div>
<button id="nextPage">move to the next page</button>
<?php
}
function save_custom_meta( $post_id, $post, $update ) {
// Checks save status
$is_autosave = wp_is_post_autosave( $post_id );
$is_revision = wp_is_post_revision( $post_id );
$is_valid_nonce = ( isset( $_POST[ 'image_nonce' ] ) && wp_verify_nonce( $_POST[ 'image_nonce' ], basename( __FILE__ ) ) ) ? 'true' : 'false';
// Exits script depending on save status
if ( $is_autosave || $is_revision || !$is_valid_nonce ) {
return;
}
// Checks for input and sanitizes/saves if needed
if( isset( $_POST[ 'image_meta' ] ) ) {
$image_data = json_decode( stripslashes( $_POST[ 'image_meta' ] ), true );
if(is_object($image_data)) {
$image_data = array(
'id' => intval($image_data[0]->id),
'src' => esc_url_raw($image_data[0]->url),
'width' => intval($image_data[0]->width),
'height' => intval($image_data[0]->height)
);
} else {
$image_data=[];
}
update_post_meta( $post_id, 'image_meta', sanitize_text_field( $_POST[ 'image_meta' ] ) );
}
}
add_action( 'save_post', __NAMESPACE__ . '\save_custom_meta', 10, 3 );
add_filter('wp_handle_upload_prefilter','tc_handle_upload_prefilter');
function tc_handle_upload_prefilter($file)
{
$img=getimagesize($file['tmp_name']);
$fixedSize = array('width' => '400', 'height' => '600');
$width= $img[0];
$height =$img[1];
if ($width != $fixedSize['width'] )
return array("error"=>"Image dimensions are too small. Minimum width is {$fixedSize['width']}px. Uploaded image width is $width px");
elseif ($height != $fixedSize['height'])
return array("error"=>"Image dimensions are too small. Minimum height is {$fixedSize['height']}px. Uploaded image height is $height px");
else
return $file;
}
for js file
addEventListener("DOMContentLoaded", function() {
console.log('DOMContentLoaded');
var addButton = document.getElementById('image-upload-button');
var removeButton = document.getElementById('image-remove-button');
var image = document.getElementById('image-preview');
var hidden = document.getElementById('image-meta');
var next = document.getElementById('nextPage');
image.setAttribute('required', 'required');
var uploader = wp.media({
title: 'Select an image',
button: {
text: 'Use this image'
},
multiple: false
});
addButton.addEventListener('click', function(e) {
e.preventDefault();
if(uploader) {
uploader.open();
}
});
uploader.on('select', function() {
var attachment = uploader.state().get('selection').first().toJSON();
image.setAttribute('src', attachment.url);
hidden.setAttribute('value', JSON.stringify({id: attachment.id, url: attachment.url}));
});
removeButton.addEventListener('click', function(e) {
image.removeAttribute('src');
hidden.removeAttribute('value');
});
next.addEventListener('click', function(e) {
e.preventDefault();
window.location.href = "http://google.com";
});
});
I did a lot of research, but still can not figure it out.
Please give me some advices, thanks a lot!

Gutenberg server side rendered (dynamic) block - attributes don't update in editor

I'm making Wordpress server side rendered block and it works well on frontend, but in editor attributes don't save (I have always default value in editor, although on frontend there is my saved value).
This is my code (not whole but minimal reproducible).
Register block on client side and set block options in editor:
const { __ } = wp.i18n;
const { ServerSideRender } = wp.editor;
const { InspectorControls } = wp.blockEditor;
const { PanelBody, __experimentalNumberControl: NumberControl } = wp.components;
registerBlockType(
'mysite/trainings',
{
title: __( 'Trainings list', 'mysite' ),
attributes: {
postsCount: {
type: 'number',
default: 9,
}
},
edit: ( { attributes, setAttributes } ) => {
const { postsCount } = attributes;
return (
<>
<InspectorControls>
<PanelBody
title={ __( 'Set number of displayed trainings', 'mysite' ) }
>
<NumberControl
value={ postsCount }
onChange={ ( value ) => setAttributes( { postsCount: value } ) }
min={ 1 }
max={ 9 }
/>
</PanelBody>
</InspectorControls>
<ServerSideRender
block="mysite/trainings"
attributes={ {
postsCount: 9,
} }
/>
</>
);
},
save() {
return null;
},
}
);
Register and render block on server side:
add_action( 'init', 'register_trainings_block' );
function register_trainings_block() {
register_block_type(
'mysite/trainings',
array(
'api_version' => 2,
'editor_script' => 'sm_editor_script',
'render_callback' => 'render_trainings_block',
'attributes' => array(
'postsCount' => array(
'type' => 'number',
'default' => 9,
),
),
)
);
}
function render_trainings_block( $attributes ) {
$query_args = array(
'post__in' => array(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10 // IDs of posts
),
'post_type' => 'sm_training',
'orderby' => 'post__in',
'paged' => '1'
);
$posts = new WP_Query( $query_args );
$output = '<section class="wp-block-mysite-trainings">';
$i = 0;
foreach ( $posts->posts as $post ) {
if ( $i < $attributes['postsCount'] ) {
ob_start();
$output .= get_template_part( 'template-parts/content/training' );
$output .= ob_get_clean();
}
$i++;
}
$output .= '</section>';
return $output;
}
Enqueue editor script:
add_action( 'enqueue_block_editor_assets', 'load_editor_scripts' );
public function load_editor_scripts() {
wp_enqueue_script( 'sm_editor_script', get_template_directory_uri() . '/assets/dist/js/editor.js', array(
'wp-blocks',
'wp-i18n',
'wp-editor',
'wp-components',
'wp-block-editor'
), '1.0.0', true );
wp_localize_script( 'sm_editor_script', 'gutenbergBlocks', array( 'themeUrl' => get_template_directory_uri() ) );
}
What am I missing?
I know :)
Two things:
It should be:
<ServerSideRender
block="mysite/trainings"
attributes={ { postsCount } }
/>
(without default value here)
If attribute is number, you have to ensure that it will be saved as number.
In js change in onChange function:
<NumberControl
value={ postsCount }
onChange={ ( value ) => setAttributes( { postsCount: Number.parseInt( value ) } ) }
min={ 1 }
max={ 9 }
/>
and in php render_trainings_block function:
$attributes['postsCount'] = (int) $attributes['postsCount'];

Add a checkbox as WooCommerce admin product option that disables payment gateways

I'm trying to unset COD payment gateway based on a custom product type based on the value from the checkbox, added as WooCommerce admin product option.
But it seems the code doesn't do anything with product type: doarcard.
If I set it to simple then it will work:
//new product type
add_filter("product_type_options", function ($product_type_options) {
$product_type_options['doarcard'] = array(
'id' => '_doarcard',
'wrapper_class' => 'show_if_simple show_if_variable',
'label' => __( 'Doar Card', 'woodmart' ),
'description' => __( 'Activare doar plata cu card sau transfer bancar', 'woodmart' ),
'default' => 'no');
return $product_type_options;
});
add_action("save_post_product", function ($post_ID, $product, $update) {
update_post_meta(
$product->ID
, "_doarcard"
, isset($_POST["_doarcard"]) ? "yes" : "no");
}, 10, 3);
//disable cod for doarcard
add_filter('woocommerce_available_payment_gateways', 'conditional_payment_gateways', 10, 1);
function conditional_payment_gateways( $available_gateways ) {
if( is_admin() )
return $available_gateways;
$prod_doarcard = false;
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = wc_get_product($cart_item['product_id']);
// Get the product types in cart (example)
if($product->is_type('doarcard')) $prod_doarcard = true;
}
if($prod_doarcard)
unset($available_gateways['cod']); // unset 'cod'
return $available_gateways;
}
Any advice?
A custom product type has nothing to do with your question. The value of the checkbox is a boolean with value yes or no
and based on that you can then unset the $payment_gateways
So use:
// Add a checkbox as WooCommerce admin product option
function filter_product_type_options( $product_type_options ) {
$product_type_options['doarcard'] = array(
'id' => '_doarcard',
'wrapper_class' => 'show_if_simple show_if_variable',
'label' => __( 'Doar Card', 'woocommerce' ),
'description' => __( 'Activare doar plata cu card sau transfer bancar', 'woocommerce' ),
'default' => 'no',
);
return $product_type_options;
}
add_filter( 'product_type_options', 'filter_product_type_options', 10, 1 );
// Save checkbox
function action_woocommerce_admin_process_product_object( $product ) {
$product->update_meta_data( '_doarcard', isset( $_POST['_doarcard'] ) ? 'yes' : 'no' );
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
// Payment gateways
function filter_woocommerce_available_payment_gateways( $payment_gateways ) {
// Not on admin
if ( is_admin() ) return $payment_gateways;
// Initialize
$prod_doarcard = false;
// WC Cart
if ( WC()->cart ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// Get meta
$doarcard = $cart_item['data']->get_meta( '_doarcard', true );
// Equal to yes = checked
if ( $doarcard == 'yes' ) {
$prod_doarcard = true;
// Product present with the right condition, so break the loop
break;
}
}
// True
if ( $prod_doarcard ) {
// Cod
if ( isset( $payment_gateways['cod'] ) ) {
unset( $payment_gateways['cod'] );
}
}
}
return $payment_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );
you should use unset inside foreach loop like this:
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = wc_get_product($cart_item['product_id']);
// Get the product types in cart (example)
if($product->is_type('doarcard')){
unset($available_gateways['cod']); // unset 'cod'
}
}

Refresh shipping rates on city select field

I am trying to update/refresh the shipping rates on city change, so far I have managed to do so only by refreshing the page manually.
add_action( 'woocommerce_package_rates', 'check_minimum_and_city', 10, 2 );
function check_minimum_and_city($rates, $package){
$selected_city = WC()->checkout->get_value('billing_city');
$price_thirty = array('bat-yam','hulon','azur','tel-aviv-yafo','givatayim','ramat-gan','bnei-brak','rishon-letzion','netaim','yavne','kfar-nagid','galiya','ben-zakai','beit-gamliel');
$price_fifty = array('einot','gan-shlomo','beit-oved','aseret','givat-brener','irus','misgav-dov','givton','kerem-yavne','beit-raban','rehovot','beit-elezri','beit-hanan','kvuzat-yavne','kfar-bilu','bnei-darom','nir-galim','kiryat-ekron','gedera','nes-tziona','kanot','gan-darom','netayim','mishmar-hashiva','gan-sorek','beit-dagan','ganot','beit-hanan-irus','hemed');
$price_sixty = array('savion','ganei-tikva','or-yehuda','kiryat-ono','yehud','petah-tikva','ramat-hasharon','herzliya','kfar-shmariyahu','rishpon','raanana','kfar-saba','tsafria','beer-yaakov','netser-sireni','nir-tzvi','ramla','matsliax','bnaya','kfar-aviv');
if(WC()->session->get( 'chosen_shipping_methods' )[0] == 'local_pickup:13'){
$minimum = 0;
}else{
$minimum_thirty = 100;
$minimum_fifty = 150;
$minimum_sixty = 200;
if(in_array($selected_city, $price_thirty)){
unset( $rates['flat_rate:18']);
unset( $rates['flat_rate:19']);
if(WC()->cart->subtotal < $minimum_thirty){
throw new Exception(
sprintf( 'סכום ההזמנה הנוכחית שלך עומד על %s, מינימום הזמנה לפני משלוח הינו %s.' ,
wc_price( WC()->cart->subtotal ),
wc_price( $minimum_thirty )
)
);
}
}elseif(in_array($selected_city, $price_fifty)){
unset( $rates['flat_rate:9']);
unset( $rates['flat_rate:19']);
if(WC()->cart->subtotal < $minimum_fifty){
throw new Exception(
sprintf( 'סכום ההזמנה הנוכחית שלך עומד על %s, מינימום הזמנה לפני משלוח הינו %s.' ,
wc_price( WC()->cart->subtotal ),
wc_price( $minimum_fifty )
)
);
}
}elseif(in_array($selected_city, $price_sixty)){
unset( $rates['flat_rate:9']);
unset( $rates['flat_rate:18']);
if(WC()->cart->subtotal < $minimum_sixty){
throw new Exception(
sprintf( 'סכום ההזמנה הנוכחית שלך עומד על %s, מינימום הזמנה לפני משלוח הינו %s.' ,
wc_price( WC()->cart->subtotal ),
wc_price( $minimum_sixty )
)
);
}
}
return $rates;
}
}
When I select a city field (dropdown custom list) I get the shipping cost I have made through the woocommerce settings but when I change it it does not update the rates.
add_filter( 'woocommerce_checkout_fields', 'city_dropdown_field' );
function city_dropdown_field( $fields ) {
$city_args = wp_parse_args( array(
'type' => 'select',
'options' => array(
'' => '',
'yavne' => 'יבנה',
'kfar-nagid' => 'כפר הנגיד',
'galiya' => 'גאליה',
'ben-zakai' => 'בן זכאי',
'beit-gamliel' => 'בית גמליאל',
'bnaya' => 'בניה',
'einot' => 'עינות',
'kfar-aviv' => 'כפר אביב',
'gan-shlomo' => 'גן שלמה',
'beit-oved' => 'בית עובד',
'aseret' => 'עשרת',
'givat-brener' => 'גבעת ברנר',
'irus' => 'אירוס',
'misgav-dov' => 'משגב דב',
'givton' => 'גיבתון',
'kerem-yavne' => 'כרם יבנה',
'beit-raban' => 'בית רבן',
'rehovot' => 'רחובות',
'beit-elezri' => 'בית אלעזרי',
'beit-hanan' => 'בית חנן',
'kvuzat-yavne' => 'קבוצת יבנה',
'kfar-bilu' => 'כפר בילו',
'bnei-darom' => 'בני דרום',
'nir-galim' => 'ניר גלים',
'kiryat-ekron' => 'קרית עקרון',
'gedera' => 'גדרה',
'nes-tziona' => 'נס ציונה',
'kanot' => 'כנות',
'netayim' => 'נטעים',
'gan-darom' => 'גן דרום',
'givatayim' => 'גבעתיים',
'ramat-gan' => 'רמת גן',
'tel-aviv-yafo' => 'תל אביב - יפו',
'bnei-brak' => 'בני ברק',
'ramat-hasharon' => 'רמת השרון',
'herzliya' => 'הרצליה',
'kfar-shmariyahu' => 'כפר שמריהו',
'rishpon' => 'רישפון',
'raanana' => 'רעננה',
'kfar-saba' => 'כפר סבא',
'bat-yam' => 'בת ים',
'hulon' => 'חולון',
'azur' => 'אזור',
'savion' => 'סביון',
'ganei-tikva' => 'גני תקווה',
'or-yehuda' => 'אור יהודה',
'kiryat-ono' => 'קרית אונו',
'yehud' => 'יהוד',
'petah-tikva' => 'פתח תקווה',
'rishon-letzion' => 'ראשון לציון',
'mishmar-hashiva' => 'משמר השבעה',
'gan-sorek' => 'גן שורק',
'beit-dagan' => 'בית דגן',
'ganot' => 'גנות',
'beit-hanan-irus' => 'בית חנן אירוס',
'hemed' => 'חמד',
'tsafria' => 'צפריה',
'beer-yaakov' => 'באר יעקב',
'netser-sireni' => 'נצר סירני',
'nir-tzvi' => 'ניר צבי',
'ramla' => 'רמלה',
'matsliax' => 'מצליח',
'clear' => true
),
), $fields['shipping']['shipping_city'] );
$fields['shipping']['shipping_city'] = $city_args;
$fields['billing']['billing_city'] = $city_args;
return $fields;
}
Tried using this jQuery but nothing does the work
add_action( 'wp_footer', 'checkout_shipping_city_refresh_display' );
function checkout_shipping_city_refresh_display() {
// On checkout
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?><script type="text/javascript">
jQuery( function($){
// Shipping fias code change & input events
$(document.body).on( 'change', 'select[name=billing_city]', function() {
console.log($(this).val());
});
});
</script>
<?php
endif;
}
Help is appreciated. :-)
I have Managed to resolve the issue and here is my solution, the answer was in corrected AJAX call and changing from multiple shipping rates to one and changing the rate by code.
add_action('woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
WC()->cart->calculate_shipping();
}
add_action( 'wp_footer', 'checkout_shipping_city_refresh_display' );
function checkout_shipping_city_refresh_display() {
// On checkout
if ( is_checkout() && ! is_wc_endpoint_url() ) :
?><script type="text/javascript">
jQuery(document).on('change', 'select[name=billing_city]', function(){
var requested_city = jQuery(this).val();
ajaxurl = '<?php echo admin_url( 'admin-ajax.php' ) ?>'; // get ajaxurl
var data = {
'action': 'get_and_set_shipping_rate',
'city': requested_city
};
jQuery.ajax({
type: "POST",
url: ajaxurl, // this will point to admin-ajax.php
data: data,
async: false,
success: function (response) {
console.log(response);
setTimeout(function (){
jQuery('.shipping_method:checked').trigger('change');
});
}
});
});
</script>
<?php
endif;
}
function get_and_set_shipping_rate(){
$shipping_city = $_POST['city'];
$shipping_cost = get_shipping_cost_by_city($shipping_city);
setcookie('shipping_city_cost', $shipping_cost, time() + (86400 * 30), '/');
$_COOKIE['shipping_city_cost'] = $shipping_cost;
echo $shipping_cost;
wp_die();
}
add_action( 'wp_ajax_get_and_set_shipping_rate', 'get_and_set_shipping_rate' );
add_action( 'wp_ajax_nopriv_get_and_set_shipping_rate', 'get_and_set_shipping_rate' );
function get_shipping_cost_by_city( $city ) {
$cost = 30;
$price_thirty = array('bat-yam','hulon','azur','tel-aviv-yafo','givatayim','ramat-gan','bnei-brak','rishon-letzion','netaim','yavne','kfar-nagid','galiya','ben-zakai','beit-gamliel');
$price_fifty = array('einot','gan-shlomo','beit-oved','aseret','givat-brener','irus','misgav-dov','givton','kerem-yavne','beit-raban','rehovot','beit-elezri','beit-hanan','kvuzat-yavne','kfar-bilu','bnei-darom','nir-galim','kiryat-ekron','gedera','nes-tziona','kanot','gan-darom','netayim','mishmar-hashiva','gan-sorek','beit-dagan','ganot','beit-hanan-irus','hemed');
$price_sixty = array('savion','ganei-tikva','or-yehuda','kiryat-ono','yehud','petah-tikva','ramat-hasharon','herzliya','kfar-shmariyahu','rishpon','raanana','kfar-saba','tsafria','beer-yaakov','netser-sireni','nir-tzvi','ramla','matsliax','bnaya','kfar-aviv');
// SET HERE the default cost (when "calculated cost" is not yet defined)
if(in_array($city, $price_thirty)){
$cost = 30;
}elseif(in_array($city, $price_fifty)){
$cost = 50;
}elseif(in_array($city, $price_sixty)){
$cost = 60;
}
return $cost;
}
add_filter('woocommerce_package_rates', 'update_shipping_costs_based_on_cart_session_custom_data', 10, 2);
function update_shipping_costs_based_on_cart_session_custom_data( $rates, $package ){
$selected_city = WC()->checkout->get_value('billing_city');
$calculated_cost = get_shipping_cost_by_city($selected_city);
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return $rates;
// SET HERE the default cost (when "calculated cost" is not yet defined)
$cost = '30';
// Iterating though Shipping Methods
foreach ( $rates as $rate_key => $rate_values ) {
$method_id = $rate_values->method_id;
$rate_id = $rate_values->id;
// For "Flat rate" Shipping" Method only
if ( 'flat_rate' === $method_id ) {
if( ! empty( $calculated_cost ) ) {
$cost = $calculated_cost;
}
// Set the rate cost
$rates[$rate_id]->cost = number_format($rates[$rate_id]->cost * $cost, 2);
WC()->session->set( 'shipping_calculated_cost', $rates[$rate_id]->cost );
// Taxes rate cost (if enabled)
foreach ($rates[$rate_id]->taxes as $key => $tax){
if( $rates[$rate_id]->taxes[$key] > 0 ){ // set the new tax cost
$taxes[$key] = number_format( $rates[$rate_id]->taxes[$key] * $cost, 2 );
$has_taxes = true;
} else {
$has_taxes = false;
}
}
if( $has_taxes )
$rates[$rate_id]->taxes = $taxes;
}
}
return $rates;
}

How can I add panels to the sidebar on the Document tab in Gutenberg? [duplicate]

I am trying to add a new component panel under document tab, like categories, featured image etc.
They've added the PluginDocumentSettingPanel SlotFill now.
const { registerPlugin } = wp.plugins
const { PluginDocumentSettingPanel } = wp.editPost
const PluginDocumentSettingPanelDemo = () => (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
Custom Panel Contents
</PluginDocumentSettingPanel>
)
registerPlugin('plugin-document-setting-panel-demo', {
render: PluginDocumentSettingPanelDemo
})
add_meta_box will do the trick, but only if you add the context-argument with a value of 'side':
add_meta_box(
'box-id-here',
'Box Title Here',
'createBoxHtml',
'post',
'side' ); // <-- this is important
Arrrh, two days for nothing!
Old answer
According to this tutorial, we can add our custom sidebar and fill it with customized form inputs.
Here is a working example in a React JSX version. This adds a meta field country:
const { registerPlugin } = wp.plugins;
const { PluginSidebar } = wp.editPost;
const { TextControl } = wp.components;
const { withSelect, withDispatch } = wp.data;
// Customized TextControl
const CustomMetaField = withDispatch( ( dispatch, props ) => {
return {
updateMetaValue: ( v ) => {
dispatch( 'core/editor' ).editPost( {
meta: {
[ props.metaFieldName ]: v
}
});
}
};
})( withSelect( ( select, props ) => {
return {
[ props.metaFieldName ]: select( 'core/editor' ).getEditedPostAttribute( 'meta' )[ props.metaFieldName ]
};
} )( ( props ) => (
<TextControl
value={props[ props.metaFieldName ] }
label="Country"
onChange={( v ) => {
props.updateMetaValue( v );
}}
/> )
) );
// Our custom sidebar
registerPlugin( 'custom-sidebar', {
render() {
return (
<PluginSidebar
name="project-meta-sidebar"
title="Project Meta">
<div className="plugin-sidebar-content">
<CustomMetaField metaFieldName="country" />
</div>
</PluginSidebar>
);
},
} );
And in PHP, register the meta field in the init-hook:
register_meta( 'post', 'country', [
'show_in_rest' => TRUE,
'single' => TRUE,
'type' => 'string'
] );
I know:
This is still not the required solution, but nearly.
You can now use the newer useSelect and useDispatch custom hooks. They are similar to withSelect and withDispatch, but utilize custom hooks from React 16.8 for a slightly more concise dev experience:
(Also, using #wordpress/scripts, so the imports are from the npm packages instead of the wp object directly, but either would work.)
import { __ } from '#wordpress/i18n';
import { useSelect, useDispatch } from '#wordpress/data';
import { PluginDocumentSettingPanel } from '#wordpress/edit-post';
import { TextControl } from '#wordpress/components';
const TextController = (props) => {
const meta = useSelect(
(select) =>
select('core/editor').getEditedPostAttribute('meta')['_myprefix_text_metafield']
);
const { editPost } = useDispatch('core/editor');
return (
<TextControl
label={__("Text Meta", "textdomain")}
value={meta}
onChange={(value) => editPost({ meta: { _myprefix_text_metafield: value } })}
/>
);
};
const PluginDocumentSettingPanelDemo = () => {
return (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Panel"
className="custom-panel"
>
<TextController />
</PluginDocumentSettingPanel>
);
};
export default PluginDocumentSettingPanelDemo;
Along with registering your meta field as usual:
function myprefix_register_meta()
{
register_post_meta('post', '_myprefix_text_metafield', array(
'show_in_rest' => true,
'type' => 'string',
'single' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => function () {
return current_user_can('edit_posts');
}
));
}
add_action('init', 'myprefix_register_meta');
And make sure if using for a custom post type, that you include custom-fields in the array of supports:
'supports' => array('title', 'editor', 'thumbnail', 'revisions', 'custom-fields'),
Hopefully that helps.
You can add this code to your function.php. This code create new tab and add text field to this tab. Text field save to database like custom field in post_meta table and you can output this like default WP post meta.
1. Create tab Настройки UTM.
2. Create custom text field utm_post_class
3. To output in website use $utm = get_post_meta( $post->ID, 'utm_post_class', true );
//Article UTM Link
add_action( 'load-post.php', 'utm_post_meta_boxes_setup' );
add_action( 'load-post-new.php', 'utm_post_meta_boxes_setup' );
function utm_post_meta_boxes_setup() {
add_action( 'add_meta_boxes', 'utm_add_post_meta_boxes' );
add_action( 'save_post', 'utm_save_post_class_meta', 10, 2 );
}
function utm_add_post_meta_boxes() {
add_meta_box(
'utm-post-class',
'Настройки UTM',
'utm_post_class_meta_box',
'post',
'side',
'default'
);
}
function utm_post_class_meta_box( $post ) {
wp_nonce_field( basename( __FILE__ ), 'utm_post_class_nonce' );?>
<div class="components-base-control editor-post-excerpt__textarea">
<div class="components-base-control__field">
<label class="components-base-control__label" for="utm-post-class">UTM ссылка (необязательно)</label>
<input type="text" name="utm-post-class" id="utm-post-class" class="edit-post-post-schedule" value="<?php echo esc_attr( get_post_meta( $post->ID, 'utm_post_class', true ) ); ?>">
</div>
</div>
<?php }
function utm_save_post_class_meta( $post_id, $post ) {
if ( !isset( $_POST['utm_post_class_nonce'] ) || !wp_verify_nonce( $_POST['utm_post_class_nonce'], basename( __FILE__ ) ) )
return $post_id;
$post_type = get_post_type_object( $post->post_type );
if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
return $post_id;
$new_meta_value = ( isset( $_POST['utm-post-class'] ) ? $_POST['utm-post-class'] : '' );
$meta_key = 'utm_post_class';
$meta_value = get_post_meta( $post_id, $meta_key, true );
if ( $new_meta_value && '' == $meta_value )
add_post_meta( $post_id, $meta_key, $new_meta_value, true );
elseif ( $new_meta_value && $new_meta_value != $meta_value )
update_post_meta( $post_id, $meta_key, $new_meta_value );
elseif ( '' == $new_meta_value && $meta_value )
delete_post_meta( $post_id, $meta_key, $meta_value );
}
add_meta_box adds a new panel there for the gutenberg editor

Resources