Create ACF repeater field from front end - wordpress

I'm trying to create a form users can use to post from the front end of a wordpress site.
I'm having trouble with creating repeater fields though. I've tried a couple of methods, but nothing seems to work:
$periods = $_POST['periods'];
// for each perdiod, save the start/end date and notes
for ($p = 1; $p <= $periods; $p++) {
update_sub_field( array('date', $p, 'start-date'), $_POST['p'.$p.'-start-date'] );
update_sub_field( array('date', $p, 'end-date'), $_POST['p'.$p.'-start-date'] );
update_sub_field( array('date', $p, 'notes'), $_POST['p'.$p.'-start-date'] );
} // end periods loop
and
// for each perdiod, save the start/end date and notes
for ($p = 1; $p <= $periods; $p++) {
add_post_meta($post_id, 'date_'.$p.'_start-date', $_POST['p'.$p.'-start-date']);
add_post_meta($post_id, 'date_'.$p.'_end-date', $_POST['p'.$p.'-end-date']);
add_post_meta($post_id, 'date_'.$p.'_notes', $_POST['p'.$p.'-notes']);
} // end periods loop
But these do nothing to the post itself.
The repeater is set up like this:
Date (repeater) ->
start-date (field)
end-date (field)
notes (field)
There's also another repeater field in there (repeater within a repeater), but I want to get this one working first!
Any ideas?

To create a post, you'll need to use the actual field keys for each field. You can't use the field name, because the db record hasn't yet been created. Check out Elliot's documentation here for that info.
Here's how some code might look to do this:
$event_field_key = 'field_534d3f17f3ca2';
// for each perdiod, save the start/end date and notes
for ($p = 1; $p <= $periods; $p++) {
$events[] = array(
'_start-date' => $_POST['p'.$p.'-start-date'],
'_end-date' => $_POST['p'.$p.'-end-date'],
'date' => $_POST['p'.$p.'-notes']
);
} // end periods loop
update_field($event_field_key, $events, $post_id);
You will have to get the field key for that field in order for this to work correctly. To do that, go to your custom fields screen and look for screen options in the top right corner. Check the box that says show field keys. Your field keys should now show up to the right of the field name in the custom fields list. Use that to add the field.
Here's Elliot's instructions if mine didn't make sense.

Related

Updating an ACF field after creating a Woocommerce attribute

I have a set of products (courses) that are dependent on a calendar.
The calendar is generated by a post type date which has an ACF field date_start and an associated_product
The logic is; the user creates a post-type Date which adds an attribute term to the associated product's attribute pa_dates.
I have hooked save_post and so far so good, the attribute is written to the product.
I then need to copy the date field to the term created $term_set this section doesn't produce anything. (I need this date to order the terms in my product)
Part of the problem is I have no way of interrogating the variables as this is all happening in a hook that has no way of printing output. (I have tried fwrite but with no result)
// Add terms on Date save.
function add_terms_to_date($post_ID) {
if ('date' !== get_post_type() ) {
return;
} else {
$product_id = get_field('associated_product',$post_ID);
$term_name = get_the_title($post_ID);
$taxonomy = 'pa_dates';
$term_set = wp_set_post_terms( $product_id, $term_name, $taxonomy, true );
// up to here, works fine.
// now need to identify that term ($term_set)
// Then I need to write copy the date field to its ACF field in my Date attribute
$selector = "term_date_start"; // the ACF field in the term
$date_start = get_field('date_start', $post_ID); // the date field to be copied
$value = $date_start;
// This next line caused the issue leading to the question so is commented out
// update_field($selector, $value, $term_set);
// and this line is correct
update_field($selector, $value, $taxonomy."_".$term_set);
}
}
add_action('save_post', 'add_terms_to_date');
So, complicated question, simple answer.
The last line should read;
update_field($selector, $value, $taxonomy."_".$term_set);
to avoid confusion with post IDs (RTFM) ACF has a different system for identifying terms. ($taxonomy comes from the earlier line and is pa_dates)
I have edited the post above, just in case it can provide help to someone.

Alter views search api solr result

I am using search api and Solr, When I echo the result variable , it gave me the following results
stdClass Object
(
[entity] => 442415
[_entity_properties] => Array
(
[search_api_relevance] => 1
[search_api_excerpt] =>
[search_api_item_id] => 442415
)
)
In views i added ( custom text field, that is global variable), With this nid 442415, i will do certain node load operation and finally,
i will get price for the specific product. This code block will execute inside the foreach.
_views_pre_render
Please guideme,
which hook i should use , _views_post_execute or _views_pre_render ?
How to assign new value in to which variable and how to print that in tpl
Finally, i want to display the price on each item
This link resolved my problem.
Solution approach
function mymodule_views_pre_render(&$view) {
if($view->name == 'my_view') {
foreach($view->result as &$row) {
$row->_entity_properties['nothing'] = 'new value';
}
}
}
views-view-field--view-name--display-name--nothing.tpl.php
print $row->_entity_properties['nothing'];

Modifying a field collection programmatically missing hostEntity fields

I am trying to modify a field collection in a node that already exists so I can change an image on the first element in an array of 3. The problem is, the hostEntity info is not set when I do a entity_load or entity_load_single so when I do a:
$field_collection_item->save(true); // with or without the true
// OR
$fc_wrapper->save(true); // with or without the true
I get the following error:
Exception: Unable to save a field collection item without a valid reference to a host entity. in FieldCollectionItemEntity->save()
When i print_r the field collection entity the hostEntity:protected fields are indeed empty. My field collection is setup as follows:
field_home_experts
Expert Image <--- Want to change this data only and keep the rest below
field_expert_image
Image
Expert Name
field_expert_name
Text
Expert Title
field_expert_title
Text
Here is the code I am trying to use to modify the existing nodes field collection:
$node = getNode(1352); // Get the node I want to modify
// There can be up to 3 experts, and I want to modify the image of the first expert
$updateItem = $node->field_home_experts[LANGUAGE_NONE][0];
if ($updateItem) { // Updating
// Grab the field collection that currently exists in the 0 spot
$fc_item = reset(entity_load('field_collection_item', array($updateItem)));
// Wrap the field collection entity in the field API wrapper
$fc_wrapper = entity_metadata_wrapper('field_collection_item', $fc_item);
// Set the new image in place of the current
$fc_wrapper->field_expert_image->set((array)file_load(4316));
// Save the field collection
$fc_wrapper->save(true);
// Save the node with the new field collection (not sure this is needed)
node_save($node);
}
Any help would be greatly appreciated, I am still quite new to Drupal as a whole (end-user or developer)
Alright so I think I have figured this out, I wrote up a function that will set a field collection values:
// $node: (obj) node object returned from node_load()
// $collection: (string) can be found in drupal admin interface:
// structure > field collections > field name
// $fields: (array) see usage below
// $index: (int) the index to the element you wish to edit
function updateFieldCollection($node, $collection, $fields = Array(), $index = 0) {
if ($node && $collection && !empty($fields)) {
// Get the field collection ID
$eid = $node->{$collection}[LANGUAGE_NONE][$index]['value'];
// Load the field collection with the ID from above
$entity = entity_load_single('field_collection_item', array($eid));
// Wrap the loaded field collection which makes setting/getting much easier
$node_wrapper = entity_metadata_wrapper('field_collection_item', $entity);
// Loop through our fields and set the values
foreach ($fields as $field => $data) {
$node_wrapper->{$field}->set($data);
}
// Once we have added all the values we wish to change then we need to
// save. This will modify the node and does not require node_save() so
// at this point be sure it is all correct as this will save directly
// to a published node
$node_wrapper->save(true);
}
}
USAGE:
// id of the node you wish to modify
$node = node_load(123);
// Call our function with the node to modify, the field collection machine name
// and an array setup as collection_field_name => value_you_want_to_set
// collection_field_name can be found in the admin interface:
// structure > field collections > manage fields
updateFieldCollection(
$node,
'field_home_experts',
array (
'field_expert_image' => (array)file_load(582), // Loads up an existing image
'field_expert_name' => 'Some Guy',
'field_expert_title' => 'Some Title',
)
);
Hope this helps someone else as I spent a whole day trying to get this to work (hopefully I won't be a noob forever in Drupal7). There may be an issue getting formatted text to set() properly but I am not sure what that is at this time, so just keep that in mind (if you have a field that has a format of filtered_html for example, not sure that will set correctly without doing something else).
Good luck!
Jake
I was still getting the error, mentioned in the question, after using the above function.
This is what worked for me:
function updateFieldCollection($node, $collection, $fields = Array(), $index = 0) {
$eid = $node->{$collection}[LANGUAGE_NONE][$index]['value'];
$fc_item = entity_load('field_collection_item', array($eid));
foreach ($fields as $field => $data) {
$fc_item[$eid]->{$field}[LANGUAGE_NONE][0]['value'] = $data;
}
$fc_item[$eid]->save(TRUE);
}
I hope this helps someone as it took me quite some time to get this working.

WordPress: Having trouble in pagination for plugin settings page

Developing a plugin in WordPress and getting well but stuck on pagination for the plugin page. Here is my code downloaded from internet ( got reference from here )
$items = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $wpdb->review_media GROUP BY post_id")); // number of total rows in the database
// tested and got results as commented
print_r($items); // say this is outputs value 2
echo $rm_options['list_per_page']; // this is my option set with value 1
if($items > 0) {
$p = new pagination;
$p->items($items);
$p->limit(empty($rm_options['list_per_page']) ? 20 : $rm_options['list_per_page']); // Limit entries per page
$p->target("admin.php?page=moderate.php");
$p->currentPage($_GET[$p->paging]); // Gets and validates the current page
$p->calculate(); // Calculates what to show
$p->parameterName('paging');
$p->adjacents(1); //No. of page away from the current page
if(!isset($_GET['paging'])) {
$p->page = 1;
} else {
$p->page = $_GET['paging'];
}
//Query for limit paging
$limit = "LIMIT " . ($p->page - 1) * $p->limit . ", " . $p->limit;
} else {
echo "No Record Found";
}
When I don't group my query by post_id it is working fine but as soon as I grouped its behaving weird. It is creating a pagination links and getting blank page. I think the reason is grouping the row. But don't know how to solve this.
Here is my table screenshot
Thanks a lot for your help...
If you use WordPress WP_List_Table class, it will take care of the pagination and provide a default table experience for the user.
This tutorial covers it all, the pagination part is:
function prepare_items() {
[...]
$per_page = 5;
$current_page = $this->get_pagenum();
$total_items = count($this->example_data);
// only necessary because we have sample data
$this->found_data = array_slice($this->example_data,(($current_page-1)*$per_page),$per_page);
$this->set_pagination_args( array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page //WE have to determine how many items to show on a page
) );
$this->items = $this->found_data;
}
And here's the full plugin shown in the tutorial. And in this other plugin you can see WP_List_Table in action using database data.

Create node programmatically with cck location field

I try to programmatically create a node of custom contenttype "location" in Drupal 6, with the node containing a location field (http://drupal.org/project/location) called "location" (yes I know, the nomenclature could be better, but I am just experimenting on this at the moment).
Creating the node works just fine, but I cannot find a way to set the contents for the location field - i.e. the node is created with all content but the value for then location field.
I try creating the node like this:
$newNode = (object) NULL;
$newNode->type = 'location';
$newNode->title = $locationName;
$newNode->uid = $userId;
$newNode->created = strtotime("now");
$newNode->changed = strtotime("now");
$newNode->status = 1;
$newNode->comment = 0;
$newNode->promote = 0;
$newNode->moderate = 0;
$newNode->sticky = 0;
$newNode->field_location[0]['street'] = 'Teststraße';
$newNode->field_location[0]['postal_code'] = '12345';
$newNode->field_location[0]['city'] = 'Musterstadt';
node_save($newNode);
The node gets created with the correct title, but the location fields remain unset.
How can I programmatically set the location-related fields?
Thanks in advance!
Wanted to add this as a comment, but it seems like putting code into the comment is rather problematic. So here we go: I changed the internas so that I do not use a cck field anymore, but use the default location option as suggested by googletorp.
The actual code to create a new location and assign this to a new node looks like this:
$location['street'] = "myStreet";
$location['postal_code'] = "12345";
...
$newLocationId = location_save($location);
$newNode = ...
$newNode->locations[0]['lid'] = $newLocationId;
node_save($newNode);
Thanks for the guidance :)
Instead of node_save, many people recommend using drupal_execute to programmatically submit the node edit form. This gives you the benefit of form validation.
See http://thedrupalblog.com/programmatically-create-any-node-type-using-drupal-execute for an excellent example of using drupal_execute. Don't forget to look at the comment http://thedrupalblog.com/programmatically-create-any-node-type-using-drupal-execute#comment-70 to see some additional info on CCK fields.
The advantage of drupal_execute is that you get form validation also. So after the drupal_executestatement you can see if there were any errors using form_get_errors ( http://api.drupal.org/api/function/form_get_errors/6 ). See snippet (pasted below) from http://civicactions.com/blog/cck_import_and_update for an example of using form_get_errors
$node->type = 'yourtype';
$values = array();
$values[...] = ...;
drupal_execute('yourtype_node_form', $values, $node);
$errors = form_get_errors();
if (count($errors)) {
// do something ...
}
Another very nice resource on programmatic submission of nodes using drupal_execute can be found at http://drupal.org/node/293663
I have done this, only not with a CCK field but the default location option you can add to nodes.
What I did to make it work, was to first save the location (there's an API function for it) and then add the location id from the saved location.
Sample code:
Note, $center is from an external source, so it's not Drupal related. I know all my locations are from Denmark in my example, so that part is just hardcoded.
When you don't use a CCK field, you don't need to save the location data on the node, instead you can just save the location and pair the location yourself. It's a quick solution, instead of running through the node form like suggested. For complex nodes, that might be the better choice, but when it's simple, this is done faster.
// Update the location data.
$location = is_array($node->location) ? $node->location : array();
$location += array(
'street' => $center->address->address2,
'city' => $center->address->zipName,
'postal_code' => $center->address->zip,
'country' => 'dk',
'country_name' => 'Denmark',
);
location_save($location);
// Insert location instance, if it's not set yet.
$criteria = array(
':nid' => $node->nid,
':vid' => $node->vid,
':lid' => $location['lid'],
);
if (!db_result(db_query("SELECT COUNT(*) FROM {location_instance} WHERE nid = %d AND vid = %d AND lid = %d;", $criteria))) {
db_query("INSERT INTO {location_instance} (nid, vid, lid) VALUES (%d, %d, %d)", $criteria);
}
For Drupal 7, saving as default location tab.
$location = array(
'latitude' => $row->gmapycord,
'longitude' => $row->gmapxcord,
);
$lid = location_save($location);
if ($lid) {
$entity->locations['0']['lid'] = $lid;
}
Inspired from: here

Resources