I am building a drupal 7 (7.20) website with a "project" content type which contains multiple image fields (i do not want to use galleries).
I would like to be able to perform a mass delete operation on these fields from the node edit page. From what I have gathered I have to override theme_file_widget_multiple and return a tableselect instead of a table and then use a button plus javascript to delete the images from the database.
Am I missing something obvious ? This seems like alot of work for something so trivial.
EDIT:
I have had some progress with this:
function mytheme_file_widget_multiple($variables) {
$element = $variables ['element'];
$headers = array ();
$headers ['info'] = t ( '' );
$widgets = array ();
foreach ( element_children ( $element ) as $key ) {
$widgets [] = &$element [$key];
}
usort ( $widgets, '_field_sort_items_value_helper' );
$rows [] = array ();
$i = 0;
foreach ( $widgets as $key => &$widget ) {
// Save the uploading row for last.
if ($widget ['#file'] == FALSE) {
$widget ['#description'] = $element ['#file_upload_description'];
continue;
}
$operations_elements = array ();
foreach ( element_children ( $widget ) as $sub_key ) {
if (isset ( $widget [$sub_key] ['#type'] ) && $widget [$sub_key] ['#type'] == 'submit') {
$operations_elements [] = &$widget [$sub_key];
}
}
$information = drupal_render ( $widget );
$rows [$i ++] ['info'] = $information;
}
$output = '';
$output = drupal_render_children ( $element );
$form ['element'] = array (
'#type' => 'tableselect',
'#header' => $headers,
'#options' => $rows,
'#js_select' => TRUE,
'#empty' => t ( 'No data' ),
'#attributes' => array () );
$output .= empty ( $rows ) ? "" : drupal_render ( $form );
return $output;
}
This was included in my theme's template file however the tableselect does not have checkboxes. This is driving me crazy.. Can someone please tell me what I am doing wrong ?
From what I have gathered I have to create a module which overrides the fieldset preprocess functions..
Here are the references:
1) https://drupal.org/node/1905244
This article seems to try to do what you want to.
2) Also check out https://drupal.org/project/views_bulk_operations
this might be useful.
3) if not then you will need to make your own widget:
https://api.drupal.org/api/drupal/modules%21field%21field.module/group/field/7
https://drupal.org/project/examples ( has all the examples you will need )
all the best.
Related
I'm trying to display some order item meta data as checkboxes instead of plain text via the woocommerce_order_item_display_meta_value hook (hope my terminology is right. I'm new to this woocommerce game).
add_filter( 'woocommerce_order_item_display_meta_value', 'modify_order_item_display_value' , 10, 3 );
function modify_order_item_display_value( $display_value, $meta, $wc_order_item ) {
$meta_data = $meta->get_data();
if( $meta_data['key'] === '_Packed' ) {
$display_value = __('<input type="checkbox" name="mycheckbox" id="mycheckbox" value="1" />', 'woocommerce' );
}
return $display_value;
}
If I do something like $display_value = '<p>TEST</p>'; it comes out fine. When I try to use an input it doesn't show up. Looking at DOM in the browser I can get down to the <td> that should contain my input and the HTML just isn't there.
Does woocommerce_order_item_display_meta_value filter out input fields?
Is there another way to get a checkbox for order item meta data ?
I don't know if this is the right way to do it but it works. I'd love any feedback about the "woocommercyness" of it...
STEP1
Use woocommerce_hidden_order_itemmeta to hide my field so it doesn't get shown "the normal way"
add_filter( 'woocommerce_hidden_order_itemmeta', 'myplugin_hide_order_item_meta_fields' );
function myplugin_hide_order_item_meta_fields( $fields )
{
$fields[] = '_Packed';
return $fields;
}
STEP 2
Use woocommerce_after_order_itemmeta to display my field in a custom way after all of the other Meta data.
Note that I give the checkbox an ID based on the order item id. In other code I need to see if these IDs are passed in requests or not
add_action( 'woocommerce_after_order_itemmeta', 'myplugin_order_meta_customized_display',10, 3 );
function myplugin_order_meta_customized_display( $item_id, $item, $product )
{
$packed = $item->get_meta('_Packed') === 'Y';
echo "<div>";
woocommerce_form_field("packed_$item_id",
array(
'type' => 'checkbox',
'label' => __('Packed', 'woocommerce'),
'required' => false,
'class' => array('input-checkbox')
), $packed);
echo "</div>";
}
STEP 3
Use the REQUEST to set the meta datafunction myplugin_set_meta_from_post($order_id, $order)
I call a wrapper from the actions woocommerce_checkout_order_processed and save_post_shop_order. The actuions get the order id - I lookup the order (because I'm doing other stuff, not just the crazy meta display)
function myplugin_set_meta_from_post($order_id, $order)
{
// For each meta data in each order item
// If it is '_Packed' then see if a corresponding packed_<id> parameter
// is in the request and update the item's meta data accordingly.
//
foreach ($order->get_items() as $item_key => $item ) {
$item_meta = $item->get_meta_data();
foreach($item_meta as $meta)
{
if ($meta->__get('key') === '_Packed')
{
$k = 'packed_'.$item->get_id();
$packed = 'Y';
if ( ! isset( $_REQUEST[ $k ] ) || empty( $_REQUEST[ $k ] ) ) {
$packed = 'N';
}
if ($packed != $item->get_meta('_Packed'))
{
$item->update_meta_data('_Packed', $packed);
}
}
}
}
}
tldr:// how to clone an existing WC_Order_Item_Product to a new order?
I have looked through a lot of existing subscription plugins but didnt really get warm with them. So I decided to create something as a learning project. Its not for a customer, I dont expect it to be commercially successful product, but I guess its good to step up my game.
So I have created a custom table already that saves target dates and would like to create new orders from the existing WC_Order_Item_Product-Objects. By simply adding the original Object it will just move them from the old order, which is something I do not want to happen. I wonder how I could 'clone' the object and remove the protected [order_id] which would be overridden by WC_Order->add_item anyway without altering the original database entries. Maybe thats the wrong approach or a bad idea?
I have also tried to find some up2date hint on how to create a full custom WC_Order_Item_Product but was not really successful on that.
What I got atm:
function update ($reminder_id = null) {
global $woocommerce;
global $wpdb;
global $aboprodukt_table_name;
// TODO if reminder id
if ( ! $reminder_id) {
$neworders = [];
// get all reminders from db and loop through them
$aboprodukt_reminders = $wpdb->get_results( 'SELECT * FROM ' . $aboprodukt_table_name . ' ORDER BY ' . $aboprodukt_table_name . '.targetdate ASC');
foreach ($aboprodukt_reminders as $item ) {
// get original order item object to abstract
$order_item = new \WC_Order_Item_Product($item->orderitem);
// get order object
$order = $order_item->get_order();
// get customer id
$customer = $order->get_customer_id();
// TODO abstract order items
// assign user, adresses if not existing yet, copy from last order
if ( ! $neworders[$customer] ) {
// check all reminders
$customer_array = $order->get_data();
$args = array(
'customer_id' => $customer,
'created_via' => 'Aboprodukt',
'add_order_note' => __('Aboprodukt Custom Order', 'aboprodukt'),
);
$neworders[$customer] = \wc_create_order($args);
// TODO Shipping
}
// add order items
$neworders[$customer]->add_item($order_item);
$neworders[$customer]->calculate_totals();
$neworders[$customer]->save();
}
return print_r($neworders,true);}
Not sure if it helps so. but this is the way I've managed to do so.
For understanding: I got an extra "reminder"-table in the database that stores: date, order-item-id. It is removed after its used to create a new order.
function update ($reminder_id = null) {
global $woocommerce;
global $wpdb;
global $aboprodukt_table_name;
// TODO if order id
if ( ! $reminder_id) {
$neworders = [];
// get all reminders from db and loop through them
$aboprodukt_reminders = $wpdb->get_results( 'SELECT * FROM ' . $aboprodukt_table_name . ' ORDER BY ' . $aboprodukt_table_name . '.targetdate ASC');
foreach ($aboprodukt_reminders as $item ) {
// get original order item object to abstract
$order_item = new \WC_Order_Item_Product($item->orderitem);
$order = $order_item->get_order();
$customer = $order->get_customer_id();
// assign user, adresses if not existing yet, copy from last order
if ( ! $neworders[$customer] ) {
// check all reminders
$args = array(
'customer_id' => $customer,
'created_via' => 'Aboprodukt',
'add_order_note' => __('Aboprodukt Custom Order', 'aboprodukt'),
);
$neworders[$customer] = \wc_create_order($args);
// order
$customer_object = new \WC_Customer( $customer );
$types = array('billing','shipping');
foreach ($types as $type) {
foreach ( $customer_object->{"get_{$type}"}() as $key => $value) {
if ( ! empty($value) ) {
if ( is_callable( array( $neworders[$customer], "set_{$type}_{$key}" ) ) ) {
$neworders[$customer]->{"set_{$type}_{$key}"}( $value );
}
}
}
}
// Set Shipping
$shippingold = $order->get_shipping_methods();
$oldshippingitem = new \WC_Order_Item_Shipping( reset($shippingold) );
$newshippingitem = new \WC_Order_Item_Shipping();
$newshippingitem->set_method_id( $oldshippingitem->get_method_id() );
$newshippingitem->set_instance_id( $oldshippingitem->get_instance_id() );
$newshippingitem->set_method_title( $oldshippingitem->get_method_title() );
$newshippingitem->set_total( $oldshippingitem->get_total() );
$neworders[$customer]->add_item( $newshippingitem );
}
// if variation_id > 0 then is simple product, get product
$item_variation_id = $order_item->get_variation_id();
$item_id = $neworders[$customer]->add_product(
wc_get_product(isset( $item_variation_id ) && $item_variation_id > 0 ? $item_variation_id : $order_item->get_product_id() ),
$order_item->get_quantity()
);
// copy metadata for future use
$neworderitem = new \WC_Order_Item_Product($item_id);
$neworderitem->add_meta_data( '_aboprodukt_order', $order_item->get_meta('_aboprodukt_order'), true );
$neworderitem->add_meta_data( '_aboprodukt_timespan', $order_item->get_meta('_aboprodukt_timespan'), true );
$neworderitem->add_meta_data( '_aboprodukt_type', $order_item->get_meta('_aboprodukt_type'), true );
$neworderitem->save();
$neworders[$customer]->calculate_totals();
$neworders[$customer]->save();
$wpdb->query(
$wpdb->prepare(
"DELETE FROM $aboprodukt_table_name
WHERE id = %d",
$item->id
)
);
}
}
// send emails
foreach ( $neworders as $customers => $neworder ) {
$mailer = \WC()->mailer();
\WC()->mailer()->emails['WC_Email_Customer_Invoice']->trigger($neworder->get_id());
$neworder->add_order_note( sprintf( __('%s email notification manually sent.', 'woocommerce'), $mail->title), false, true);
}
return $neworders;
}
I need to pass a list of labels into a Wordpress form to create checkboxes, preferably Gravity Forms. I know you can use: "Allow field to be populated dynamically" but that only populates the value and doesn't make a list of checkboxes dyncamically. Eg: yahoo.com/?CheckboxLabels=yellow&green&red
Checkboxes:
yellow
green
red
Is there a way to accomplish this? Thank you.
Hope this will resolve your problem. check the link
https://www.gravityhelp.com/forums/topic/dynamically-populate-checkboxes?replies=2
This ended up working for me by adding to functions.php in the theme.
<?php
//NOTE: update the ' 1' to the ID of your form
add_filter( 'gform_pre_render_1', 'populate_checkbox' );
add_filter( 'gform_pre_validation_1', 'populate_checkbox' );
add_filter( 'gform_pre_submission_filter_1', 'populate_checkbox' );
add_filter( 'gform_admin_pre_render_1', 'populate_checkbox' );
function populate_checkbox( $form ) {
foreach( $form['fields'] as &$field ) {
//NOTE: replace 3 with your checkbox field id
$field_id = 6;
if ( $field->id != $field_id ) {
continue;
}
$input_id = 1;
foreach (explode(',', $_GET["addresses"]) as $name => $value) {
//skipping index that are multiples of 10 (multiples of 10 create problems as the input IDs)
if ( $input_id % 10 == 0 ) {
$input_id++;
}
$choices[] = array( 'text' => $value, 'value' => $value );
$inputs[] = array( 'label' => $value, 'id' => "{$field_id}.{$input_id}" );
$input_id++;
}
$field->choices = $choices;
$field->inputs = $inputs;
}
return $form;
}
?>
I'm currently working with the plugin Google Calendar Events. I'd like to add the ability for users to choose (via a select drop-down menu) which feed they're viewing and then have the calendar automatically display the selected feed. Does anyone know how to do this?
I know that you can use the shortcode to choose what feeds to display, but I'd rather not create an individual page for each feed, and then have links to them (there are 10+ feeds and one is added and deleted with regularity, so it's just not feasible to manually create a calendar for each individual feed).
I've added this code to the gce-script.js file in the plugin:
function changeFeeds(){
var values = jQuery("#gce-view-feed").val();
jQuery("#result").replaceWith(values);
}
jQuery("option").click(function(){
location.reload();
});
jQuery("select").change(changeFeeds);
changeFeeds();
...Where the id "gce-view-feed" is the select menu's id and id "result" is where I display the results. This works great, except how do I then pass that result to the plugin so that it uses it?
Feed ids are defined by a PHP variable $feed_ids. I think the best place to edit the variable is this line of code in the google-calendar-events.php file:
//Check that any feeds have been added
if ( is_array( $options ) && ! empty( $options ) ) {
extract( shortcode_atts( array(
'id' => '',
'type' => 'grid',
'title' => null,
'max' => 0,
'order' => 'asc'
), $atts ) );
$no_feeds_exist = true;
$feed_ids = array();
if ( '' != $id ) {
//Break comma delimited list of feed ids into array
$feed_ids = explode( ',', str_replace( ' ', '', $id ) );
//Check each id is an integer, if not, remove it from the array
foreach ( $feed_ids as $key => $feed_id ) {
if ( 0 == absint( $feed_id ) )
unset( $feed_ids[$key] );
}
//If at least one of the feed ids entered exists, set no_feeds_exist to false
foreach ( $feed_ids as $feed_id ) {
if ( isset($options[$feed_id] ) )
$no_feeds_exist = false;
}
} else {
foreach ( $options as $feed ) {
$feed_ids[] = $feed['id'];
}
$no_feeds_exist = false;
}
But I don't know how to pass the jQuery value to the $feed_ids variable. Is there a way to do this? And if not, is there another way to dynamically select an option and then pass it to a PHP variable?
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