My plugin retrieves a few comments at the beginning of the post through my own WP_Comment_Query. I save these IDs so I can then alter the WP_Comment_Query request and not fetch these IDs.
When I use the pre_get_comments hook to hide these already-fetched IDs, they are also hidden from my first query at the beginning of each post. It defies the point.
$this->loader->add_action( 'pre_get_comments', $plugin_public, 'hide_the_comments' );
public function hide_the_comments( $comment_query ) {
$comment_query->query_vars['comment__not_in'] = $the_ids_to_hide;
}
How can we target the bottom request only, just like there is is_main_query() for the post loop?
Create a private variable, eg private $count = 0;
Increment it each time your function is run
Don't hide the comments if it's the first time you're running it :)
If you need to target the "main" WP_Query_Comments() within the comments_template() core function, then the comments_template_query_args filter is available since WordPress 4.5:
$comment_args = apply_filters( 'comments_template_query_args', $comment_args );
$comment_query = new WP_Comment_Query( $comment_args );
See ticket #34442 for more info and a simple example here.
Related
I have the following code snippet:
add_action('woocommerce_new_order', 'foo_function', 10);
If I create a new order from the admin panel, this fires just fine.
However, creating it via the REST API will not fire the function.
Why is that?
Update
I've tried using the following:
woocommerce_rest_insert_shop_object – this one doesn't fire at all.
wp_insert_post and save_post – they do fire, but don't contain the line items... (on the first run, it's an empty list, and on the second run (where the $update flag is true) there is an item but that item has no data (like product id or quantity).
add_action( "woocommerce_rest_insert_shop_order_object", 'your_prefix_on_insert_rest_api', 10, 3 );
function your_prefix_on_insert_rest_api( $object, $request, $is_creating ) {
if ( ! $is_creating ) {
return;
}
$order_id = $object->get_id();
$wc_order = new WC_Order( $order_id );
do_action( 'woocommerce_new_order', $order_id, $wc_order );
}
You have tried woocommerce_rest_insert_shop_object,
but the hook is woocommerce_rest_insert_shop_order_object
Please use this hook woocommerce_process_shop_order_meta instead of woocommerce_new_order As far as I can determine, woocommerce_new_order is only fired when an order is processed through the checkout. In a lot of instances, staff were creating orders in the wp-admin and assigning them straight to processing or completed, which meant that hook wasn't doing what I thought it would. Using woocommerce_process_shop_order_meta will solve it for you.
On v2 there is the woocommerce_rest_insert_{$this->post_type}_object filter
So the correct hook for what you need is woocommerce_rest_insert_shop_order_object
I have one custom post type I use for some text blocks on a page built using uncode theme. I need these blocks to be public so they display on the page but I want to stop them appearing in search results.
The search.php isn't like a normal wordpress search file, it is the uncode-theme file and doesn't have normal queries in I don't think so I'm thinking I need a function maybe?
Can anyone please advise how to achieve this?
The CPT is 'staticcontent'
Thanks!
The answer here depends on whether you're creating the CPT via your own code, or if another plugin is creating the CPT. See this link for a great explanation of both approaches:
http://www.webtipblog.com/exclude-custom-post-type-search-wordpress/
The basic gist is this:
If you're creating your own CPT, you can add an argument to the register_post_type() call of 'exclude_from_search' => true
If another plugin / theme is creating the CPT, you need to set this exclude_from_search variable later on, as part of a filter to the CPT, as such:
// functions.php
add_action( 'init', 'update_my_custom_type', 99 );
function update_my_custom_type() {
global $wp_post_types;
if ( post_type_exists( 'staticcontent' ) ) {
// exclude from search results
$wp_post_types['staticcontent']->exclude_from_search = true;
}
}
I don think accepted answer is correct. exclude_from_search prevents all $query = new WP_Query from returning results.
The core says:
...retrieves any type except revisions and types with
'exclude_from_search' set to TRUE)
This is a common problem and mixup with the front end search results page v.s. search posts in the database.
Presenting content using custom queries on front end, needs exclude_from_search = false or use another approach and get the content by id directly.
You need to filter the search front end mechanism instead. This is a true Exclude Post Types From Search, without manually re-build "known" types:
function entex_fn_remove_post_type_from_search_results($query){
/* check is front end main loop content */
if(is_admin() || !$query->is_main_query()) return;
/* check is search result query */
if($query->is_search()){
$post_type_to_remove = 'staticcontent';
/* get all searchable post types */
$searchable_post_types = get_post_types(array('exclude_from_search' => false));
/* make sure you got the proper results, and that your post type is in the results */
if(is_array($searchable_post_types) && in_array($post_type_to_remove, $searchable_post_types)){
/* remove the post type from the array */
unset( $searchable_post_types[ $post_type_to_remove ] );
/* set the query to the remaining searchable post types */
$query->set('post_type', $searchable_post_types);
}
}
}
add_action('pre_get_posts', 'entex_fn_remove_post_type_from_search_results');
And remark $post_type_to_remove = 'staticcontent'; can be changed to fit any other post type.
Please make a comment if Im missing something here, I cant find another way to prevent post type scenarios like this, showing content by query but hide from search/ direct access to front end users.
First of all, the answer by Jonas Lundman is correct and should be the accepted answer.
The exclude_from_search parameter does work incorrectly - it excludes the post type from other queries as well.
There is a ticket on WP issue tracking system, but they have closed it as wontfix because they cannot fix this without breaking the backwards compatibility. See this ticket and this one for more details.
I've added additional checks to the solution proposed by Jonas Lundman, because:
in real setups there can be other plugins trying to modify the search query, so simply replacing the post_type may cause unexpected results.
I think it's more flexible to use an array of post types to exclude.
add_action('pre_get_posts', 'remove_my_cpt_from_search_results');
function remove_my_cpt_from_search_results($query) {
if (is_admin() || !$query->is_main_query() || !$query->is_search()) {
return $query;
}
// can exclude multiple post types, for ex. array('staticcontent', 'cpt2', 'cpt3')
$post_types_to_exclude = array('staticcontent');
if ($query->get('post_type')) {
$query_post_types = $query->get('post_type');
if (is_string($query_post_types)) {
$query_post_types = explode(',', $query_post_types);
}
} else {
$query_post_types = get_post_types(array('exclude_from_search' => false));
}
if (sizeof(array_intersect($query_post_types, $post_types_to_exclude))) {
$query->set('post_type', array_diff($query_post_types, $post_types_to_exclude));
}
return $query;
}
I have created a plugin which has a separate page for order listing.. in that it looks like the same as WooCommerce's Order Listing page but. i am unable to get the comments of the order so i added my custom post type to wc_order_types after that there is no order listed.. its showing a empty table. ?
add_filter( 'wc_order_types',array($this,'add_wc_order_types'),10,3);
public function add_wc_order_types($order_types,$type){
$order_types[] = WC_QD_PT;
return $order_types;
}
apply_filters( 'wc_order_types', $order_types, $for ); is default wc_filters which takes 2 parameters you have asked for 3 here add_filter( 'wc_order_types',array($this,'add_wc_order_types'),10,3); and again supplied 2.
visit http://docs.woothemes.com/wc-apidocs/source-function-wc_get_order_types.html#149 It may help you do this.
I Solved The issue just by adding a if condition in my hook's function
function add_wc_order_types($order_types,$type){
$order_type = $order_types;
if('' == $type){
$order_type[] = WC_QD_PT;
}
return $order_type;
}
http://localhost/wordpress/give-api/forms/?key=15443f18029e6f5d3b65d04e1640ffbe&token=c3de770a410282359413c74a588c5c74
The above link is a plugin api link. Above link won't work to your browser.
when I set the above link in the browser , it returns array object like http://postimg.org/image/6ozmjy0e7/ .
My question is , how can I set this url in a variable in wordpress and how can I get the data from that array object. I just want to get the data from that array object. If any other process is available, then please suggest me. Thanks...
In functions.php:
function displayApiUrl() {
global $apiUrl; // you probably don't actually need to set it global as it is a function
$apiUrl = 'http://localhost/wordpress/give-api/forms/?key=15443f18029e6f5d3b65d04e1640ffbe&token=c3de770a410282359413c74a588c5c74';
return $apiUrl;
}
In your theme you can now use:
<?php $api = displayApiUrl(); ?>
With that you can process your array in a foreach loop:
<?php
$json_url = file_get_contents($api);
$json_data = json_decode($json_url, true);
foreach ($json_data['forms'] as $form) {
$form_id = $form['info']['id'];
echo $form_id;
}
?>
The new "standard" for WordPress rest apis is Json Rest API, which will be partially integrated into WordPress core in the next release.
You can get it here https://wordpress.org/plugins/json-rest-api/ and documentation at http://wp-api.org/
In terms of the question how to put array information into the URL, the format is
http://www.example.com/wp-json/endpoint?array_1[key1]=Pensacola&array_1[key2]=Florida
The URL of course changes, and the wp-json/endpoint is replaced with whatever the final endpoint is for which ever rest api you choose to use.
Using the autocomplete field for a cck nodereference always displays the node id as a cryptic bracketed extension:
Page Title [nid:23]
I understand that this ensures that selections are unique in case nodes have the same title, but obviously this is a nasty thing to expose to the user.
Has anyone had any success in removing these brackets, or adding a different unique identifier?
Ultimately, you need to change the output of nodereference_autocomplete() in nodereference.module.
To do this properly, you want a custom module to cleanly override the function.
This function is defined as a menu callback, thus,
/**
* Implementation of hook_menu_alter().
*/
function custom_module_menu_alter(&$items) {
$items['nodereference/autocomplete']['page callback'] = 'custom_module_new_nodereference_autocomplete';
}
Then, copy the nodereference_autocomplete function into your custom module, changing it's name to match your callback. Then change this one line:
$matches[$row['title'] ." [nid:$id]"] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';
Dropping the nid reference.
$matches[$row['title']] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';
I believe the identifier is purely cosmetic at this point, which means you could also change the text however you like. If it is not purely cosmetic, well, I haven't tested to see what will happen in the wrong conditions.
I always meant to identify how to do this. Thank you for motivating me with your question.
What Grayside has posted will work... as long as you don't have two nodes with the same title. In other words, if you want to do as Grayside has proposed, you need to be aware that the nid is not entirely unimportant. The nodereference_autocomplete_validate() function does two things. It checks to see if there is a node that matches, and if so, it passes the nid on, setting it to the $form_state array. If it can't find a node, it will set an error. If the nid is present, it will be used to get the node, which also is faster, the code is here:
preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches);
if (!empty($matches)) {
// Explicit [nid:n].
list(, $title, $nid) = $matches;
if (!empty($title) && ($n = node_load($nid)) && $title != $n->title) {
form_error($element[$field_key], t('%name: title mismatch. Please check your selection.', array('%name' => t($field['widget']['label']))));
}
}
This just checks to see if there is a nid and checks if that node matches with the title, if so the nid is passed on.
The 2nd option is a bit slower, but it is here errors can happen. If you follow the execution, you will see, that if will try to find a node based on title alone, and will take the first node that matches. The result of this, is that if you have two nodes with the same title, one of them will always be used. This might not be a problem for you, but the thing is, that you will never find out if this happens. Everything will work just fine and the user will think that he selected the node he wanted to. This might be the case, but he might as well have chosen the wrong node.
So in short, you can get rid of the nid in the autocomplete callback, but it has 2 drawbacks:
performance (little)
uncertainty in selecting the correct node.
So you have to think about it, before going this route. Especially, since you most likely wont be able to find the problem of the selection of the wrong nodes, should it happen. Another thing to be aware of, is that the nid showing up, also brings some valuable info to the users, a quick way to lookup the node, should they be in doubt if it is the one they want, if several nodes have similar titles.
I got Grayside's answer to work, but I had to use MENU alter, instead of the FORM alter he posted. No biggy!
function custommodule_menu_alter(&$items) {
$items['nodereference/autocomplete']['page callback'] = 'fp_tweaks_nodereference_autocomplete';
}
I've found an alternative solution is to change your widget type to select list and then use the chosen module to convert your list to an autocomplete field.
This handles nodes with the same title, and actually I think the UI is better than the one provided by the autocomplete widget.
To anyone coming across this (rather old) topic by way of a google search - for Drupal 7 please consider using entityreference module and "Entity Reference" field type if possible.
You can acheive a lot more in configuration with an "Entity Reference" field. It doesn't have this problem with the nid in square brackets.
Here is the full Drupal 7 version (References 7.x-2.1) of Grayside's answer. This goes in your custom module:
/**
* Implementation of hook_menu_alter().
*/
function custom_menu_alter(&$items) {
$items['node_reference/autocomplete/%/%/%']['page callback'] = 'custom_new_node_reference_autocomplete';
}
/**
* Implementation of Menu callback for the autocomplete results.
*/
function custom_new_node_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
$field = field_info_field($field_name);
$instance = field_info_instance($entity_type, $field_name, $bundle);
$options = array(
'string' => $string,
'match' => $instance['widget']['settings']['autocomplete_match'],
'limit' => 10,
);
$references = node_reference_potential_references($field, $options);
$matches = array();
foreach ($references as $id => $row) {
// Markup is fine in autocompletion results (might happen when rendered
// through Views) but we want to remove hyperlinks.
$suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
// Add a class wrapper for a few required CSS overrides.
$matches[$row['title']] = '<div class="reference-autocomplete">' . $suggestion . '</div>'; // this is the line that was modified to remove the "[nid:XX]" disambiguator
}
drupal_json_output($matches);
}