<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[BuddyPress][13912] trunk: Introduce theme support check for specific component features</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://buddypress.trac.wordpress.org/changeset/13912">13912</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://buddypress.trac.wordpress.org/changeset/13912","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>imath</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2024-06-08 06:09:24 +0000 (Sat, 08 Jun 2024)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Introduce theme support check for specific component features

Some of the feature we'll soon introduce like the Block based activity post form will need standalone BP themes to do some adjustments to their code to support them.

Once done, they'll need to opt-in for these features using the WordPress `add_theme_support()` function. The first argument for this function remains `buddypress`. Supporting BP component specific features will need to use a second argument: an associative array keyed by BP Component IDs. For instance, it will be `array( 'activity' => array( 'block-editor' ) )` when a theme support the future Block based activity post form.

In BuddyPress code, we'll then be able for example to use the following kind of check `bp_current_theme_supports( array( 'activity' => 'block-editor' ) )` to be sure the theme fully support the feature.

Props espellcaste

See <a href="http://buddypress.trac.wordpress.org/ticket/8319">#8319</a>
Closes https://github.com/buddypress/buddypress/pull/301</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcbpcorebpcorethemecompatibilityphp">trunk/src/bp-core/bp-core-theme-compatibility.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunktestsphpunittestcasescorethemeCompatibilityphp">trunk/tests/phpunit/testcases/core/themeCompatibility.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcbpcorebpcorethemecompatibilityphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/bp-core/bp-core-theme-compatibility.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/bp-core/bp-core-theme-compatibility.php 2024-06-07 04:59:08 UTC (rev 13911)
+++ trunk/src/bp-core/bp-core-theme-compatibility.php   2024-06-08 06:09:24 UTC (rev 13912)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1056,3 +1056,81 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        return isset( $theme->is_block_theme ) && $theme->is_block_theme;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+/**
+ * Registers the `buddypress` theme feature.
+ *
+ * @since 14.0.0
+ */
+function bp_register_buddypress_theme_feature() {
+       register_theme_feature(
+               'buddypress',
+               array(
+                       'type'        => 'array',
+                       'variadic'    => true,
+                       'description' => __( 'Whether the Theme supports BuddyPress and possibly BP Components specific features', 'buddypress' ),
+               )
+       );
+}
+add_action( 'bp_init', 'bp_register_buddypress_theme_feature' );
+
+/**
+ * Filters the WP theme support API so that it can be used to check whether the
+ * current theme has global BuddyPress and/or BP Component specific support.
+ *
+ * Please do not use in your plugins or themes.
+ *
+ * @since 14.0.0
+ * @access private
+ *
+ * @param bool  $supports Whether the active theme supports the given feature. Default false.
+ * @param array $args     Array of arguments for the feature.
+ * @param mixed $feature  The theme feature.
+ * @return boolean True if the feature is supported. False otherwise.
+ */
+function _bp_filter_current_theme_supports( $supports = false, $args = array(), $feature = null ) {
+       $params             = reset( $args );
+       $is_expected_params = array_filter( array_map( 'is_string', array_keys( $params ) ) );
+
+       if ( true === $supports && $is_expected_params ) {
+               if ( ! is_array( $feature ) ) {
+                       $supports = false;
+               } else {
+                       $component         = key( $args[0] );
+                       $component_feature = $args[0][ $component ];
+                       $theme_feature     = $feature[0];
+
+                       // Check the theme is supporting the component's feature.
+                       $supports = isset( $theme_feature[ $component ] ) && in_array( $component_feature, $theme_feature[ $component ], true );
+               }
+       }
+
+       return $supports;
+}
+add_filter( 'current_theme_supports-buddypress', '_bp_filter_current_theme_supports', 10, 3 );
+
+/**
+ * BP wrapper function for WP's `current_theme_supports()`.
+ *
+ * @since 14.0.0
+ *
+ * @param array $args An associative array containing **ONE** feature & keyed by the BP Component ID.
+ * @return boolean True if the theme supports the BP feature. False otherwise.
+ */
+function bp_current_theme_supports( $args = array() ) {
+       if ( is_array( $args ) && $args && ( 1 < count( $args ) || is_array( $args[ key( $args ) ] ) ) ) {
+               _doing_it_wrong( __FUNCTION__, esc_html( 'The function only supports checking 1 feature for a specific component at a time for now.', 'buddypress' ), '14.0.0' );
+               return false;
+       }
+
+       $supports = current_theme_supports( 'buddypress', $args );
+
+       /**
+        * Filter here to edit BP Theme supports.
+        *
+        * @since 14.0.0
+        *
+        * @param boolean $supports True if the theme supports the BP feature. False otherwise.
+        */
+       return apply_filters( 'bp_current_theme_supports', $supports, $args );
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestcasescorethemeCompatibilityphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/testcases/core/themeCompatibility.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/testcases/core/themeCompatibility.php                         (rev 0)
+++ trunk/tests/phpunit/testcases/core/themeCompatibility.php   2024-06-08 06:09:24 UTC (rev 13912)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,58 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * @group core
+ * @group core-theme-compatibility
+ * @group bp_current_theme_supports
+ */
+class BP_Tests_Theme_Compatibility_Functions extends BP_UnitTestCase {
+
+       public function test_bp_current_theme_doesnot_support() {
+               $this->assertFalse( bp_current_theme_supports() );
+       }
+
+       public function test_bp_current_theme_does_support_buddypress() {
+               add_theme_support( 'buddypress' );
+               $this->assertTrue( bp_current_theme_supports() );
+       }
+
+       public function test_bp_current_theme_doesnot_support_buddypress_feature() {
+               add_theme_support( 'buddypress' );
+               $this->assertFalse( bp_current_theme_supports( array( 'activity' => 'feature' ) ) );
+       }
+
+       public function test_bp_current_theme_does_support_buddypress_feature() {
+               add_theme_support(
+                       'buddypress',
+                       array(
+                               'activity'      => array( 'feature1', 'feature2' ),
+                       )
+               );
+               $this->assertTrue( bp_current_theme_supports( array( 'activity' => 'feature1' ) ) );
+               $this->assertFalse( bp_current_theme_supports( array( 'activity' => 'feature3' ) ) );
+               $this->assertFalse( bp_current_theme_supports( array( 'notifications' => '' ) ) );
+               $this->assertTrue( bp_current_theme_supports() );
+       }
+
+       /**
+        * @expectedIncorrectUsage bp_current_theme_supports
+        */
+       public function test_bp_current_theme_support_incorrect_usage() {
+               add_theme_support(
+                       'buddypress',
+                       array(
+                               'activity'      => array( 'feature1', 'feature2' ),
+                               'notifications' => array( 'feature3' ),
+                       )
+               );
+
+               $this->assertFalse( bp_current_theme_supports( array( 'activity' => array( 'feature1', 'feature2' ) ) ) );
+               $this->assertFalse(
+                       bp_current_theme_supports(
+                               array(
+                                       'activity'      => 'feature1',
+                                       'notifications' => 'feature3',
+                               )
+                       )
+               );
+       }
+}
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/tests/phpunit/testcases/core/themeCompatibility.php
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span></div>

</body>
</html>