How to change output of a certain Pods field? - wordpress

I have two pods: course and teacher.
Each course has a teacher.
I use shortcodes in order to build a form to define new course:
[pods name='course' form='1' fields='name, teacher' ]
When defining a new course, the user can choose the teacher for this course.
By default, the name of the teacher is displayed in a drop down list. I wonder if I can change the output of the teachers in the drop down list.
For example, in addition to the name I want to display a certain field, such as location of the teacher in the drop down list.
Is this possible using the built-in shortcodes of Pods 2?
Update:
Following the instructions of Scott, I solved the problem. I wrote the solution into the comment section but formating was lost. Below, I put the code again:
function pods_teacher_pick_data($data, $name, $value, $options, $pod, $id){
if ($name == "pods_field_teachers") {
foreach ($data as $id => &$value) {
$p = pods('teacher', $id);
$name = $p->display('name');
$city = $p->display('profile.city.name');
$value = $name . ' - ' . $city;
}
}
return $data;
}
add_filter('pods_field_pick_data', 'pods_teacher_pick_data', 1, 6);

Not built in yet, but you can take over the data output using the filter: pods_field_pick_data
$data = apply_filters( 'pods_field_pick_data', $data, $name, $value, $options, $pod, $id );
Adding a filter to that filter should give you the ability to change what appears in the drop-down, or other relationship input types.
Edit: I just added a similar filter for filtering the autocomplete data too.
$pick_data = apply_filters( 'pods_field_pick_data_ajax', array(), $field[ 'name' ], null, $field, $pod, 0, $data );
$data in this array is actually the fully setup PodsData object
EDIT (02/07/2013):
In Pods 2.3, I've added a quick function that should streamline adding custom relationship objects. This is preferrer over overriding an existing relationship or using the custom simple definition dynamically. Pretty easy to use, check it out at https://github.com/pods-framework/pods/issues/1033
$options = array(
'group' => 'Special Relationships', // Whatever you want the selection group to be, defaults to label
'simple' => false, // Whether this field is related by strings or integer IDs, integer IDs get stored in wp_podsrel, strings are stored in the field itself either serialized (meta-based) or json encoded (table-based)
'data' => array( // Custom define the items to select from manually
1 => 'Gravity Form 1',
2 => 'Gravity Form 2'
),
'data_callback' => 'get_custom_gravity_forms_list', // Provide a callback function to call to define the data (instead of setting 'data' above)
'value_to_label_callback' => 'get_custom_gravity_forms_list', // Provide a callback function to define the data when called through PodsField_Pick::value_to_label
'simple_value_callback' => 'get_custom_gravity_forms_list' // Provide a callback function to define the data when called through PodsField_Pick::simple_value
);
pods_register_related_object( 'gravity-form', 'Gravity Forms', $options );

For ajax, it seems need to use a bit different filter pods_field_pick_data_ajax_items like this:
function pods_teacher_pick_data_ajax_items($items, $name, $null, $field, $pod, $id){
if ($name == "pods_meta_categorie" || $name == 'categorie') {
foreach ($items as &$item) {
$id = $item['id'];
$value = $item['text'];
$p = pods('dvd_categories', $id);
$code = $p->display('code');
$item['text'] .= ' - ' . $code;
}
}
return $items;
}
add_filter('pods_field_pick_data_ajax_items', 'pods_teacher_pick_data_ajax_items', 1, 6);
Note different structure of arrays $data and $items.
Filter pods_teacher_pick_data_ajax looks very strange and useless to me as it doesnt accept $data array.

Related

Programmatically construct a dynamic dropdown field in Contact Form 7

I looked around here and by search engine, but unfortunately I couldn't find a solution for myself.
So, I now ask assistance with a function that I need to customize for the Contact Form 7 WordPress plugin. The function was from another question.
In a drop-down menu (select) I need two details (workshop name and date) in one option field. Both details come from the same post of a custom post type. The first detail is a post_title, the second is a custom-field from Meta-Box plugin.
The following function works in principle, but it only returns the one or the other detail. Probably the solution is within the foreach construct. But I don't know how it works.
I would be very grateful for support!
[UPDATE 2018-08-12]
After further research, I've found the solution at this post and changed the function accordingly.
The solution should look like this:
<select>
<option value="workshop name – date">workshop name – date</option>
...
</select>
This is the function:
add_filter( 'wpcf7_form_tag', 'dynamic_field_choose_workshop', 10, 2);
function dynamic_field_choose_workshop ( $tag, $unused ) {
if ( $tag['name'] != 'workshop' )
return $tag;
$args = array (
'post_type' => 'workshop',
'post_status' => 'publish',
'orderby' => 'name',
'order' => 'ASC',
'numberposts' => - 1,
);
$custom_posts = get_posts($args);
if ( ! $custom_posts )
return $tag;
foreach ( $custom_posts as $custom_post ) {
$ID = $custom_post->ID;
$tag['values'][] = $custom_post->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $ID);
$tag['raw_values'][] = $custom_post->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $ID);
$tag['labels'][] = $custom_post->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $ID);
}
return $tag;
}
There is CF7 extension that will do this for you. Checkout the Smart Grid-Layout for CF7, it introduces a new tag called dynamic_dropdown. This is is what you want to use. The dynamic_dropdown creates a select field and allows you to populate the field options using either a taxonomy, titles of a post type, or a filter. You want to use the filter option to actually construct the options as per your requirement. The tag popup window is self explanatory, however if you get stuck post a comment below and I'll give you some more tips.
Using the following dynamic_dropdown tag,
[dynamic_select workshop-date-select class:select2 "source:filter"]
it creates a <select name="workshop-date-select"> dropdown field which will be converted into a select2 jquery field on the front end, and its values dynamically created using the following function placed in the functions.php file,
add_filter('cf7sg_dynamic_dropdown_custom_options', 'filter_options',10,3);
function filter_options($options, $field_name, $form_key){
/*first we verify if this is the right field from the right form
in case multiple forms with similar fieldd exiss.
the $form_key is a unique key exposed by the Smart Grid-layout plugin
instead of using form IDs to make forms and code more portable across servers.*/
if($form_key != 'my-form' && $field_name != 'workshop-date-select') return $options;
$options = array();
//load your options programmatically, as $value=>$name pairs.
$args = array (
'post_type' => 'workshop',
'post_status' => 'publish',
'orderby' => 'name',
'order' => 'ASC',
'numberposts' => - 1,
);
$workshops = get_posts( $args );
foreach($workshops as $workshop){
$val = $workshop->post_title . ' - ' . rwmb_get_value('workshop_meta_boxes_date', '', $workshop->ID);
$options[$val]=$val;
}
return $options;
}
this will create the desired dropdown select field in the front end.
NOTE of CAUTION: I would populate the option values as the workshop post ID rather than the same text as the option label. When the form is submitted the value of the post ID can be used to populate the notification email with the desired workshop title and date. This gives more flexibility to expand the reported information in the future.

Custom product attributes is blank even though I add it [duplicate]

The products in my clients website require certain attributes which I have added via Products -> Attributes in the Wordpress administration. In this import script I'm coding I need to use the function update_post_meta($post_id, $meta_key, $meta_value) to import the proper attributes and values.
Currently I have the function like so:
update_post_meta( $post_id, '_product_attributes', array());
However I'm not sure how to properly pass along the attributes and their values?
Right so it took me a while to figure it out myself but I finally managed to do this by writing the following function:
// #param int $post_id - The id of the post that you are setting the attributes for
// #param array[] $attributes - This needs to be an array containing ALL your attributes so it can insert them in one go
function wcproduct_set_attributes($post_id, $attributes) {
$i = 0;
// Loop through the attributes array
foreach ($attributes as $name => $value) {
$product_attributes[$i] = array (
'name' => htmlspecialchars( stripslashes( $name ) ), // set attribute name
'value' => $value, // set attribute value
'position' => 1,
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
// Example on using this function
// The attribute parameter that you pass along must contain all attributes for your product in one go
// so that the wcproduct_set_attributes function can insert them into the correct meta field.
$my_product_attributes = array('hdd_size' => $product->hdd_size, 'ram_size' => $product->ram_size);
// After inserting post
wcproduct_set_attributes($post_id, $my_product_attributes);
// Woohay done!
I hope this function will help other people if they need to import multiple attributes pro-grammatically in WooCommerce!
I tried Daniel's answer, and it didn't work for me. It might be that the Wordpress/Woocommerce code has changed since, or perhaps I didn't quite understand how to do it, but either way that code did nothing for me. After a lot of work using it as a base, however, I came up with this snippet of code and put it on my theme's functions.php:
function wcproduct_set_attributes($id) {
$material = get_the_terms( $id, 'pa_material');
$material = $material[0]->name;
// Now update the post with its new attributes
update_post_meta($id, '_material', $material);
}
// After inserting post
add_action( 'save_post_product', 'wcproduct_set_attributes', 10);
With this, I can take what I set as "material" on my WooCommerce install as a custom attribute and add it to the formal meta as _material. This in turn allows me to use another snippet of code so the WooCommerce search function extends to meta fields, meaning I can search for a material in the WooCommerce search field and have all items with that material appear.
I hope this is useful to somebody.
#Daniels's answer works, won't decide on right or wrong, however if you want to add the values as a taxonomy term under attributes you have to adapt the code as below (set is_taxonomy = 1). Otherwise Woocommerce sees it as custom meta field(?). It still adds the value under attributes. This will only work for strings. For values that are arrays the code has to be adapted.
Additionally it uses the wp_set_object_terms that #Anand suggests as well. I was using that, because all the documentation I could find led to believe that had to be used. However if one only uses the wp_set_object_terms then I couldn't see the attributes in the edit product screen. Using the information from both answers and reading on the subject resulted in the solution.
You will need to tweak the code for things such as product variations.
/*
* Save Woocommerce custom attributes
*/
function save_wc_custom_attributes($post_id, $custom_attributes) {
$i = 0;
// Loop through the attributes array
foreach ($custom_attributes as $name => $value) {
// Relate post to a custom attribute, add term if it does not exist
wp_set_object_terms($post_id, $value, $name, true);
// Create product attributes array
$product_attributes[$i] = array(
'name' => $name, // set attribute name
'value' => $value, // set attribute value
'is_visible' => 1,
'is_variation' => 0,
'is_taxonomy' => 1
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
Then call the function:
$custom_attributes = array('pa_name_1' => $value_1, 'pa_name_2' => $value_2, 'pa_name_3' => $value_3);
save_wc_custom_attributes($post_id, $custom_attributes);
Thank you for posting the code Daniel & Anand. It helped me a great deal.
Don't know if this is the "correct" way to do this... But I needed a function to add ACF repeater fields with a date value as a attribute on post save, so this was the function I came up with:
add_action( 'save_post', 'ed_save_post_function', 10, 3 );
function ed_save_post_function( $post_ID, $post, $update ) {
//print_r($post);
if($post->post_type == 'product')
{
$dates = get_field('course_dates', $post->ID);
//print_r($dates);
if($dates)
{
$date_arr = array();
$val = '';
$i = 0;
foreach($dates as $d)
{
if($i > 0)
{
$val .= ' | '.date('d-m-Y', strtotime($d['date']));
}
else{
$val .= date('d-m-Y', strtotime($d['date']));
}
$i++;
}
$entry = array(
'course-dates' => array(
'name' => 'Course Dates',
'value' => $val,
'position' => '0',
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
)
);
update_post_meta($post->ID, '_product_attributes', $entry);
}
}
}
Hope this helps someone.

Display user's data from database on their profile pages

In Drupal 7, is it possible to show a result of a DB query on each users' respective profile page, in some table? I need to do this programmatically within my existing module. So the input to the query would be the ID of a user whose profile is currently being viewed.
Only to show the queried data - no administration, no edits, nothing else.
something along the lines of.. (image)
Also the block or field or whatever would make this possible needs to be configurable through the _permission() hook as to who can or cannot view it.
I thought since this is basically just a query with no extra custom stuff there would be an easy way via the Drupal API.
you can create custom block for that and view it in current user profile
/**
* Implements hook_block_info().
*/
function custom_block_block_info() {
$blocks = array();
$blocks['my_block'] = array(
'info' => t('My Custom Block'),
'status' => TRUE,
'region' => 'Content',
'visibility' => BLOCK_VISIBILITY_LISTED,
'pages' => 'user/*',
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function custom_block_view($delta = '')
{
// The $delta parameter tells us which block is being requested.
switch ($delta)
{
case 'my_block':
// Create your block content here
$block['subject'] = t('This is just a test block created programatically');
$block['content'] = _user_detail_list();
break;
}
return $block;
}
/**
* Implements costome code we want to print().
*/
function _user_detail_list(){
//enter your query and output in some variable
$value = "<p>User Detail</p>"
return $value;
}
Note :- Here profile is extended with new block
There will be some coding to get what you want, but if you just want style/show the data that's already available with the "user" object then #1 below will do it.
Easy way(#1):
1. Create a view and choose the "user" info that you need shown and give it a path. Then in your sub-theme use the correct template -see the code snippets.
https://www.drupal.org/forum/support/post-installation/2011-04-04/modify-the-default-profile-pagelayout
other ways:
use the user-profile.tpl.php see
https://api.drupal.org/api/drupal/modules%21user%21user-profile.tpl.php/7.x
in your module, you need to call and reach out to the hook_user_view.
https://api.drupal.org/api/drupal/modules%21user%21user.api.php/function/hook_user_view/7.x
Here you fetch user profile data from database then follow it
function modulename_menu() {
$items['user-data'] = array(
'title' => 'User data',
'page callback' => 'user_data',
'access callback' => ('user_is_logged_in'),
'#type' => MENU_NORMAL_ITEM,
);
return $items;
}
function user_data(){
global $user;
$user_fields = user_load($user->uid);
$output = "" //return those $user_fields values into table using theme('table',header,rows)
return $output;
}
https://www.drupal.org/node/156863 (for create table view)
i.e
global $user;
$user_fields = user_load($user->uid);
$firstname = $user_fields->field_firstname['und']['0']['value'];
$lastname = $user_fields->field_lastname['und']['0']['value'];

Wordpress shortcode name as an Attribute

I was wondering if possible to setup a shortcode and have the name of the shortcode also work as an attribute. How I have mine currently setup is like so
add_shortcode('tooltip', 'tooltip');
function tooltip( $atts $content = null) {
array(
'type' => '',
);
So when someone in wordpress uses the shortcode you type in
[tooltip type="fruit"]Item Name[/tooltip]
Although I was wondering is it possible to just use the name of the shortcode as a atts so I can short it a little bit and have it look like this
[tooltip="fruit"]Item Name[/tooltip]
So pretty much cut out the type attribute and use the name of the shortcode tooltip as an attribute instead.
Nope, what you're proposing isn't possible. It may be shorter but in my opinion it would be confusing so I don't see it ever being something that's made possible short of you building the functionality yourself.
You have to use first item in $atts array, ($atts[0]) when using shortcode tag as attribute.
Working example:
<?php
add_shortcode('tooltip', 'tooltip');
function tooltip(Array $atts = array(), $content = null, $tag = null) {
$args = shortcode_atts(array( 0 => null ), $atts);
$args['type'] = trim($args[0], '"=');
unset($args[0]);
extract($args);
// Your code starts here ...
$output = array(
'$type' => $type,
'$content' => $content
);
$output = '<pre>' . print_r($output, true) . '</pre>';
return $output;
}
Please replace everything after // Your code starts here ...
Executing example:
[tooltip="fruit"]Item Name[/tooltip]
will return:
<pre>Array
(
[$type] => fruit
[$content] => Item Name
)
</pre>

compare number of items in the mysql row (php wordpress)

In my wordpress mockup, I have meta_value for users which is called ref_credit. This meta value for sandro looks like this:
174 1 ref_credit a:2:{i:0;s:1:"9";i:1;s:2:"10";}
Means he referred users with id=9,10
Another user meta_value looks like this:
209 9 ref_credit a:1:{i:0;s:2:"11";}
He referred only 1 user id=11.
Now I'd like to create a simple leader-board, I mocked up something but logics is completely wrong. I understand my code compares values and orders by this. I want to order it by number of users referred.
Any ideas?
complete function is this:
//get_users calls WP_User_Query and returns an array of matching users
$users = get_users(
array( 'fields' => 'all_with_meta',
'meta_query' => array( array( 'key' => 'ref_credit', // the meta field (or key) we want to target
'compare' => '>=' // comparison method (optional: =, >, <, etc)
)))
);
//custom function for comparing the data we want to sort by
function cmp($a, $b){
if ($a->points == $b->points) {
return 0;
}
return ($a->points > $b->points) ? -1 : 1;
}
//usort sorts our $users array with our function cmp()
usort($users, 'cmp');
//leaving an array of $users sorted by the value of meta 'points'
echo '<ol>';
foreach ($users as $user) {
echo '<li>' . $user->display_name . '</li>';
}
echo '</ol>';
I think there are a few problems.
The first is that all_with_meta doesn't seem to bring back the metadata, despite what the name implies. Not sure what it's supposed to do - the codex doesn't help much. So you'll have to grab the ref_credit values yourself.
Secondly, your comparison seems to be using something called points, not ref_credit. Not sure where that's coming from. Since ref_credit is an array, you'll have to compare the array lengths, not the values themselves (using count say).
Leaving your original query as is, something like this should work (though you may have to check I've got the cmp result the right way around):
//get_users calls WP_User_Query and returns an array of matching users
$users = get_users(
array( 'fields' => 'all_with_meta',
'meta_query' => array(
array( 'key' => 'ref_credit', // the meta field (or key) we want to target
'compare' => '>=' // comparison method (optional: =, >, <, etc)
)
)
)
);
foreach($users as $user_id => $user) {
$user->ref_credit = get_user_meta($user_id, 'ref_credit', true);
}
//custom function for comparing the data we want to sort by
function cmp($a, $b){
return count($b->ref_credit) - count($a->ref_credit);
}
usort($users, 'cmp');
//leaving an array of $users sorted by the value of meta 'points'
echo '<ol>';
foreach ($users as $user) {
echo '<li>' . $user->display_name . '</li>';
}
echo '</ol>';

Resources