How to nest 2 third-party Wordpress shortcodes - wordpress

I'm looking to make a progress bar with shortcode that requires a percentage to determine its 'progress'. However, I'm getting my percentage from another piece of shortcode.
When I nest the two shortcodes, they fail. Can someone help me please?
Below is the two code snippets in the plugin's shortcode file, first is the progress bar...
function fruitful_pbar_shortcode ($atts, $content = null) {
$out = $type = $class = '';
extract(shortcode_atts(array(
'id' => 'ffs-pbar-' . rand( 1, 100 ),
'type' => '',
'active' => false,
'stripped' => false
), $atts));
if (!empty($id)) { $id = sanitize_html_class($id); }
if (!empty($type)) { $type = sanitize_html_class($type); }
if (!empty($active)) { $active = sanitize_html_class($active); }
if (!empty($stripped)) { $stripped = sanitize_html_class($stripped); }
$class .= $type;
if ($stripped) { $class .= ' progress-striped'; }
if ($active) { $class .= ' active'; }
$out .= '<div id="'.$id.'" class="progress '.$class.'">';
$out .= fruitful_sh_esc_content_pbr(do_shortcode($content));
$out .= '</div>';
$out .= '<div class="clearfix"></div>';
return $out;
}
add_shortcode ("fruitful_pbar", "fruitful_pbar_shortcode");
function fruitful_bar_shortcode ( $atts, $content = null ) {
$type = $width = '';
extract(shortcode_atts(array(
'type' => '',
'width' => '60%'
), $atts));
if (!empty($type)) { $type = sanitize_html_class($type); }
if (!empty($width)) { $width = esc_attr($width); }
return '<div class="bar '.$type.'" style="width: '.do_shortcode($width).';"></div>';
}
add_shortcode( 'fruitful_bar', 'fruitful_bar_shortcode', 99 );
And second (which is placed after the progress bar) is the get percentage function...
if( !function_exists('show_specific_product_quantity') ) {
function show_specific_product_quantity( $atts ) {
// Shortcode Attributes
$atts = shortcode_atts(
array(
'id' => '', // Product ID argument
),
$atts,
'product_qty'
);
if( empty($atts['id'])) return;
$stock_quantity = 0;
$product_obj = wc_get_product( intval( $atts['id'] ) );
$stock_quantity = ((12000 - $product_obj->get_stock_quantity()) / 12000) * 100;
if( $stock_quantity > 0 ) return $stock_quantity;
}
add_shortcode( 'product_qty', 'show_specific_product_quantity' );
}
And below is the shortcode I'm using...
[fruitful_pbar][fruitful_bar type="progress-bar-info" width=" [product_qty id="4278"]% " stripped="true"][/fruitful_bar][/fruitful_pbar]
As you can see - I'm using a shortcode inside a shortcode to create what I need.
Thanks in advance! :-)

Get first shortcode result in one variable and send for second shortcode as a attribute.

Related

Shortcode that displays product attributes set for a WooCommerce product by ID

I found the following code in an older thread (Shortcode that display all product attributes set for a WooCommerce product) which basicly SHOULD be the solution to what im looking for
function get_product_attributes_shortcode($atts ) {
// Extract shortcode attributes
extract( shortcode_atts( array(
'id' => get_the_ID(),
), $atts, 'display-attributes' ) );
global $product;
if ( ! is_a($product, 'WC_Product') ) {
$product = wc_get_product( $id );
}
if ( is_a($product, 'WC_Product') ) {
$html = []; // Initializing
foreach ( $product->get_attributes() as $attribute => $values ) {
$attribute_name = wc_attribute_label($values->get_name());
$attribute_data = $values->get_data();
$is_taxonomy = $attribute_data['is_taxonomy'];
$option_values = array(); // Initializing
// For taxonomy product attribute values
if( $is_taxonomy ) {
$terms = $values->get_terms(); // Get attribute WP_Terms
// Loop through attribute WP_Term(s)
foreach ( $terms as $term ) {
$term_link = get_term_link( $term, $attribute );
$option_values[] = ''.$term->name.'';
}
}
// For "custom" product attributes values
else {
// Loop through attribute option values
foreach ( $values->get_options() as $term_name ) {
$option_values[] = $term_name;
}
}
$html[] = '<strong>' . $attribute_name . '</strong>: ' . implode(', ', $option_values);
}
return '<div class="product-attributes">' . implode(' | ', $html) . '<div>';
}
}
add_shortcode( 'display-attributes', 'get_product_attributes_shortcode' );
I modified the output part to display the attributes in a table
// Loop through attribute WP_Term(s)
foreach ( $terms as $term ) {
$option_values[] = $term->name;
}
}
// For "custom" product attributes values
else {
// Loop through attribute option values
foreach ( $values->get_options() as $term_name ) {
$option_values[] = $term_name;
}
}
$html[] = '<tr><td class="column-1">' . $attribute_name . '</td><td class="column-2">' . implode(', ', $option_values) . '</td></tr>';
}
return '<h4>Technische Daten</h4><table class="tablepress table produktdatenblatt tablepress-responsive"><tbody class="row-hover">' . implode($html) . '</tbody></table>';
}
}
add_shortcode( 'display_attributes', 'get_product_attributes_shortcode' );
Usage should be like this: [display-attributes] or with a defined product Id [display-attributes id="254"]
But its not showing the attributes from the respective ID i put into the shortcode. Its just showing attributes from one product. I want to use the shortcode on Wordpress Pages and Posts to enrich product descriptions i do.
I tried to figure out if i can fix it myself, but im realy bad when it comes to coding :)
Can somebody help me with this?

Show the custom attribute "variable product" in the list of related products

Based on "How to add variation stock status to Woocommerce product variation dropdown" answer, I have made some code that shows the custom attribute of a variable product and its presence in the store:
// Function that will check the stock status and display the corresponding additional text
function get_stock_status_text($product, $name, $term_slug) {
foreach($product - > get_available_variations() as $variation) {
if ($variation['attributes'][$name] == $term_slug)
$stock = $variation['is_in_stock'];
}
return $stock == 1 ? '' : ' - out of stock';
}
// The hooked function that will add the stock status to the dropdown options elements.
add_filter('woocommerce_dropdown_variation_attribute_options_html', 'show_stock_status_in_dropdown', 10, 2);
function show_stock_status_in_dropdown($html, $args) {
// Only if there is a unique variation attribute (one dropdown)
if (sizeof($args['product'] - > get_variation_attributes()) == 1):
$options = $args['options'];
$product = $args['product'];
$attribute = $args['attribute']; // The product attribute taxonomy
$name = $args['name'] ? $args['name'] : 'attribute_'.sanitize_title($attribute);
$id = $args['id'] ? $args['id'] : sanitize_title($attribute);
$class = $args['class'];
$show_option_none = $args['show_option_none'] ? true : false;
$show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __('Select size', 'woocommerce');
if (empty($options) && !empty($product) && !empty($attribute)) {
$attributes = $product - > get_variation_attributes();
$options = $attributes[$attribute];
}
$html = '<select id="'.esc_attr($id).
'" class="'.esc_attr($class).
'" name="'.esc_attr($name).
'" data-attribute_name="attribute_'.esc_attr(sanitize_title($attribute)).
'" data-show_option_none="'.($show_option_none ? 'yes' : 'no').
'">';
$html. = '<option value="">'.esc_html($show_option_none_text).
'</option>';
if (!empty($options)) {
if ($product && taxonomy_exists($attribute)) {
$terms = wc_get_product_terms($product - > get_id(), $attribute, array('fields' => 'all'));
foreach($terms as $term) {
if (in_array($term - > slug, $options)) {
// HERE Added the function to get the text status
$stock_status = get_stock_status_text($product, $name, $term - > slug);
$html. = '<option value="'.esc_attr($term - > slug).
'" '.selected(sanitize_title($args['selected']), $term - > slug, false).
'>'.esc_html(apply_filters('woocommerce_variation_option_name', $term - > name).$stock_status).
'</option>';
}
}
} else {
foreach($options as $option) {
$selected = sanitize_title($args['selected']) === $args['selected'] ? selected($args['selected'], sanitize_title($option), false) : selected($args['selected'], $option, false);
// HERE Added the function to get the text status
$stock_status = get_the_stock_status($product, $name, $option);
$html. = '<option value="'.esc_attr($option).
'" '.$selected.
'>'.esc_html(apply_filters('woocommerce_variation_option_name', $option).$stock_status).
'</option>';
}
}
}
$html. = '</select>';
endif;
return $html;
}
On a single product page, I show related products. How to show this attribute (its presence in the store) in the form of a label in related products?
For example:
The product's name
Price - $25
Sizes available: L, XL
Try this code, I hooked into the woocommerce_after_shop_loop_item and displayed the product attributes. Right now it only works for the size attribute. It is showing the Large, Medium, Small. If you want to show L, XL, M, etc. just edit the size attribute.
add_action( 'woocommerce_after_shop_loop_item', 'mamham_woocommerce_after_shop_loop_item', 10);
function mamham_woocommerce_after_shop_loop_item() {
global $product;
// Bail if not in the single product page.
if ( ! is_product() ) return;
// Prduct attributes which you want to show.
// Attributes to show in the slug.
// 'attribute slug' => 'Text shown';
$show_attributes = array(
'size' => 'Sizes available:',
);
// Get the slugs.
$show_slugs = array_keys( $show_attributes );
// Get product type.
$product_type = $product->get_type();
if( 'simple' === $product_type ) {
$product_attributes = $product->get_attributes();
foreach( $product_attributes as $key => $product_attribute ) {
$slug = substr( $key, 3 );
if ( in_array( $slug, $show_slugs, TRUE ) ) {
$terms = $product_attribute->get_terms();
$terms_output = wp_list_pluck( $terms, 'name');
$terms_output = implode(', ', $terms_output );
echo esc_html( "${show_attributes[$slug]} ${terms_output}" );
}
}
} elseif ( 'variable' === $product_type ) {
$product_variations = $product->get_available_variations();
foreach ( $product_variations as $product_variation ) {
if ( $product_variation['is_in_stock'] && isset( $product_variation['attributes']['attribute_pa_size'] )) {
$terms_output[] = ucwords( $product_variation['attributes']['attribute_pa_size'] );
}
}
if ( ! empty( $terms_output) ) {
$terms_output = implode(', ', $terms_output );
echo esc_html( "Sizes available: ${terms_output}" );
}
}
}
Here is the screenshot, I have storefront theme and WooCommerce installed.

How to display woocommerce PRICE on product's BODY text - using SHORTCODE?

I'm writing some details of each prodcuts (short/long description) on woocommerce.
i'd like to insert a SHORTCODE inside the description that shows the current PRICE (sale / regular).
it should look something like that on the backend:
"Buy it now, for only [wc_price] $"
is there any shortcode i can use for that?
This is one the most simple snippet that does what you want without the need of inputting the id manually:
function my_shortcode_product_price() {
$html = '';
global $product;
$price = wc_get_price_to_display( $product, array( 'price' => $product->get_price() ) );
$args = array(
'ex_tax_label' => false,
'currency' => 'USD',
'decimal_separator' => '.',
'thousand_separator' => ' ',
'decimals' => 2,
'price_format' => '%2$s %1$s',
);
$html = "<span>" . wc_price( $price, $args ) . "</span>";
return $html;
}
add_shortcode( 'product_price', 'my_shortcode_product_price' );
The above code goes in the functions.php file of your active theme. After that you can use the shortcode like this:
[product_price]
Here You Go: add this code in your function.php
function short_code_woo_comm_desc( $atts ) {
$atts = shortcode_atts( array(
'id' => null
), $atts, 'tag_for_short_code_price' );
if ( empty( $atts[ 'id' ] ) ) {
return '';
}
$product = wc_get_product( $atts['id'] );
if ( ! $product ) {
return '';
}
return $product->get_price_html();
}
add_shortcode( 'tag_for_short_code_price', 'short_code_woo_comm_desc' );
Use:
[tag_for_short_code_price id="101"]

How to make custom form-tag in contact form 7 required

So i make custom form-tag in contact form 7! It is a drop down with list of my courses and now I want to make it required because that is the main thing in whole form.
So can someone give me a tip how to do that?
When I do the [myCustomField* course-name class:custom-field]
It does not working with *
So if someone can help it will be great!
I have been working on this myself this afternoon and I do not think Mahmoud has added everything that is needed to get the validation working well and the messages showing up.
using what I have learnt from the posts on contact form 7 here:
https://contactform7.com/2015/01/10/adding-a-custom-form-tag
https://contactform7.com/2015/02/27/using-values-from-a-form-tag/
and looking at this file in the plugin: contact-form-7/modules/select.php which helped a lot.
I think this will work better and needs to be added to your functions.php file in your child-theme.
add_action( 'wpcf7_init', 'custom_add_form_tag_myCustomField' );
function custom_add_form_tag_myCustomField() {
wpcf7_add_form_tag( array( 'myCustomField', 'myCustomField*' ),
'custom_myCustomField_form_tag_handler', true );
}
function custom_myCustomField_form_tag_handler( $tag ) {
$tag = new WPCF7_FormTag( $tag );
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
$atts['aria-invalid'] = $validation_error ? 'true' : 'false';
$atts['name'] = $tag->name;
$atts = wpcf7_format_atts( $atts );
$myCustomField = '';
$query = new WP_Query(array(
'post_type' => 'CUSTOM POST TYPE HERE',
'post_status' => 'publish',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
));
while ($query->have_posts()) {
$query->the_post();
$post_title = get_the_title();
$myCustomField .= sprintf( '<option value="%1$s">%1$s</option>',
esc_html( $post_title ) );
}
wp_reset_query();
$myCustomField = sprintf(
'<span class="wpcf7-form-control-wrap %1$s"><select %2$s>%3$s</select>%4$s</span>',
sanitize_html_class( $tag->name ),
$atts,
$myCustomField,
$validation_error
);
return $myCustomField;
}
That is how we create the custom tag. The important differences here are the addition of the $validation_error variables as wells the aria-required and aria-invalid data. It is also important to include the $validation_error in the final output so that we can see the validation messages being created.
Then to finish it off we need to add some validation via filters.
There is no documentation on this yet, but I used the functions from the select.php and altered them to what I needed.
/* Validation filter */
add_filter( 'wpcf7_validate_myCustomField', 'wpcf7_myCustomField_validation_filter', 10, 2 );
add_filter( 'wpcf7_validate_myCustomField*', 'wpcf7_myCustomField_validation_filter', 10, 2 );
function wpcf7_myCustomField_validation_filter( $result, $tag ) {
$tag = new WPCF7_FormTag( $tag );
$name = $tag->name;
if ( isset( $_POST[$name] ) && is_array( $_POST[$name] ) ) {
foreach ( $_POST[$name] as $key => $value ) {
if ( '' === $value ) {
unset( $_POST[$name][$key] );
}
}
}
$empty = ! isset( $_POST[$name] ) || empty( $_POST[$name] ) && '0' !== $_POST[$name];
if ( $tag->is_required() && $empty ) {
$result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) );
}
return $result;
}
This code should also go in your functions.php file just under the code for the custom CF7 tag.
Here the filter's first string $tag should match with the class that is being generated in the custom CF7 tag so if your custom tag->type = 'myCustomField' then the $tag of the filter must include the name, like so wpcf7_validate_myCustomField as well as the required version of it, wpcf7_validate_myCustomField*.
I hope that helps anyone else looking for this.
If you want even more of the options available from the backend of Contact Form 7 check the select.php file as it lays it out quite nicely on how to get each option and include it.
You can use [select*] to output a required drop-down menu.
[select* course-name include_blank "English" "Math"]
Check https://contactform7.com/checkboxes-radio-buttons-and-menus/
EDIT:
So you have your own shortcode [myCustomField]. To make two versions of your shortcode as [myCustomField] and [myCustomField*] you have to pass both shortcodes to your function as the following:
add_action( 'wpcf7_init', 'wpcf7_add_form_tag_mycustomfield' );
function wpcf7_add_form_tag_mycustomfield() {
wpcf7_add_form_tag( array( 'myCustomField', 'myCustomField*'),
'wpcf7_mycustomfield_form_tag_handler', array( 'name-attr' => true ) );
}
function wpcf7_mycustomfield_form_tag_handler( $tag ) {
$tag = new WPCF7_FormTag( $tag );
if ( empty( $tag->name ) ) {
return '';
}
$atts = array();
$class = wpcf7_form_controls_class( $tag->type );
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['name'] = $tag->name;
$atts = wpcf7_format_atts( $atts );
$html = sprintf( '<your-tag %s></your-tag>', $atts );
return $html;
}
Then, you can use it:
[myCustomField course-name class:custom-field]
or
[myCustomField* course-name class:custom-field]
References:
https://contactform7.com/2015/01/10/adding-a-custom-form-tag
https://contactform7.com/2015/02/27/using-values-from-a-form-tag/

Wordpress Prevent Users from posting full size image uploads

Is there any way in Wordpress to prevent content editors from selecting the "Full size" option when uploading images to a post? I'd like them to just have the "thumbnail", "medium", and "large" options. I used to use the Scissors plugin to do this, but as of Wordpress 2.9 this plugin no longer works.
You could acheive this result by forcing WordPress not to display the full size option. The function that creates the size radio buttons is in wp-admin/includes/media.php and is called image_size_input_fields.
There's no filter or action hook for that function that I'm aware of, but the function that calls it (image_attachment_fields_to_edit) has a filter hook of attachment_fields_to_edit.
So basically we can use the filter hook to override those two functions with our own, which will only be very slightly modified.
This will work in the standard functions.php file, or I suppose you could incorporate it into a plugin.
First, add the new filter:
add_filter('attachment_fields_to_edit', 'MY_image_attachment_fields_to_edit', 11, 2);
Next we create our two functions. I've just prefixed the names with MY_ for this case:
function MY_image_attachment_fields_to_edit($form_fields, $post) {
if ( substr($post->post_mime_type, 0, 5) == 'image' ) {
$alt = get_post_meta($post->ID, '_wp_attachment_image_alt', true);
if ( empty($alt) )
$alt = '';
$form_fields['post_title']['required'] = true;
$form_fields['image_alt'] = array(
'value' => $alt,
'label' => __('Alternate text'),
'helps' => __('Alt text for the image, e.g. “The Mona Lisa”')
);
$form_fields['align'] = array(
'label' => __('Alignment'),
'input' => 'html',
'html' => image_align_input_fields($post, get_option('image_default_align')),
);
$form_fields['image-size'] = MY_image_size_input_fields( $post, get_option('image_default_size', 'medium') );
} else {
unset( $form_fields['image_alt'] );
}
return $form_fields;
}
The only thing that's changed here from the normal WordPress function is that we're calling MY_image_size_input_fields instead of image_size_input_fields.
Now the function that does the actual hiding:
function MY_image_size_input_fields( $post, $check = '' ) {
// get a list of the actual pixel dimensions of each possible intermediate version of this image
/* $size_names = array('thumbnail' => __('Thumbnail'), 'medium' => __('Medium'), 'large' => __('Large'), 'full' => __('Full size')); */
$size_names = array('thumbnail' => __('Thumbnail'), 'medium' => __('Medium'), 'large' => __('Large'));
if ( empty($check) )
$check = get_user_setting('imgsize', 'medium');
echo '<pre>'; print_r($check); echo '</pre>';
foreach ( $size_names as $size => $label ) {
$downsize = image_downsize($post->ID, $size);
$checked = '';
// is this size selectable?
$enabled = ( $downsize[3] || 'large' == $size );
$css_id = "image-size-{$size}-{$post->ID}";
// if this size is the default but that's not available, don't select it
if ( $size == $check ) {
if ( $enabled )
$checked = " checked='checked'";
else
$check = '';
} elseif ( !$check && $enabled && 'thumbnail' != $size ) {
// if $check is not enabled, default to the first available size that's bigger than a thumbnail
$check = $size;
$checked = " checked='checked'";
}
$html = "<div class='image-size-item'><input type='radio' " . ( $enabled ? '' : "disabled='disabled' " ) . "name='attachments[$post->ID][image-size]' id='{$css_id}' value='{$size}'$checked />";
$html .= "<label for='{$css_id}'>$label</label>";
// only show the dimensions if that choice is available
if ( $enabled )
$html .= " <label for='{$css_id}' class='help'>" . sprintf( __("(%d × %d)"), $downsize[1], $downsize[2] ). "</label>";
$html .= '</div>';
$out[] = $html;
}
return array(
'label' => __('Size'),
'input' => 'html',
'html' => join("\n", $out),
);
}
In this last function only two things change. At the top we get rid of the reference to 'Full Size' in the $size_names array definition. Then the line that says $enabled = ( $downsize[3] || 'large' == $size );, we changed. We simply replaced 'full' == $size with 'large' == $size.
Here's a screenshot of the result:
I don't think you can disable the large size, but you can set it's width and height to be the same as the medium size. It's under Settings → Media

Resources