How to parse data into meta box with multiple fields? - php

I successfully build a function, that is able to import data from a CSV into posts of a Custom Post Type. I am able to parse data into the native title and description fields, but the function fails to parse data into a meta box with multiple fields.
Here is a code snippet of the function that are parsing CSV data into post fields:
// Check and see if the current post exists within the database.
$check_post_exists = function( $title ) use ( $wpdb, $postTypeArray ) {
// Get an array of all posts within the custom post type
$posts = $wpdb->get_col( "SELECT post_title FROM {$wpdb->posts} WHERE post_type = '{$postTypeArray["custom-post-type"]}' AND post_status = 'publish'" );
// Check if the passed title exists in array
return in_array( $title, $posts );
}
$i = 0;
foreach ( $posts() as $post ) {
// If the post exists, skip this post and go to the next one
if ( $check_post_exists( $post["zoneid"] ) ) {
continue;
}
$i++;
// Insert the post into the database
$post["id"] = wp_insert_post( array(
"post_title" => $post["zoneid"],
"post_content" => $post["bemaerkning"],
"post_type" => $postTypeArray["custom-post-type"],
"post_punktcat" => array( 4 ),
"post_status" => "publish"
));
// Set post category to the value "4"
wp_set_post_terms($post["id"], 4, 'punktcat', false );
// Parse data into a custom field normally referred
// FOLLOWINF FUNCTION IS UPDATING EVERY FIELD OF THE META BOX WITH THE
VALUE OF '1'
update_post_meta( $post["id"], 'fredningszone_data', true );
}
echo '<div id="message" class="updated fade"><p>' . $i . ' posts have succesfully been imported from CSV!' . '</p></div>';
So the update_post_meta() function in the code snippet above does not provide the data of the zoneid into the custom field fredningszone_data[id].
The way I build my custom field and be seen within the following code snippet:
function fredningszone_meta_box() {
add_meta_box(
'punkt_fredningszone', // $id - Meta box ID (used in the 'id' attribute for the meta box).
'Data for fredningszone', // $title - Title of the meta box.
'punkt_fredningszone_callback', // $callback - Function that fills the box with the desired content. The function should echo its output.
'punkt', // $screen - he screen or screens on which to show the box (such as a post type, 'link', or 'comment').
'normal', // $context - The context within the screen where the boxes should display.
'high' // $priority - The priority within the context where the boxes should show ('high', 'low').
);
}
add_action( 'add_meta_boxes', 'fredningszone_meta_box' );
/**
* Enable and display custom fields.
**/
function punkt_fredningszone_callback() {
global $post;
$meta = get_post_meta( $post->ID, 'fredningszone_data', true ); ?>
<input type="hidden" name="fredningszone_data_nonce" value="<?php echo wp_create_nonce( basename(__FILE__) ); ?>">
<!-- All fields goes below this line -->
<p>
<label for="fredningszone_data[id]">ID</label>
<br>
<input type="text" name="fredningszone_data[id]" id="fredningszone_data[id]" class="regular-text widefat" placeholder="Indtast fredningszonens ID (f.eks 450)" value="<?php echo $meta['id']; ?>">
</p>
I will appreciate, if anyone would have a suggestion on how I could parse the data into one of the fields of my custom metabox with multiple fields.

Related

How to achieve search in code for dynamic-created text using PHP code as shortcode in WordPress?

I need to move certain articles on my website, all of them, to another unique category. I am using specific phrases which are at bottom of every article, but after code execution, only two articles are moved to a new category, not all of them.
Also when I search through all posts using the native Dashboard-All posts option, it returns only those two articles, not all of them. I assume that is because the text is not stored in the database because it shows only when the post renders itself on the front end.
How can I include dynamically created text in my code?
My code, just for reference:
<?php
// Move to the category Breaking News.
$target_category_id = 1982;
// Get all posts that contain the search phrase from Syndication.
$posts = get_posts(
array(
's' => 'and has been published here with permission',
'post_status' => 'any',
'posts_per_page' => -1, // This will retrieve all posts.
)
);
// Loop through the posts and move them to the target category.
foreach ( $posts as $post ) {
// Remove the post from any existing categories.
$current_categories = wp_get_post_categories( $post->ID );
wp_remove_object_terms( $post->ID, $current_categories, 'category' );
// Add the post to the target category.
wp_set_post_categories( $post->ID, array( $target_category_id ), true );
}
That specific phrase is created dynamically because I am using the WP Broadcast plugin to add text at the bottom of every broadcasted article, but I am not sure if that phrase is stored in a database or that text is dynamically populated (created) every time post is rendered on the frontend.
This is the code I am using to generate a message (and has been published here with permission) at the bottom of every article:
<?php
function broadcasted_from() {
// Check that Broadcast is enabled.
if ( ! function_exists( 'ThreeWP_Broadcast' ) ) {
return;
}
// Load the broadcast data for this post.
global $post;
$broadcast_data = ThreeWP_Broadcast()->get_post_broadcast_data( get_current_blog_id(), $post->ID );
// This post must be a child. Check for a parent.
$parent = $broadcast_data->get_linked_parent();
if ( ! $parent ) {
return;
}
// Fetch the permalink
switch_to_blog( $parent['blog_id'] );
$blog_name = get_bloginfo( 'name' );
$permalink = get_post_permalink( $parent['post_id'] );
restore_current_blog();
// And now assemble a text.
$r = sprintf( 'This article appeared in %s and has been published here with permission.', $permalink, $blog_name );
return $r;
}
add_shortcode( 'broadcasted_from', 'broadcasted_from' );
add_filter(
'the_content',
function( $content ) {
// Get the broadcast from the text.
$sc_text = do_shortcode( '[broadcasted_from]' );
// Add the text to the content.
$content .= $sc_text;
// Return the expanded content.
return $content;
}
);

How to automatically set post title according to custom meta fields

I want to automatically set my post title according to custom meta fields for example my custom meta fields have a Name of user I want the title of the post to be the Name of User hope you can help me with this
You can use WordPress' "save_post" hook to change the post title according to post meta whenever a post is saved. Lets say you fave a post meta field called "name_of_user" and you want to change the post title accordingly
add_action('save_post', 'wpse_update_post_title');
function wpse_update_post_title($post_id) {
// If this is just a revision, don't update the title yet.
if ( wp_is_post_revision( $post_id ) ) {
return;
}
// unhook this function so it doesn't loop infinitely
remove_action('save_post', 'wpse_update_post_title');
$user_name = get_post_meta( $post_id, 'name_of_user', true );
// Check if the meta for given key exists and then update the title
if($user_name) {
$slug = str_replace(' ', '-', strtolower($user_name))
$post_update = array(
'ID' => $post_id,
'post_title' => $user_name,
'post_name' => $slug // This swill update the url slug of the post too`enter code here`
);
wp_update_post( $post_update );
}
// re-hook this function
add_action('save_post', 'wpse_update_post_title');
}
The above code should go into your theme's functions.php file

Woocommerce sending array index as value on order submission

I have been trying to add a custom 'select' field to a woocommerce checkout. The select options are comprised of entries in an array, which in turn is comprised of titles and dates from a query of custom post types.
This all works fine, I can add new custom posts and the title and dates are concatenated, added to the array and in turn added to the select drop-down at the checkout, however when I submit the form and complete the order the index of the chosen select field value is added to the meta data, not the value.
I have added images in here to show you what I mean. e.g. if I select the third option from the dropdown 'Tain Farmers Market' which is array index 2 that's what is saved for the order meta instead of the value at that index entry.
The screenshot includes the results of the var dump showing the array contents as well as the select field below it.
image of how the array appears in var dump
the order meta showing in the admin screen, displaying the index not the value
Here is my code covering this section, any pointers would be really handy. I feel there is probably some simple solution to get the value at the chosen index when the order is processed?
/**
* Add custom Pickup Field field to the checkout page
*/
add_filter( 'woocommerce_after_order_notes', 'hiwoo_add_checkout_fields' );
function hiwoo_add_checkout_fields( $checkout ) {
$args = array(
'post_type' => 'pickup-point',
'posts_per_page' => -1,
'post_status' => 'publish'
);
// Custom query to pull in the pickup points.
$query = new WP_Query( $args );
$pickup_comb_option = [];
while ($query->have_posts()) {
$query->the_post();
$postid = $post->ID;
$pickuptitle = get_the_title($post);
$pickupdate = get_post_meta(get_the_id($post), 'available_date', true);
$pickupoption = $pickuptitle . ' - ' . $pickupdate;
array_push($pickup_comb_option, $pickupoption);
}
var_dump($pickup_comb_option);
// Restore original post data.
wp_reset_postdata();
echo '<div id="custom_checkout_field"><h2>' . __('Order Pickup Location/Date') . '</h2>';
woocommerce_form_field( 'pickup_point_options', array(
'type' => 'select',
'class' => array(
'my-field-class form-row-wide'
) ,
'label' => __('Select Pickup Location/Date') ,
'placeholder' => __('Pickup Point') ,
'options' => $pickup_comb_option,
),
$checkout->get_value( 'pickup_point_options' ));
echo '</div>';
} /* Close custom field function */
/**
* Process the checkout
*/
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['pickup_point_options'] )
wc_add_notice( __( 'Please select a pickup location from the list.' ), 'error' );
}
/**
* Update the order meta with field value
*/
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['pickup_point_options'] ) ) {
update_post_meta( $order_id, 'Pickup Location/Date', sanitize_text_field( $_POST['pickup_point_options'] ) );
}
}
/**
* Display field value on the order edit page
*/
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('Pickup Location/Date').':</strong> ' . get_post_meta( $order->id, 'Pickup Location/Date', true ) . '</p>';
}
The html produced on the checkout page for the select field is:
array(3) {
[0]=>
string(32) "Tain Farmers Market - 2019-12-25"
[1]=>
string(30) "Hi Create Offices - 2019-10-25"
[2]=>
string(27) "Dornoch Stores - 2019-09-26"
}
<select name="pickup_point_options" id="pickup_point_options" class="select " data-placeholder="Pickup Point">
<option value="0">Tain Farmers Market - 2019-12-25</option>
<option value="1">Hi Create Offices - 2019-10-25</option>
<option value="2">Dornoch Stores - 2019-09-26</option>
</select>
According to your HTML I assume the value being saved in your example is "2" instead of "Tainy Farmers Market", right? If so, that is technically correct, as the value of a <select> being submitted on a form submit is always the value in the option's value attribute (<option value="2">) and not the text in between (<option value="2">Some text</option>)
To have it saving the text in between it has to be set inside the value-attribute. Therefor you need to change the option's array from numeric to associative, like so:
$pickup_comb_option = [];
while ($query->have_posts()) {
$query->the_post();
// ...
// change this line
array_push($pickup_comb_option, $pickupoption);
// to:
$pickup_comb_option[$pickupoption] = $pickupoption;
}
To verify this worked check for the generated HTML, it should look something like this:
<select>
<option value="Tain Farmers Market">Tain Farmers Market</option>
</select>
#edit
I should mention this approach has some downsides:
You should ensure that the string in $pickupoption is not used multiple times. It's also necessary that the string is valid for use as an array key (not NULL, not empty). Since the value is being written inside a html-attribute (value="$arrKey") you may also want to check how Woocommerce handle's such things as doublequotes inside the string. Just to avoid possible bugs beforehand.
An alternative approach could be to save an id instead of a string.

How to output attachment post meta on frontend in WordPress

I am creating a small plugin to add a 'data-pin-description' attribute to my images. I intend for the client to be able to add that meta data description to any image attachment from admin and then have that meta value be output to the tag on the front end, when the attachment is added to post content. I want the plugin to grab that meta data at the appropriate time and include it with the img tag data- attribute and value, before it's already output. End result should be:
My admin code seems to be accepting and saving the client-entered value just find, however I am having trouble outputting that data. One problem is I have been unable to identify which hook would retrieve and add that data to the tag at the correct time
I've tried querying the attachment posts but I don't know what action or filter to hook into
Here is how I'm adding the meta data in admin:
<?php
//exit if file is called directly
if (! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Adding a custom field to Attachment Edit Fields
* #param array $form_fields
* #param WP_POST $post
* #return array
*/
//add attachment fields
function ad_add_pinterest_fields( $form_fields, $post ) {
$field_value = get_post_meta( $post->ID, 'pin-description', true );
$form_fields['pin-description'] = array(
'value' => $field_value ? esc_textarea($field_value) : '',
'label' => __( 'Pin Description' ),
'helps' => __( 'Add a short description for Pinterest SEO' ),
'input' => 'textarea'
);
return $form_fields;
}
add_filter( 'attachment_fields_to_edit', 'ad_add_pinterest_fields', null, 2 );
//save attachment fields
function ad_save_pinterest_fields( $attachment_id ) {
if ( isset( $_REQUEST['attachments'][$attachment_id]['pin-description'] ) ) {
$pinDescription = sanitize_text_field( $_REQUEST['attachments'][$attachment_id]['pin-description'] );
update_post_meta( $attachment_id, 'pin-description', $pinDescription );
}
}
add_action( 'edit_attachment', 'ad_save_pinterest_fields' );
?>
I expect to retrieve the post_meta of each attachment image for a given post, but have only received errors
to solve this I ended up hooking into image_send_to_editor to modify the image html prior to it's being sent to the editor. this way, with the image html in the editor and correctly displaying my attribute and value, when I click 'update post' the html is saved to the database with those pieces of data. when the post is viewed on the frontend, the output from the database correctly reflects as well.

WooCommerce pagination on single product pages - but only inside parent category

I would like to put pagination on each single product page in WooCommerce so that a user can move between products in that category easier than having to go back out to the main category page every time.
I know it's possible to use the standard WordPress pagination links like…
<?php previous_post_link('« %link'); ?>
<?php next_post_link('%link »'); ?>
This works if I want to page through all products, but I only want to page through products that are within the category I'm in. Does anyone know how I can limit this so products outside this category aren't included?
I've tried using the in_same_term parameter as mentioned in the WordPress codex to get the links only showing if the next/prev product is in the same category, but it's returning an integer for some reason. Here's the code I'm using…
<?php next_post_link( '%link', '%title', TRUE, '' ); ?>
This returns nothing at all even though it follows the Codex structure. I've also tried…
<?php next_post_link( '%link %title', TRUE, '' ); ?>
And this is what I'm getting in return…
1 %title
I'm stumped where to go next.
Here is a function that I have recently written that also does the job and is quite flexible
THE IDEA:
You first need to get the current post id, which I get through get_queried_object_id(). The post ID will be used to retrieve:
The post terms the post belongs to with wp_get_post_terms(). To speed things up, only the ID's of the terms will be returned. The first ID will be used (you can modify the code here to decide which term will be used if a post have more than one term) and this will be used to retrieve all the posts which has this certain term
The post ID's of the posts that is directly adjacent to this post to determine and retrieve the next and previous post from this one
All the info above will be used in a tax_query with get_posts to retrieve all the posts that shares the term from the current post. In the function, the default taxonomy is category and the post_type is set to any to get all the posts that has this specific term
Again, to make the code faster and to safe on resources, we only going to get the post ID's as this is all that is needed
Now comes the important parts of the code. We now need to determine the following:
The current position of the current post in the returned array of post ID's from the custom get_posts query. The function used here is array_search
If there is a post before or after this post (next or previous posts, the definitions are the same as for the build in functions next_post_link() and previous_post_link()), get the ID's of these posts
Use the ID's with get_post to retrieve the next and previous post's titles from the current post
Lastly will be to return the links. I have set messages if the current post is either the first or last post in the array and there are no next or previous post. You can decide what you want to do here, and for all that matters, the rest of the code
To make the code even faster and more efficient, I have made use of the Transient API which you can read further on. I have also used the transition_post_status action hook to hook a function to delete these transients whenever the post status of a post change. This includes new posts being published, post being updated and post deleted/undeleted
THE CODE:
Here is the code. This goes into your functions.php
function get_post_link( $taxonomy = 'category', $post_type = [ 'any' ] ) {
$id = get_queried_object_id(); // Get the current post ID
$transient_id = 'post_number_' . md5( $id . $taxonomy . implode( ',', $post_type ) ); //Create a unique transient id
if ( false === ( $links = get_transient( $transient_id ) ) ) {
// Get the terms a post belongs to
$terms = wp_get_post_terms( $id, $taxonomy, array( 'fields' => 'ids' ) );
// Use a tax_query to get all posts from the given term
// Just retrieve the ids to speed up the query
$post_args = [
'post_type' => $post_type,
'fields' => 'ids',
'posts_per_page' => -1,
'tax_query' => [
[
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => $terms[0],
'include_children' => false,
],
],
];
// Get all the posts having the given term from all post types
$q = get_posts( $post_args );
//Get the current post position. Will be used to determine next/previous post
$current_post_position = array_search( $id, $q );
// Get the previous/older post ID
if ( array_key_exists( $current_post_position + 1 , $q ) ) {
$previous = $q[$current_post_position + 1];
}
// Get post title link to the previous post
if( isset( $previous ) ) {
$previous_post = get_post( $previous );
$previous_post_link = get_permalink( $previous );
$previous_title = '' . $previous_post->post_title . '</br>';
}
// Get the next/newer post ID
if ( array_key_exists( $current_post_position - 1 , $q ) ) {
$next = $q[$current_post_position - 1];
}
// Get post title link to the next post
if( isset( $next ) ) {
$next_post = get_post( $next );
$next_post_link = get_permalink( $next );
$next_title = '' . $next_post->post_title . '</br>';?><pre><?php var_dump($next_title); ?></pre><?php
}
// The returned post links
if( isset( $previous_title, $next_title ) ) {
$links = [
'previous_post' => $previous_title,
'next_post' => $next_title,
];
}elseif( !isset( $previous_title ) && $next_title ) {
$links = [
'previous_post' => 'You are currently viewing the newest post',
'next_post' => $next_title,
];
}elseif( $previous_title && !isset( $next_title ) ) {
$links = [
'previous_post' => $previous_title,
'next_post' => 'You are currently viewing the last post',
];
}
set_transient( $transient_id, $links, 7 * DAY_IN_SECONDS );
}
return (object)$links;
}
add_action( 'transition_post_status', function ( $new_status, $old_status, $post )
{
global $wpdb;
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient%_post_number_%')" );
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient_timeout%_post_number_%')" );
}, 10, 3 );
HOW TO USE:
You can now use the code as follows in you single.php. The default taxonomy is category and post type is any. If your custom taxonomy is called mytax, you can use the code like this
if( function_exists( 'get_post_link' ) ) {
$post_links = get_post_link( 'mytax' );
echo $post_links->previous_post . '</br>' . $post_links->next_post;
}

Categories