According to the Codex:
[...] This function can be extremely costly in terms of performance. It should be used as sparingly as possible - such as during activation or deactivation of plugins or themes. Every attempt should be made to avoid using it in hooks that execute on each page load, such as init.
Ok, so, I know it shouldn't be used in every page load and I'm not, but I still need a very conditional rewrite rule on this project.
I have these 2 url structures:
- example.com/products/tables/fancy-computer-table //This is a product url, here I expect the normal behavior from wp.
- example.com/products/tables/office //This should be some kind of a filter, where the site gets all the tables related to the office department. Note how both URL structure matches.
To make it work, I narrowed it down to these very specific URLs, using some regex. If matched, I'll run 2 queries to verify if the url I'm in is for the filter I want that rule to apply, or if it's a product url. In the latter, I want wordpress to behave normally. But I have to flush the rules either way, whether it's a product or it's the category and the filter, so that both pages work properly and dinamically.
I do all this to narrow down the use of this function to the least possible, but the Codex doesn't really tell me how bad it does affect the performance, or why.
I'm passing the parameter on that function as false by the way, so it doesn't rewrite my htaccess file, but I'm not sure where that rewrite rule option is stored, if it's on the memory somewhere, or on the database, wish they would provide some clarification on that.
Thanks in advance for reading this question. Any pointers are appreciated here, even if you want to point me to some other way of doing this. :)
EDIT: Posting some code here so you guys can actually understand what I mean and let me know if this maybe this could be bad practice... maybe a suggestion on how to do it better.
<?php function custom_rewrite_products()
{
// regex to match either "products/tables/fancy-computer-table" or "products/tables/office"
preg_match('#products\/([^\/]+)\/([^\/]+)\/?#', $_SERVER['REQUEST_URI'], $url_matches);
if(is_array($url_matches)) {
$query_category = new WP_Query('category_name='.$url_matches[1]);
$query_category->get_posts();
$args = array(
'post_type' => 'filters',
'name' => $url_matches[2]
);
$query_post = new WP_Query($args);
$query_post->get_posts();
if($query_category->have_posts() && $query_post->have_posts()) {
$category_ID = '';
$filter = '';
$category_ID = '' . $query_category->query_vars['cat'] . '';
$filter = '' . $query_post->query_vars['name'] . '';
$string = "index.php?cat={$category_ID}&filter={$filter}";
add_rewrite_rule('products/([^/]+)/([^/]+)/?$', $string, 'top');
}
global $wp_rewrite;
//Call flush_rules() as a method of the $wp_rewrite object
$wp_rewrite->flush_rules(false);
}
}
add_action('init', 'custom_rewrite_products');
I still don't understand why, but the flush is needed here, so the $category_ID and $filter variables actually get passed to the rewrite rules. If I take it out, the rewrite just goes to the index page, the place where the values should be are empty.
In case you're wondering, I created the filters on a custom post type and they are related to each post by using a custom field, since they're like four or five and they're present on every category on this project. As you can see, I already have a category/subcategory structure and I didn't find it smart to create these filters once again by hand inside each main category.
There is a 'rewrite_rules' record in the 'wp_options' table that includes all the rewrite rules. When calling flush_rules(), WordPress will clear this record and regenerate all the new rules, including the ones you're not changing.
Related
I have function that update post content automatically based from custom field like this:
function update_content(){
$mycustomfield = get_post_meta( get_the_ID(), 'customfield', true);
$post = array();
$post['ID'] = get_the_ID();
$post['post_content' ] = $mycustomfield ;
$post['post_title' ] = $mycustomfield ;
// Update the post into the database
wp_update_post( $post );
We update only custom field to make content. For now, we launch this function manually on save_post hook, but the articles are so many and we need now a cron to automate this function: process 4 posts every hour until all posts are completed, then start over.
How to make this, thank you
WordPress actually has a built-in psuedo cron system called WP Cron. It doesn't function exactly like a proper server cron, but can perform a similar function in many cases. You can find documentation on it here:
https://developer.wordpress.org/plugins/cron/#:~:text=WP%2DCron%20is%20how%20WordPress,post%2C%20utilize%20WP%2DCron.&text=WP%2DCron%20works%20by%20checking,what%20needs%20to%20be%20run.
However thinking about your use case and looking at your function above, I'm wondering what the purpose of your cron is? It looks from that function like all you're doing is taking some content already in your database and putting it somewhere else. Why? Why not simply display your custom field in the correct spot? Or better yet, use the fields as intended?
Even if that is necessary - maybe I don't understand fully from the example above - I think your initial inclination to run this on save_post is much more correct. Unless there's some information external to your site that's changing, the only time these values will change is when you save the post. So what is the purpose of running it on a schedule?
So I am trying to get custom post values in WP. The thing is I can have multiple custom fields value. So I don't want to hard code in the code. What I am thinking of doing is providing the a prefix in the key value something like
abc_email
abc_website
So I want to use this function
get_post_meta
or some other to get all the key,value pair that starts with abc. That way I can just add values on the back end and don't have to update my code. One way would be to get all the meta data using above function and then loop over it and filter. But is there any other way where I can send in the pattern I am looking for?
Thanks
You could directly query the database for a posts entries containing the prefix (relevant table etc here https://wordpress.stackexchange.com/questions/104434/where-are-custom-field-values-stored-in-the-database )
but this is more complex, still involves a loop and doesn't provide you with anything you could do using WP and PHP. If you want to cater for unknowns you will have to loop or interogate an index etc.
I may be missing something in your question but this seems straight forward:
You are trying to avoid this scenario:
process_field($abc_known1);
process_field($abc_known2);
// continually edit code for new entries e.g.:
process_field($abc_NEW1);
Something like this will handle later additions without modification.
// get array of ALL cust fields for post
$all_cust_fields = get_post_meta( get_queried_object_id());
foreach ($all_cust_fields as $key => $value) {
// some function for determing if $value starts with "abc_"
// if so either:
// add to an "abc" array for later use/processing
// or take action in this loop e.g.
process_field($value);
}
I am not sure whether you are talking about keys or values prefixed "abc_" but the same principle applies.
you should write code like this,
$email_meta = get_post_meta( 'your_post_id', 'abc_email', true );
$website_meta = get_post_meta( 'your_post_id', 'abc_website', true );
Or
you can follow these links,
example
example
Hope this will help you.
I have some block views in my sidebar that show events marked as a highlight happening in certain cities. Nodes are organized into cities using taxonomy.
When I load a node directly I have an URL like www.host.com/events/new-york/name-of-my-nice-event
I have some other page views that show teasers for all events in a certain city: www.host.com/events/new-york
Also I have some static pages that are valid for all cities, e.g. www.host.com/about-us
The sidebar blocks showing the highlights are available throughout the whole website. Now I want to make sure that the blocks in my sidebar only show those nodes for the selected city based on the taxonomy provided in the URL. (except for the static pages as there is no taxonomy in the URL, but those are not that important)
So far I tried to pass my view the taxonomy term as an argument using PHP as standard argument:
if (arg(1)) {
$term = arg(1);
return $term;
}
This works fine on the above mentioned page views (e.g. www.host.com/events/new-york). But when I load a node directly www.host.com/events/new-york/name-of-my-nice-event my block only shows the empty text.
I thought that arguments are indexed like this:
events/new-york/name-of-my-nice-event
^0 ^1 ^2
So I don't understand why arg(1) does not return new-york when I am viewing the node detail.
First of all, with path and path auto what you see is not always what you get.
Fx I could setup pathauto for my articles nodes to generate urls like this
content/article/[title]
So if I wanted the title I should use arg(2) right?
No! (arg(2) is actually NULL in this case.)
The reason is that the url that's generated by path auto is a fake url, that gets translated into a Drupal url. In the case above what I get is node/[nid]. So eventhough the node title i in the url, I can't get it by using arg(), but I can get the nid by using arg(1)
I can't guess what your urls map to, it depends how you have set up your site what modules you use etc.
A good advice if you do a lot of these context aware things, is to look into panels. It's made to be able to tell modules like views about the context which it is present. Like fx terms, nodes, etc, and you could use this to pass arguments into views.
Panels can do a lot more and is quite complex, but if you need to do a lot of this stuff, it is probably worth the investment.
Solution to my problem:
if (arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1));
if (count($node->taxonomy) > 0) {
foreach ($node->taxonomy as $term) {
$term = $term->name;
}
}
$term = strtolower($term); // for some reason needed in my case
}
else {
$term = arg(1);
$term = str_replace('-', ' ', $term); // for some reason needed in my case
}
return $term;
While this was technically possible with Views 2 as described in some of the other answers, Views 3 has this integration built in.
You can create an argument for the taxonomy term id and then choose "Provide default argument". This will then give you an option for "Taxonomy Term ID from URL" and "Load default argument from node page..."
This will allow you to take the taxonomy of a page and pass that as an argument to your view block.
Note: Views 3 is currently in Alpha 3 but in my experience is at a relatively stable state and I am using it on production sites. If it has features like the one above that you find useful please use it, test it and submit bugs/patches if you encounter any issues!
I was wondering which is the best approach to get the catgeory ID when listing the posts within a particular category. Normally, the urls look something like this : www.example.com/?cat=4 and it is pretty easy to get the id. However, I really need the urls to be routed like this www.example.com/categories/hotels . wordpress provides an easy way to do the "pretty" routing, however all of the GET paramater information is lost this way. In this case, the $_GET variable is assigned nothing. I need to be able to say $category = $_GET["cat"] or something like that
What is the easiest approach ?
Can you use the Wordpress get_the_category function to grab the ID (from member variable cat_ID) once you're in the template?
See http://codex.wordpress.org/Function_Reference/get_the_category
e.g.
foreach((get_the_category()) as $category) {
$id = $category->cat_ID;
// do something with $id
}
The thing is that the guy might not really want to associate categories with post ids. In this case, there's the global $wp->query_vars array that contains all the data coming from the GET request even when the routing has been "prettified"
What about the category base setting in the backend? "Configuration" > "Permalinks" and there the last paragraph. See here for docs.
I'm trying to filter ALL widget output through a simple filter, but can't find any hooks and was hoping to be pointed in the right direction. Or possibly my efforts are not even possible?
My simple filter is something like this:
function clean_widget_output( $input ) {
return str_replace( array( "\t", "\n", "\r" ), '', $input );
}
add_[FILTER OR ACTION]( 'need_a_hook', 'clean_widget_output', 99 );
Any ideas? I'm pretty new to PHP, but I can get around.
This was borne out of the need/desire to clean the god-awful HTML spewed by WordPress' widgets. I love what they do, but some of the output makes me cry.
The short answer is output buffering because I couldn't find any widget or sidebar hooks.
The long answer is:
function tidy_sidebar( $sidebar_name_or_id )
{
ob_start();
$bool = dynamic_sidebar( $sidebar_name_or_id);
if ( $bool )
{
$str = ob_get_contents();
$str = 'do cleanup stuff...';
}
else
{
$str = '';
}
ob_end_clean();
return $str;
}
Then call echo tidy_sidebar( 'sidebar-name-or-id' ); from your theme.
I had a similar issue and after looking through Adam Brown's list of all WordPress filter hooks, found that the hook I needed does exist (widget_title, as pxl mentions), but that there is no hook to get all widget output. I thought I'd elaborate on the solution that worked for me.
Theoretically, the widget_title hook should affect all widgets on your blog, but I'm sure some 3rd party widgets neglect to include the necessary line of code to apply any title filters, so it's not foolproof. It worked for me, however, and it can be used to apply custom 'shortcode' (more accurately, in this case, 'longcode') or syntaxes to your widget titles. For example, I wanted to occasionally include html code in my widget titles, but by default, all html is stripped out. So, in order to be able to add things like <em> tags to text in some of my titles, I chose a custom syntax: [[ instead of < & ]] instead of > (for ex, [[em]] and [[/em]]) and then created a function in my theme's functions.php file to process that custom syntax and replace it with the html equivalent:
function parse_html_widget_title( $text ) {
return str_replace(array('[[', ']]'), array('<', '>'), $text);
}
Then I added a line below it to add the function as a filter:
add_filter('widget_title', 'parse_html_widget_title', 11); // 11 is one above the default priority of 10, meaning it will occur after any other default widget_title filters
The add_filter / apply_filter functionality automatically passes the content being filtered as the first parameter to the function specified as the filter, so that's all you need to do.
In order to do something similar for the main output of the widget, you would need to look at all your widgets to see what hook they use and verify that they have a filter for their main output, than use add_filter() for each hook you find with your custom callback function (for example, it's widget_text for the Text widget output, or get_search_form for the search form [you can see it in wp-includes/general-template.php, at the get_search_form() function]). The problem is that some of the dynamically generated widgets don't have hooks (like the Meta widget), which is why the output buffering solution Jeff provides is the most versatile, though not ideal, solution.
there are lots of hooks for wordpress widgets that aren't documented. The wordpress codex doesn't list them, for whichever reason (such as these hooks may change in the future and will break unexpectedly with new updates and versions)... so use these with extreme caution.
to find out what they are, there are at least 2 places to look:
<wordpress install directory>/wp-includes/default-filters.php
<wordpress install directory>/wp-includes/default-widgets.php
contained in those two files is a pretty good listing of all the hooks wordpress uses.
An example would be a filter for widgets is widget_title
again, use these with caution, they're not guaranteed to work past the specific version of the code you're looking at.
I'm not sure when they introduced the widget_text filter, maybe they didn't have it in '09 when this question was originally asked, but since it's there now, and for the sake of anyone that gets this stackoverflow like I did from google and just happens to read far enough down to see this answer, it's now actually quite simple:
function my_widget_filter( $content )
{
// manipulate $content as you see fit
return $content;
}
add_filter( 'widget_text', 'my_widget_filter', 99 );
Also maybe check out the dynamic_sidebar_params filter --
Another link --