Silverstrip 4 Show categories which have post - silverstripe-4

I have 6 categories as shown in the image . I have posts in finance and enterprise
categories . Ao i dont want to show the other categories in the drop down . and when i add a new post to other category suppose for aircraft then aircraft should also show in the drop down . how can i acheive that .
i have tried the following filter but it did not work
filter(array('ParentID' => $this->ID , 'EventDate:GreaterThan' => $curDate))
Thanks

You can try something like this:
// In this query I assume you got this structure -> [Category 'has_many/many_many' Posts]
$categoriesWithImages = Category::get()->filter([
'Posts.ID:GreaterThan' => 0,
'Posts.EventDate:GreaterThan' => $curDate,
]);

Related

How to retrieve the latest categories assigned to a post currently under editing?

I need to limit the post tile length of a post belonging to a specific category while editing. So I need to check what categories have been assigned to the post under editing and decide whether to limit or not its post title.
I use "wp_insert_post_data" to do the job
add_filter( 'wp_insert_post_data' , 'limit_title_length' , '99', 2 );
But what I found is that the categories returned from passed $postarr are existing categories. Not the latest categories. So it would not work for new post or if categories being changed while editing.
$post_category = $postarr['post_category'];
I also checked get_the_category() inside the function, and that also returns existing categories, not the latest categories if category assignment changed.
My codes so far...
function limit_title_length( $data, $postarr ) {
// set up variables like max length, category id to limit
...
// get post id, title and categories from $data and $postarr passed
$title = $data['post_title'];
$id = $postarr['ID'];
$post_category = $postarr['post_category'];
// check if the specified category exists in the categories assigned to this post
...
// process $title, reset $post_title in $data
...
$data['post_title'] = $title;
return $data;
}
add_filter( 'wp_insert_post_data' , 'limit_title_length' , '99', 2 );
wp_insert_post_data fires in the very late stage of post publishing. I expected to get the latest categories from $postarr['post_category'];
but it's not in my case here. Any solutions or alternatives?
So just to be clear - You want to identify the most recent category added to a post?
If this is the case you will be hard pressed to do so as Wordpress does not save meta for added categories. If you are skilled enough you could script such a function and save the data in a custom table. Then retrieve it for use.
If you know the name of the category you are looking for you can use has_category! .

Use another product as option - WooCommerce

Before I get too far down this rabbit hole...
I have a product in a category that is essentially a selection of 4 other products. It can be any combination of select products. Pricing is based off of regular price for those products.
What I've managed so far
Controlled through normal WooCommerce attributes interface. Admin puts in an attribute use-for-custom with the value being the category of item, i.e. cupcakes
The result is an association to a product slugged custom-assortment in the cupcakes category. This product will be an option for any/all of the 4 selections in the custom-assortment product in cupcakes category.
I also have a function in functions.php that queries all products with this set attribute and builds a neat little array of id/title/cost. I managed that via this post earlier, plus
$useable = array();
foreach ($products as $product){
$useable[] = array(
'id' => $product->ID,
'name' => $product->post_title,
'desc' => $product->post_excerpt,
'cost' => floatval(wc_get_product($product->ID)->get_price())/4
//cost is 1/4 as 4 will be selected to create 1 new product
);
}
Notes
It does not need to actually relate the selection back to a particular product. Having the selected product name(s) shown in the final order is enough for the admin. However, it would be nice to keep that reference as it may lead to additional functionality later.
Not concerned with stock at the moment, or any other attributes from the selected products except price.
Thoughts
I've tried a little to get custom variations to create programmatically via this post from LoicTheAztec, but so far I haven't gotten them to show up. I might be able to with a little more poking as his stuff is usually spot-on.
foreach ($useable as $useit){
$display = $useit['name'] . " (" . $useit['cost'] . ")";
$variation_data = array(
'attributes' => array(
'flavor-one' => $display,
'flavor-two' => $display,
'flavor-three' => $display,
'flavor-four' => $display
),
'sku' => '',
'regular_price' => $useit['cost'],
'sale_price' => ''
);
var_dump($product->get_id());
create_product_variation($product->get_id(), $variation_data);
}
Alternatively, I could probably create the drop-down selections manually and run a filter on the price based on selections. That seems like a lot of manual recreation of functionality though - checking validity, pricing, etc.
Final question
Is there a way to use one product as a variable product attribute for another product already? It doesn't seem like something far-fetched, but I haven't been able to google-foo anything. My google-foo has not been great recently.
Assuming a single product that can be any combination of 4 of 10 other products, using variations means 10,000 possible products added. That seems unreasonable, so I went with the option of doing this another way.
Will expand this answer with code shortly, but basically:
Query posts to get product type posts with the custom attribute grouping it with this configurable option. Output these as select elements with options of items in the add-to-cart form. Option values as product IDs and displayed as product name + price for that option.
Hook to the add to cart action to check options (passed in the $_POST) and store them as attributes on the cart item.
Hook to the cart pricing filter and use the cart item attributes to calculate final product price based on the assortment products' original prices.
Also:
add attribute display to the cart
add front-end control to display changing price with the changing attributes

Drupal: custom taxonomy page, exclude nodes with some taxonomy child (without views module)

i have a news aggregator project.
in this project i have categories like this.
sport
sport:football (tick)
sport:basketball(tick)
sport:volleyball
sport:Tennis
politic
politic:your country (tick)
politic:others
above tree shows how users want news to be aggregated.
i save all selected and not selected taxonomies in two different variable for each user in database as an array width function variable_set
now i want in sport taxonomy page, default drupal page, only shows nodes that football and basketball is their category, and nodes from tennis and volleyball will not be shown.
i mean overriding behaviour of default taxonomy pages.
i know this can happen with views module buttttt number of taxonomies is not fixed. it will be more and more during the life of the news aggregator website. now the number of them now is more than 340 taxonomies.
now i have written this code. this code. this codes works well but i want in parent taxonomy page, nodes shows that user collected their subchildren taxonomy.
function caspian_bartik_menu_alter(&$menu) {
$menu['taxonomy/term/%taxonomy_term']['page callback'] = 'caspian_bartik_term_page';
$menu['taxonomy/term/%taxonomy_term']['access arguments'] = array('access content');
$menu['taxonomy/term/%taxonomy_term']['page arguments'] = array(2);
}
function caspian_bartik_term_page($term){
$voc = taxonomy_vocabulary_load($term->vid);
// here you generate the actual content of the page
// could be done e.g. with an entityfieldquery as follows
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node')
->fieldCondition('field_category', 'tid', $term->tid , '=')
->fieldCondition('field_category', 'tid', array(135) , 'NOT IN')
->propertyOrderBy('created', 'DESC');
$result = $query->execute();
if (!empty($result['node'])) {
$build['content']['nodes'] = node_view_multiple(node_load_multiple(array_keys($result['node'])), 'teaser');
} else {
$build['content']['status']['#markup'] = t('No results found for term ID !tid.', array('!tid' => $term->tid));
}
return $build;
}
this line does not work
->fieldCondition('field_category', 'tid', array(135) , 'NOT IN')
thanks for your help.
When you say
this line does not work
does the PHP application crashes or you don't get the result you expect ?
This query logic seems to be weird
->fieldCondition('field_category', 'tid', $term->tid , '=')
->fieldCondition('field_category', 'tid', array(135) , 'NOT IN')
Imagine your $term->tid = 1. You are selecting the field_category where tid is 1 AND $term->tid NOT IN (135). This will give you nodes attached to 1 category and not multiple ... Is this what you want?

Wordpress get attachment of post doesn't work

I'm trying to retrieve all the attachment of a specific post, but it doesn't work for the moment. Here is the code :
$args = array(
'post_type' => 'attachment',
'posts_per_page' => -1,
'post_parent' => $id
);
$attachments = get_posts($args);
Where Id is the id of my post. I've tried also with new WP_Query() but it didn't worked neither. Both ways return an empty result.
Does anyone have an idea what I'm doing wrong here ?
Thanks
EDIT
Ok, I think I know what's going wront.
When using this arguments for the get_posts function, it will return the images uploaded through the "Add a media" button in the specific post.
So basically, let's say that on my first post, I've uploaded all the images I would need for all my future post. If I apply the request on the first post, I will retrieve all the images, even the one that I don't use in this post.
If I apply this function to another post, because I didn't uploaded any file in this post, the function will retrieve an empty array.
Does anyone have an idea how I can retrieve all the images used in a specific post ? So not only uploaded, but really integrated into the post or added to a custom field ?
Thanks
When using get_posts to fetch attachments, you need to set post_status to inherit. Also, check out the get_children function:
$args = array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'numberposts' => -1,
'post_status' => 'inherit',
'post_parent' => $id
);
$attachments = get_children( $args );
Case: using ACF, I created an repeater field 'resort_pics' for my gallery, which has 2 fields 'picture_title' as text and 'picture' as an picture type.
Then happily uploaded 100 photos, some of them were same for several posts so I only clicked those from uploaded gallery (I will use term of "referenced images" for those).
Problem : then one happy day I noticed all "referenced images" are missing in our api.
Cause :
As noted at documentation comment from 'Uriahs Victor' (https://developer.wordpress.org/reference/functions/get_attached_media/)
Important to note that this function only returns the attachments that
were first uploaded/added to the post. Uploading an image to Post A(ID
1) and then adding that image later to Post B(ID 2) would give an
empty array if the following code was used:
$media = get_attached_media( 'image', 2 );
var_dump( $media );
Real cause :
Real source of all this problem is The thing that information about "reference images" are not stored in 'wp_posts' table but are actually stored in 'wp_postmeta', so by just querying 'wp_posts' table or using get_attached_media() which only looks there also you will not get all attachements for post.
Solution :
Lets take an example of post with ID - $postId which has defined
repeater - 'resort_pics', field in repeater with image 'picture'. (created with ACF plugin)
First get all attachements for our post (resort) (including images/pdfs and so on) with classic way (can be also used 'get_attached_media'):
$images = $wpdb->get_results("select ID,guid from wp_posts where post_parent = " . $postId . " and `post_type`= 'attachment'");
where guid is 'url' to an attachement, lets index those in array where key will be post id of an attachement
$mapImages = [];
foreach ($images as $image) {
$mapImages[$image->ID] = $image->guid;
}
Now we have all atachements but are missing all referenced images/files.
Lets continue by selecting all meta for our post (resort).
$metas = $wpdb->get_results("select meta_key,meta_value from wp_postmeta where post_id=" . $postId);
And index them by an meta key
$mapMetas = [];
foreach ($metas as $meta) {
$mapMetas[$meta->meta_key] = $meta->meta_value;
}
Lets say our post ($postId) has an 9 entries in 'resort_pics' with an image uploaded to its 'picture' field, then $mapMetas['resort_pics'] will have an value of 8.
Now the way how repeater fields keys are stored in $mapMetas array, is actually an :
'resort_pics_0_picture' -> itsPostId (5640 for example)
'resort_pics_1_picture' -> itsPostId (5641 for example)
'resort_pics_2_picture' -> itsPostId (5642 for example)
...
'resort_pics_8_picture' -> itsPostId (5648 for example)
Knowing this we can get simply all image urls for "resort_pics"
for ($i = 0; $i < $mapMetas['resort_pics']; $i++) {
$picture = [];
$picture['name'] = $mapMetas['resort_pics_' . $i . '_picture_title'];
$picture['url'] = $mapImages[$mapMetas['resort_pics_' . $i . '_picture']];
$pictures[] = $picture;
}
You may already get to this point, simply from $mapMetas get image ID and using it get an image url from $mapImages.
Lets say 'resort_pics_1_picture' is 'referenced' one (not directly uploaded image), we have its id '5641' but since its not connected to our $postID but to some other post id when it was actually uploaded. Its missing in our $mapImages array, so lets edit this code a bit.
for ($i = 0; $i < $mapMetas['resort_pics']; $i++) {
$picture = [];
$picture['name'] = $mapMetas['resort_pics_' . $i . '_picture_title'];
$picture['url'] = getAttachmentOrItsReferenceUrl('resort_pics_' . $i . '_picture', $mapImages, $mapMetas);
$pictures[] = $picture;
}
We have added an getAttachementOrItsReferenceUrl() method, which will simply first check if we already have this image (all uploaded to this post) and if not will fetch image data by its post id from 'wp_posts' table..
function getAttachmentOrItsReferenceUrl($code, $allAttachmentById, $allPostMetaByKey) {
global $wpdb;
$attachmentUrl = $allAttachmentById[$allPostMetaByKey[$code]];
if($attachmentUrl === null && isset($allPostMetaByKey[$code]) && $allPostMetaByKey[$code] !== '') {
$attachments = $wpdb->get_results("select ID,guid from wp_posts where ID = " . $allPostMetaByKey[$code]);
foreach ($attachments as $image) {
return $image->guid;
break;
}
} else {
return $attachmentUrl;
}
return "";
}
Finnal thoughts :
If you know your fields structure you can build up its key pretty straightforward
For an example
'rooms' repeater which has inside 'room_gallery' repeater which has inside 'image' image field.
'rooms_0_room_gallery_0_image'
--
$mapMetas['rooms'] - number of rooms
$mapMetas['rooms_' . $i . '_room_gallery'] - number of gallery images for room
--
'rooms_' . $i . '_room_gallery_' . $j . '_image'
How heavy is it ? Not really, if you are like me, having only small amount of referenced images you wont even feel it. All we added to load is an one meta query for an post, if no images are referenced that's all, then for every referenced image there is one more query, but its query on ID should be fast. There is a lot of way how to make load less, for example not do query for every single missing image, but do single query at the end with 'where in (id1,id2..)' to have single query to get all, or after fetching new image data, store it in some global array by its id, and check this array before fetching image for next posts (so if one image is stored in 200 posts, and you are fetching all it would make only 1 query), you got the point I leave it just at the ideas since this is bloody long post even without that :)
Hope this will help anybody in future.

Programmatically filter nodes based on their taxonomy term

I've got a session variable containing an ever changing city name.
Example - $_Session['Toronto'];
I've also got a list of unfiltered nodes with lots of fields. Most importantly they have a taxonomy term field called 'city'.
I need to be able to only display the nodes with the taxonomy terms that match the $_Session['Toronto'].
Example - Node 9 and 10 have taxonomy terms of 'Toronto' and 'Ottawa'. I will only want the node with the term of 'Toronto' to display on the page.
Any help?
With views, you can use hook_views_query_alter
D7 example
function YOURMODULE_views_query_alter(&$view, &$query){
switch ( $view->name ){
case 'YOURVIEWNAME':
$query->where[1]['conditions'][] = array(
'field' => 'term_field_name', //your term name in the sql query
'value' => $_Session['Toronto'],
'operator' => '='
);
break;
}
}

Resources