basepage_render() is called from wp_trim_excerpt() first and then is called again somewhere to get the content to display the page. If the filter removes itself then the page content isn't replaced with the CiviCRM output.
When displaying /civicrm pages the holding page content is erroneously shown: "Do not delete this page. Page content is generated by CiviCRM."
@chriscant I'm not clear how we balance the needs of those for whom the removal of the callback fixes problems with those for whom it introduces problems. Please see:
Is there a hook in Avada that would allow you to call remove_filter('the_content', [civi_wp()-> basepage, 'basepage_render'])before the call to wp_trim_excerpt()?
Similarly, is there a hook after the call to wp_trim_excerpt() so that you can then reinstate the CiviCRM callback with add_filter('the_content', [civi_wp()-> basepage, 'basepage_render']) so that the CiviCRM content renders where you want it to?
First: I'm pretty certain that the problem also occurred in the standard "Twenty Twenty-One" theme that I switched to briefly. So, it would be best to fix for all circumstances.
The basepage_render() function simply returns what is stored in $this->basepage_markup. The problem must be that the 'wp' handler basepage_handler() function is being called twice. (Removing the filter may not actually stop basepage_handler() being called twice, which could be a problem.)
It would certainly be best to ensure that Civi is only being invoked once.
Do you have any idea as to why the 'wp' action would be run again?
So, it would be best to fix for all circumstances.
@chriscant Whilst this is a noble aim it isn't actually possible. Please refer to the StackExchange question I linked to above to see an example of the exact opposite of your issue - one which would return if the callback isn't removed. All that can be done is to code for the most generally-applicable situation and allow modifications to be made.
The issue is that any callback attached to the the_content filter will always run whenever apply_filters( 'the_content', ... ) is called. This may happen in any number of situations, one of which you've pointed out. There are other situations - for example, many plugins, widgets and blocks trigger the filter to apply formatting functions like wpautop() etc to text before outputting it. (FWIW, my preferred method does this without triggering the_content, but other coders do what they do ) Which means that it is very difficult for the CiviCRM-WordPress plugin to know exactly which triggering of the filter is the correct one to return the rendered content for.
So what do we do? We either return the CiviCRM content
every time the filter is triggered (and incorrectly override legitimate content) as used to be the case.
just once (with the risk that the_content filter is triggered early) as is now the case.
My suggestion in my previous reply still stands as the best solution, i.e. it allows you to control when the content is overridden by preventing it from happening until you want it to happen.
Hi. In my albeit limited understanding, having multiple cases where 'the_content' is called isn't the problem, as the handler for this uses the cached markup in $this->basepage_markup. The problem is that the code to generate and cache the markup is being called twice. This might or might not be under our control. I'll have a look later to see where this is being called from.
Can we use $this or $this->civi within basepage_handler() to remember whether we've been run on this request? So: set $this->basepage_markup_set to TRUE when it is set, and bail out at the beginning of that basepage_handler() if $this->basepage_markup_set is set and set to TRUE.
I find it extremely unlikely that wp is being deliberately called other than from within WordPress core. I cannot think of any valid reason for doing so. Are you logging in CiviCRM_For_WordPress_Basepage::basepage_handler() and seeing two entries per page load? If so, backtrace to see what's responsible for the second log entry.
The original symptoms you report ...
When displaying /civicrm pages the holding page content is erroneously shown: "Do not delete this page. Page content is generated by CiviCRM."
... suggest to me that you did correctly identify what was going on - i.e. that wp_trim_excerpt() is called prior to the_content() in your theme via a hook, in your page template, or at some point prior to that by a plugin. Both of these functions trigger the the_content filter. However it happens, since CiviCRM 5.39, the second call that triggers the the_content filter will no longer return CiviCRM's cached content but will instead render the content of the auto-created Base Page's $post->post_content.
Again, either top-and-tail the call to wp_trim_excerpt() via available hooks in your theme's template files or override the template file in your child theme and top-and-tail it like this:
Hello again. I haven't done a child theme of Avada as I've had no need to so far. As I said, this issue also affects a standard WordPress theme when used on my site. Possibly one of my other WP plugins is calling wp_trim_excerpt().
I've added some error_log logging. As far as I can tell on my site the basepage_handler() is only being called once but basepage_render() is being called twice. And that works fine with the original basepage_render() returning the cached output in $this->basepage_markup twice.
From looking at the original StackExchange issue from Richard van Oosterhout, the problem was a duplicated registration form. But "it is only when I use a selected page as a footer in my enfold theme". I cannot actually see the image well enough to see what is going on. I can't see what the "selected page" is. It feels to me that the original CiviCRM code is doing the right thing and that Richard needs help to avoid showing the content for a second time in the footer.
Possibly one of my other WP plugins is calling wp_trim_excerpt().
Sounds like it. My guess would be a plugin that prepares OpenGraph content for <meta> tags in the HTML <head>, but obviously I can't be sure.
As far as I can tell on my site the basepage_handler() is only being called once but basepage_render() is being called twice.
Okay, that confirms what I wrote in my previous reply.
It feels to me that the original CiviCRM code is doing the right thing and that Richard needs help to avoid showing the content for a second time in the footer.
This is exactly what the removal of the the_content callback does.
Please reconsider what I wrote in this reply to see why we can't have both solutions at the same time and thus why the out-of-the-box CiviCRM plugin cannot accommodate everyone's setups. Callbacks attached to the_content can be triggered before and/or after the actual the_content() that populates the page's content area. What CiviCRM shouldn't do is overwrite the content every timethe_content filter is triggered.
I'm going to close this issue as a "won't fix" because, in practice, it is far more likely that the_content is triggered after the actual the_content() that populates the page's content area has run - i.e. during the rendering of widgets/blocks in get_sidebar() or get_footer(). Also, I have given you the code you need (whether you implement this via a plugin or a child theme) to make sure CiviCRM overwrites the correct callback in your specific setup.
For anyone else looking: without this reversion, if you do have two calls to get the CiviCRM content, the first will get the CiviCRM output and the second will probably get "Do not delete this page. Page content is generated by CiviCRM." which is probably not what you want.
Originally commented in #112 (closed), But I think this applies here more ....
If the problems the original change was meant to solve are related to repeated output in the loop, would it make sense to, instead of removing the filter on 'the_content' on first run, check that the current post is actually the civicrm basepage?
e.g. hacky pseudoish-code:
if(is_singular()&&in_the_loop()&&is_main_query()&&isset($_GLOBALS['post'])&&$_GLOBALS['post']->name==$config->wpBasePage){return$this->basepage_markup;}else{return$content;// CiviCRM base page is not required.}