I'm pretty new to PHP so perhaps lacking some basics so here goes.
For WordPress I've a function for replacing some text from a TablePress table. The function worked fine when I used code along these lines:
function replace_stuff($text) {
if (is_front_page() || is_page('2611') || is_child('2611')) {
$replace_magic = array(
//text to search => text to replace
'dog' => 'cat',
'mouse' => 'elephant'
);
}
$text = str_replace(array_keys( (array)$replace_magic), $replace_magic, $text);
return $text;
}
add_filter('tablepress_table_output', 'replace_stuff');
So in that example dog would be displayed on the frontend as cat & mouse as elephant.
But now I would like to complicate things & create the strings to replace by querying fields from all posts in a custom post type "drivers".
I have come up with something like this, with the aim of finding any text that matches the post title & replacing with text from a custom field (of all posts from my 'drivers' custom post type), but it doesn't do anything!
function replace_stuff($text) {
if (is_front_page() || is_page('2611') || is_child('2611') || get_post_type() == 'drivers') {
query_posts('post_type=drivers');
if (have_posts()) :
while (have_posts()) : the_post();
$profilenat = get_post_meta($post->ID, 'driver_nationality', true);
$profiletitle = get_the_title();
$replace_magic = array(
//text to search => text to replace
$profiletitle => $profilenat
);
endwhile;
endif;
}
$text = str_replace(array_keys( (array)$replace_magic), $replace_magic, $text);
return $text;
}
add_filter('tablepress_table_output', 'replace_stuff');
Could anyone advise me please?
Many thanks.
Firstly I think you need to replace
$replace_magic = array(
with
$replace_magic[$profiletitle] = $profilenat
Currently, if everything else works, then for every driver you are completely replacing the contents of $replace_magic with a new array, which just has that driver's details. Instead you want to add a new item to the existing array.
Going further, with this sort of problem it can be really useful to do some quick debugging to help you narrow down where the problem might be. So here it would be useful to know if the problem is really with your str_replace, or if it's actually with the code above it.
Debugging in Wordpress is worth a read, and having done that you can use error_log to output some details to debug.log inside your wp-content directory.
Before your str_replace, doing
error_log(print_r($replace_magic));
Would tell you if your query loop has worked as you intended or not.
If it hasn't, you might then put a log statement inside the loop. This will tell you if the loop contents are being executed at all (in which case the problem is with your code inside the loop), or not (in which case the problem may be with your query).
Additionally, if you haven't already I would recommend checking the WordPress Codex on query_posts. query_posts manipulates the main Wordpress query, and may give you some really unexpected results used inside a filter like this. At least consider WP_Query - and check the note about wp_reset_posts.
Hope that helps - apologies if some of it is stuff you already considered, but as you mentioned you're quite new to PHP I hope it's useful.
Related
The goal is to have wordpress spit out or echo all of the images from a custom post format I've created. I'm new to PHP and I am not looking to use any 3rd party plugins, maybe a fix to the code provided below please.
All of the solutions I've came across from here (stackoverflow) or from google does not work or spits out ALL of the images I've ever uploaded from the media library, which I do not want. Most solutions provided are for "display the first image" which I know of and works, but I would like all of the images from a post.
Here's the closest code that sort of worked a couple of times but it deforms my layout, then goes back to displaying one image:
function displayPostImg() {
global $post, $posts;
$first_img = '';
ob_start();
ob_end_clean();
$output = preg_match_all('/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $post->post_content, $matches);
$first_img = $matches[0][0];
return $first_img;
}
And the call I use to paste into my custom post php:
<?php echo displayPostImg(); ?>
As stated above, existing solutions do not work. Any help with a clear explination of what I am doing wrong will be a massive help.
EDIT
#corvidism Thanks for the further explanations man. I did have a look in the dev tools and the "return implode" seems to be taking it OUT of the loop, causing the layout issue. Your solution does show the post images/attachments I am after but I can't seem to fix this unfortuntaly. There seems to be this go to solution that's meant to do the same thing. This sadly echoes every image from the media library. Combining your code with this one below has gotten me close but if I come across a solution, I'll post it here for others:
$args = array(
'post_type' => 'attachment',
'posts_per_page' => -1,
'post_status' =>'any',
'post_parent' => $post->ID );
$attachments = get_posts( $args );
if ( $attachments ) {
foreach ( $attachments as $attachment ) {
echo apply_filters( 'the_title' , $attachment->post_title );
the_attachment_link( $attachment->ID , false );
}
}
EDIT #2: Solution
After messing around with various solutions, I found something that works. Try it out:
function grab_those_images( $post ) {
$content_post = $post->post_content;
$search_post = '~src="[^"]*"~';
preg_match_all( $search_post, $content_post, $imgs );
$no_of_pics = count($imgs[0]);
if ( $no_of_pics > 0 ) {
for ( $i=0; $i < $no_of_pics ; $i++ ) {
$string=$imgs[0][$i];
$string=trim( $string );
$length=strlen( $string );
$image_path=substr_replace( substr( $string, 5, $length ),"",-1 );
echo '<img src="';
echo $image_path;
echo '" />';
}
}
}
The function you're using contains buffer manipulation functions (ob_start() and ob_end_clean()), which and are most likely conflicting with something else in your template (probably something that's also using them, usually plugins).
Unless you're also searching for images inserted as post meta (which I assume you're not), you will find all images in a post inside the $post->post_content property. You can use preg_match_all on it to find the images.
You should pass the post content to your function as a parameter instead of accessing the global $post object. This will make things more reliable and easier to debug. (Global objects are generally frowned upon in PHP development, which is something to keep in mind if you plan to use PHP more generally than just for WordPress.)
This is how your function could look:
function getAllImagesInPost($postContent) {
preg_match_all('/<img.+src=[\'"]([^\'"]+)[\'"].*>/i', $postContent, $matches);
// This regex function searches for <img> tags and uses a capture group
// for the image source url. It will search the whole supplied string,
// in this case post content. It returns results into the $matches variable.
$image_tags = $matches[0];
// This is an array containing all the regex matches.
$image_urls = $matches[1];
// This is an array containing all the capture group matches.
return implode('',$image_tags);
// implode() creates a string from an array of strings/numbers.
}
In your template file, the usage depends on whether or not you're in the loop. In the loop you can work with the $post object and use either $post->post_content or get_the_content() (both will get you the post content as a string):
echo getAllImagesInPost(get_the_content());
Outside of the loop you will first need to get the post (e.g. get_post($somePostID);).
Addition 1:
You must pass a variable to the function, so you can't use WordPress template functions such as the_content(). These echo directly to the page and return true or something else useless (in this case, anyway). General WP rule is that if it starts with the_ it echoes, if it starts get_the_ it returns.
Addition 2:
To display only the images from your post and no other content, you simply don't use any other content template tag in your template file. (E.g. no the_content()).
Addition 3:
I suspect your problem isn't caused by the function itself but by how/where you're calling it. But if this function does cause changes in your layout, it's 99% the regex returning broken HTML (not likely but possible, depending on your input).
The way to debug this is to inspect the page with browser dev tools and look for broken tags or other weirdness. If you see that, you need to find what exactly happens by testing the function on various input. Feed it a hard-coded string, make a test post with just text/image/anything else, until you know what's happening. If you determine that the regex is the culprit, you can try fixing it yourself or search the internet for a better one (no judgement, regex is pain).
I have a custom page in my theme where I am creating a post from a different DB table and I want to then make this display inside wordpress as if it were a normal post. It seems to work most of the time, but randomly it seems that the post is modified after i call get_header() and i cant see why.
I have setup a mod rewrite rule in apache to hit a php file and in here i get the data I need and build the php object. I populate the wordpress post object using this function.
function BuildSimplePost($title, $body)
{
require_once( SITEROOT . '/wp-load.php' );
#$post = new WP_Post();
#$post->ID = -1;
$post->post_parent = 0;
$post->post_title = $title;
$post->post_name = "simple-response";
$post->post_excerpt = substr($body, 0, 100);
$post->comment_status = "closed";
$post->ping_status = "closed";
$post->post_type = "page";
$post->post_content = $body;
return $post;
}
Once the post is sorted I then push this post into the wordpress query objects and let the theme do the rest of the work.
$posts = array($post);
$wp_query->posts = $posts;
$wp_query->post_count = count($posts);
$wp_query->found_posts = count($posts);
$wp_query->max_num_pages = 1;
$wp_query->post = $post;
$wp_query->is_404 = 0;
$wp_query->is_singular = 1;
$wp_query->is_single = 1;
$wp_query->page_id = $post->ID;
include get_template_directory()."/external-page.php";
Inside external-page.php there is nothing weird. It is literally a copy of single.php with some html removed. The issue im having is that when get_header(); is called in this file the post is changed to something else. This then triggers a redirect which brings the user to a different page on the site that is part of wordpress.
Anyone know why the get_header method would be causing a redirect like this?
It's hard to tell exactly what's changing up your post. The way I see it, you've got two options:
Keep putting your content back into the post. This is not the WordPress way of solving this problem but it's probably the easier approach. #ArtisticPhoenix's answer above is the right concept but the wrong specific code.
Create a custom post type, which is the WordPress way. #CBroe offered this and the response to your answer to his question should (IMHO) be: "it doesn't matter how complicated your post type is, you should encapsulate it in a CPT if you're using WordPress."
Put your content back
Keep a copy of your post object somewhere and put it back right after anything that changes it. You can create a new global:
global $mypost;
$mypost = BuildSimplePost(...);
If you know the $title and $body parameters, you can just call your function again every time you need it. You could also use a transient, a update_option/get_option call, or several other things.
There are several filters that could be the cuplrit:
The the_post action should change $post. That's the one thing it really does. You may want to sit on top of the hook stack like this: add_filter('the_post', function() { global $post, $mypost; $post = $mypost; }, 10000);
Before the wp object is set up, there are several actions and you run a high likelihood of anything hooked changing $post because it's free game before then. You may have plugins or your theme hooking on: parse_request, parse_query, pre_get_posts, or posts_selection. You may try something like add_filter('parse_request', function() { global $post; $post = $mypost; }, 10000); for each of these filters.
I've seen some plugin developers adding things that change the $post global (and other things they probably shouldn't change) during calls to the actions template_redirect, get_header, loop_start, and after query. Heck, I've done it myself a few times. You could try the same thing with these filters although I'd consider them less suspect.
If that doesn't get your content back, you could try something really dirty, like forcing it in right before the call to the_post. There's no hook for this but if you control the theme it's easy.
The WP Way
I understand that you think that your post is very complicated but I'll offer you this from several years of being neck-deep in WP code: breaking the WP post model is a recipe for heartache. If you're not using posts and you're not using the way they're intended, you probably shouldn't be using WP. There are other frameworks that offer things like user authentication, themeing, database persistence, eventing, REST, etc. without the overhead of WP.
Another way
That having been said, I've used WP in the past because it was part of a requirement that I couldn't control. When my post gets too complicated, I create a wrapper object like so:
class MyPostWrapper {
private $_Post;
private $_Meta = array();
public function __construct($post) {
$this->_Post = get_post($post);
$this->_Meta = $this->_LoadMeta();
}
private function _LoadMeta() {
// Load everything into $_Meta: other tables, options, post meta, etc.
}
public function __get($name) {
if (array_key_exists($name, $this->_Meta))
return $this->_Meta[$name];
}
// Use a similar implementation for __set and __isset.
}
However complicated your post gets, you can manage its lifecycle and all of its trail very easily with a single wrapper.
Then you don't have to worry about who's eating your post. If they are, they probably should be.
This is my first post here, so I apologize in advance for any mishaps.
I've been searching for hours trying to figure this one out, but I simply can't seem to understand why this is happening.
The site I'm setting up is a child site (not in a multisite sense, but as a separate site/domain with the same branding). Some of the posts on my site will originate from the parent/main site (but will be made as new posts through copy-paste), and I want the original article ID as part of the permalinks.
E.g. http://www.example.com/hello-world/12345/, where 12345 is the article ID of the article on the parent/main site.
To accomplish this, I've added a custom field to my posts where I can add the article ID of the original article with external_article_id as Field Name. I've then tried to manipulate the permalinks with the following code:
add_filter('post_link', 'append_custom_permalink', 10, 2);
function append_custom_permalink($url, $post) {
$newurl = $url;
if ($post->post_type == 'post') {
$custom = get_post_custom_values('external_article_id', $post->ID);
if (!empty($custom))
$newurl = $url . $custom[0] . '/';
}
return $newurl;
}
Whenever I output the permalink to the posts it appears exactly as I want it, both in the editor and on the site. However, when I either click a link or enter the address manually, I get redirected automatically to http://www.example.com/hello-world/12345/12345/. It duplicates the additional numerical slug, and also happens when I replace $custom[0] with a hard-coded numeric value. This applies to all posts, and my permalink structure (in the settings) is set to /%postname%/.
I even tried setting the permalink structure to /%postname%/%ext_article_id%/ and replace %ext_article_id% with $custom[0], but with the exact same outcome. I also tried using the same code on another WordPress site, except this time with pages instead of posts, also with the exact same outcome.
Ideally I would like to use something like add_query_arg($custom[0], '', get_permalink($post->ID));, but omit the question mark that comes along with it.
Could someone please explain to me why this is happening, and how I can circumvent this? Do I need to use some other filter, or how can I approach this?
Thank you in advance!
In order to make this work you also need to make WordPress aware of the rewrite_tag and specify an additional permalink structure via add_permastruct. The following code should do the trick:
function append_custom_permalink( $post_link, $post ) {
if( $post->post_type == 'post' ) {
$custom = get_post_custom_values( 'external_article_id', $post->ID );
if( ! empty($custom) ) {
$post_link = $post_link.$custom[0].'/';
}
}
return $post_link;
}
add_filter('post_link', 'append_custom_permalink', 10, 2);
function sof_30058470_posts_rewrite() {
add_rewrite_tag('%external_article_id%', '([^/]+)', 'external_article_id=');
add_permastruct('external_article_id', '/%year%/%monthnum%/%day%/%postname%/%external_article_id%/', false);
}
add_action('init', 'sof_30058470_posts_rewrite', 10, 0);
Make sure to re-save your permalink structure at Settings->Permalinks once you added the code. You may also need to refresh/clear your browser cache.
Ok, here's the deal: I am constructing a Drupal website that has several different sections. Each section is a view that displays a content type. (Each section has it's own content type) For example, I have a view that points to ?q=blog which displays content type blog.
All the sections look a little different than each other. Not like 'website-within-a-website' different but different enough that they can't all use the same template file and each be modified with CSS. Each section needs it's own page.tpl.php.
Unfortunately, AFAIK Drupal theme's .info files can only either assign one page.tpl.php for the entire theme or assign a page-node-####.tpl.php for each node. There is going to be lots of content on this website so setting Drupal to make a new identical page-node-####.tpl.php for every created node would get unmanagable very fast.
To solve this problem, I am going to use pathauto to create an alias for each content type. For example, all nodes of content type blog are given an alias ?q=blog/[post title]. Modify template.php to use page-blog.tpl.php for any page who's alias starts with the word 'blog'.
Other people have tried doing this sort of thing and have created functions such as the one described. Unfortunately, all the ones I have seen are for Drupal 6 or below. I have tried modifying existing ones with no success. So far, though, I think this is on the right track:
function basic_preprocess_page(&$vars, $hook) {
...
if( module_exists('path') ) {
$alias = drupal_get_path_alias( $_GET['q'] );
$site_section = "blog";
if( strpos( $alias, $site_section ) === 0 ) {
$VARIABLE_THAT_TELLS_THE_PAGE_WHAT_TEMPLATE_TO_USE = "/path/to/page-blog.php";
}
}
}
I cannot find $VARIABLE_THAT_TELLS_THE_PAGE_WHAT_TEMPLATE_TO_USE does anyone know what it is?
Maybe my site is structured badly. If anyone knows how to restructure my site so I can more easily make a theme with seperate sections please share how!
Thanks a million! (c:
EDIT: Perhaps I need to use template suggestions instead. Does anyone know the function or variable to use to set this?
They changed the name of this array key in D7 and I haven't seen it documented anywhere. I finally figured this out after a good bit of debugging. You can override the theme template in template.php with a hook_preprocess_page() like so:
function myTheme_preprocess_page(&$vars) {
global $node;
if ($node->type == 'blog') {
$vars['theme_hook_suggestions'] = array('my__blog_template'); // use my--blog-template.tpl.php, note '-' = '_'
}
elseif ($node->type == 'articles') {
$vars['theme_hook_suggestions'] = array('article__node_template'); // use article--node-template.tpl.php
}
}
Oh and don't forget to flush the Drupal caches after making changes to your template.php.
Ok, I found it:
http://drupal.org/node/223440#comment-991840
$alias = drupal_get_path_alias($_GET['q']);
if ($alias != $_GET['q']) {
$template_filename = 'page';
foreach (explode('/', $alias) as $path_part) {
$template_filename = $template_filename . '-' . $path_part;
$variables['template_files'][] = $template_filename;
}
}
Credit to this function goes to user mfb.
I had a lot of trouble with this so I will explain it here in case anyone finds it useful.
This function goes in your template.php. It needs to be part of the <theme name>_preprocess_page function. What it does is it takes the alias and then explodes it into a bunch of different components. For example if you are on a page with the alias ?q=blog/blog-post-title it would be exploded into blog and blog-post-title. It then turns each component into a name for a template suggestion. It puts each template suggestion into the template_files[] array (inside the $variables[] array) so that the page now has two new template suggestions:
page-blog, and page-blog-blog-post-title
Template suggestions are alternate template files. In this case they are for pages, but they don't necessarily have to be. You can have template suggestions for anything you can think of including blocks, nodes and the like. Don't let the name 'template suggestion' fool you. Template suggestions will be used over default templates as long as they exist. I don't know why it was named like that. I think it should be renamed.
What you do, then, now that you've set up Drupal to look for a template suggestion that points to your alias, is create a new template file where all the rest are in your theme. In this case, let's say I want to theme my entire blog section. In the templates folder I should create a file named page--blog.tpl.php (note the --double hyphens--) with the layout I want.
Drupal will use the most specific template suggestion it can find so if you wanted you could make one blog post to look completely different than the rest of the site long as you make a template for it named page--blog--blog-post-title and put it in your theme's templates directory. (again, note the double hyphens.)
I am a bit confused about how WordPress's permalink works, especially beyond Wordpress's own usage. My permalinks are like:
%post_id%-%post_name%
But in single.php I want to put another link to page itself but with different query string. When it is clicked the permalink structure may look like:
%mystring%-%post_id%-%post_name%
I want to get the value from $_GET['action'], so:
$_GET['action'] = %mystring%
my plan is to interpret it like:
if('xx' == $_GET['action']){
//do xx stuff
} else if ('yy'==$_GET['action']){
//do yy stuff
} else {
//show the single post as a single.php always shows
}
that means, I want to parse the $_GET['action'] optionally. If I do not parse it even if it is available in query string, I want the page to be rendered correctly.
So to get this done, where should I actually work? Also how do I form the link for <a> tag? Usually we make link this way:
TEXT
but you already know, I need to add some text before the original permalink of post.
Thanks in advance.
Leave your permalink structure as it was and check out my answer on custom rewrite rules.
You could adapt the code like so;
function my_rewrite_rules($rules)
{
global $wp_rewrite;
// the key is a regular expression
// the value maps matches into a query string
$my_rule = array(
'(.+)/(.+)/?$' => 'index.php?pagename=matches[2]&my_action=$matches[1]'
);
return array_merge($my_rule, $rules);
}
add_filter('page_rewrite_rules', 'my_rewrite_rules');
function my_query_vars($vars)
{
// this value should match the rewrite rule query paramter above
// I recommend using something more unique than 'action', as you
// could collide with other plugins or WordPress core
$my_vars = array('my_action');
return array_merge($my_vars, $vars);
}
add_filter('query_vars', 'my_query_vars');
Now the page my_page should be available at http://example.com/whatever/my_page and http://example.com/my_page.
You can get the value of whatever using get_query_var('my_action').
Disclaimer
This may have undesired effects when viewing children pages or page attachments. You could get around this by passing an identifier in your rewrite, something to the effect of;
http://example.com/my_identifier/whatever/page
Note: You will need to edit the rewrite rule if you wish to do this. Every time you make changes to the code you will need to re-save your permalink structure to 'flush' the rules.