| 1 |
<?php |
| 2 |
namespace WPDeveloper\BetterDocs\Core; |
| 3 |
|
| 4 |
if ( ! defined( 'ABSPATH' ) ) { |
| 5 |
exit; |
| 6 |
} |
| 7 |
|
| 8 |
|
| 9 |
use WPDeveloper\BetterDocs\Utils\Base; |
| 10 |
use WPDeveloper\BetterDocs\Core\Settings; |
| 11 |
|
| 12 |
/** |
| 13 |
* Unified Metabox for BetterDocs |
| 14 |
* |
| 15 |
* This class creates a tabbed metabox interface that consolidates: |
| 16 |
* - Article Quality Analysis |
| 17 |
* - Estimated Reading Time |
| 18 |
* - Related Docs (from Pro) |
| 19 |
* |
| 20 |
* @since 3.7.0 |
| 21 |
*/ |
| 22 |
class UnifiedMetabox extends Base { |
| 23 |
|
| 24 |
/** |
| 25 |
* Settings instance |
| 26 |
* |
| 27 |
* @var Settings |
| 28 |
*/ |
| 29 |
private $settings; |
| 30 |
|
| 31 |
/** |
| 32 |
* Active tabs |
| 33 |
* |
| 34 |
* @var array |
| 35 |
*/ |
| 36 |
private $tabs = []; |
| 37 |
|
| 38 |
/** |
| 39 |
* Constructor |
| 40 |
* |
| 41 |
* @param Settings $settings Settings instance |
| 42 |
*/ |
| 43 |
public function __construct( Settings $settings ) { |
| 44 |
$this->settings = $settings; |
| 45 |
|
| 46 |
if ( ! is_admin() ) { |
| 47 |
return; |
| 48 |
} |
| 49 |
|
| 50 |
// Register the unified metabox |
| 51 |
add_action( 'add_meta_boxes', [ $this, 'register_metabox' ], 5 ); |
| 52 |
|
| 53 |
// Enqueue scripts and styles |
| 54 |
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); |
| 55 |
} |
| 56 |
|
| 57 |
/** |
| 58 |
* Register the unified metabox |
| 59 |
*/ |
| 60 |
public function register_metabox() { |
| 61 |
// Build tabs array |
| 62 |
$this->build_tabs(); |
| 63 |
|
| 64 |
// Only add metabox if there are tabs to show |
| 65 |
if ( empty( $this->tabs ) ) { |
| 66 |
return; |
| 67 |
} |
| 68 |
|
| 69 |
add_meta_box( |
| 70 |
'betterdocs-unified-metabox', |
| 71 |
__( 'BetterDocs', 'betterdocs' ), |
| 72 |
[ $this, 'render_metabox' ], |
| 73 |
'docs', |
| 74 |
'normal', |
| 75 |
'high' |
| 76 |
); |
| 77 |
} |
| 78 |
|
| 79 |
/** |
| 80 |
* Build the tabs array based on enabled features |
| 81 |
*/ |
| 82 |
private function build_tabs() { |
| 83 |
$this->tabs = []; |
| 84 |
|
| 85 |
// Article Quality Analysis tab (always available) |
| 86 |
$this->tabs['quality-analysis'] = [ |
| 87 |
'id' => 'quality-analysis', |
| 88 |
'label' => __( 'Article Quality Analysis', 'betterdocs' ), |
| 89 |
'callback' => [ $this, 'render_quality_analysis_tab' ], |
| 90 |
'priority' => 10 |
| 91 |
]; |
| 92 |
|
| 93 |
// Estimated Reading Time tab |
| 94 |
if ( $this->settings->get( 'enable_estimated_reading_time' ) ) { |
| 95 |
$this->tabs['reading-time'] = [ |
| 96 |
'id' => 'reading-time', |
| 97 |
'label' => __( 'Estimated Reading Time', 'betterdocs' ), |
| 98 |
'callback' => [ $this, 'render_reading_time_tab' ], |
| 99 |
'priority' => 20 |
| 100 |
]; |
| 101 |
} |
| 102 |
|
| 103 |
// Attachments tab (from Pro) |
| 104 |
if ( $this->settings->get( 'show_attachment' ) ) { |
| 105 |
$this->tabs['attachments'] = [ |
| 106 |
'id' => 'attachments', |
| 107 |
'label' => __( 'Attachments', 'betterdocs' ), |
| 108 |
'callback' => [ $this, 'render_attachments_tab' ], |
| 109 |
'priority' => 30 |
| 110 |
]; |
| 111 |
} |
| 112 |
|
| 113 |
// Related Docs tab (from Pro) |
| 114 |
if ( $this->settings->get( 'show_related_docs' ) ) { |
| 115 |
$this->tabs['related-docs'] = [ |
| 116 |
'id' => 'related-docs', |
| 117 |
'label' => __( 'Related Docs', 'betterdocs' ), |
| 118 |
'callback' => [ $this, 'render_related_docs_tab' ], |
| 119 |
'priority' => 40 |
| 120 |
]; |
| 121 |
} |
| 122 |
|
| 123 |
// Allow other plugins/features to add tabs |
| 124 |
$this->tabs = apply_filters( 'betterdocs_unified_metabox_tabs', $this->tabs ); |
| 125 |
|
| 126 |
// Sort tabs by priority |
| 127 |
uasort( $this->tabs, function( $a, $b ) { |
| 128 |
return ( $a['priority'] ?? 999 ) - ( $b['priority'] ?? 999 ); |
| 129 |
}); |
| 130 |
} |
| 131 |
|
| 132 |
/** |
| 133 |
* Render the unified metabox |
| 134 |
* |
| 135 |
* @param \WP_Post $post Current post object |
| 136 |
*/ |
| 137 |
public function render_metabox( $post ) { |
| 138 |
if ( empty( $this->tabs ) ) { |
| 139 |
return; |
| 140 |
} |
| 141 |
|
| 142 |
$first_tab = array_key_first( $this->tabs ); |
| 143 |
?> |
| 144 |
<div class="betterdocs-unified-metabox"> |
| 145 |
<div class="betterdocs-metabox-tabs"> |
| 146 |
<?php foreach ( $this->tabs as $tab_id => $tab ) : ?> |
| 147 |
<button |
| 148 |
type="button" |
| 149 |
class="betterdocs-metabox-tab <?php echo $tab_id === $first_tab ? 'active' : ''; ?>" |
| 150 |
data-tab="<?php echo esc_attr( $tab_id ); ?>" |
| 151 |
> |
| 152 |
<span class="tab-label"><?php echo esc_html( $tab['label'] ); ?></span> |
| 153 |
</button> |
| 154 |
<?php endforeach; ?> |
| 155 |
</div> |
| 156 |
|
| 157 |
<div class="betterdocs-metabox-content"> |
| 158 |
<?php foreach ( $this->tabs as $tab_id => $tab ) : ?> |
| 159 |
<div |
| 160 |
class="betterdocs-metabox-panel <?php echo $tab_id === $first_tab ? 'active' : ''; ?>" |
| 161 |
data-panel="<?php echo esc_attr( $tab_id ); ?>" |
| 162 |
> |
| 163 |
<?php |
| 164 |
if ( is_callable( $tab['callback'] ) ) { |
| 165 |
call_user_func( $tab['callback'], $post ); |
| 166 |
} |
| 167 |
?> |
| 168 |
</div> |
| 169 |
<?php endforeach; ?> |
| 170 |
</div> |
| 171 |
</div> |
| 172 |
<?php |
| 173 |
} |
| 174 |
|
| 175 |
/** |
| 176 |
* Render Article Quality Analysis tab |
| 177 |
* |
| 178 |
* @param \WP_Post $post Current post object |
| 179 |
*/ |
| 180 |
public function render_quality_analysis_tab( $post ) { |
| 181 |
// Hook for Article Quality Score to render its content |
| 182 |
do_action( 'betterdocs_quality_analysis_tab_content', $post ); |
| 183 |
} |
| 184 |
|
| 185 |
/** |
| 186 |
* Render Estimated Reading Time tab |
| 187 |
* |
| 188 |
* @param \WP_Post $post Current post object |
| 189 |
*/ |
| 190 |
public function render_reading_time_tab( $post ) { |
| 191 |
echo '<div class="betterdocs-reading-time-content">'; |
| 192 |
// Hook for Estimated Reading Time to render its content |
| 193 |
do_action( 'betterdocs_reading_time_tab_content', $post ); |
| 194 |
echo '</div>'; |
| 195 |
} |
| 196 |
|
| 197 |
/** |
| 198 |
* Render Attachments tab |
| 199 |
* |
| 200 |
* @param \WP_Post $post Current post object |
| 201 |
*/ |
| 202 |
public function render_attachments_tab( $post ) { |
| 203 |
echo '<div class="betterdocs-attachments-content">'; |
| 204 |
// Hook for Attachments (Pro) to render its content |
| 205 |
do_action( 'betterdocs_attachments_tab_content', $post ); |
| 206 |
echo '</div>'; |
| 207 |
} |
| 208 |
|
| 209 |
/** |
| 210 |
* Render Related Docs tab |
| 211 |
* |
| 212 |
* @param \WP_Post $post Current post object |
| 213 |
*/ |
| 214 |
public function render_related_docs_tab( $post ) { |
| 215 |
echo '<div class="betterdocs-related-docs-content">'; |
| 216 |
// Hook for Related Docs (Pro) to render its content |
| 217 |
do_action( 'betterdocs_related_docs_tab_content', $post ); |
| 218 |
echo '</div>'; |
| 219 |
} |
| 220 |
|
| 221 |
/** |
| 222 |
* Enqueue assets for the unified metabox |
| 223 |
* |
| 224 |
* @param string $hook Current admin page hook |
| 225 |
*/ |
| 226 |
public function enqueue_assets( $hook ) { |
| 227 |
global $post_type; |
| 228 |
|
| 229 |
// Only load on docs edit screens |
| 230 |
if ( ( $hook === 'post.php' || $hook === 'post-new.php' ) && $post_type === 'docs' ) { |
| 231 |
betterdocs()->assets->enqueue( 'betterdocs-unified-metabox', 'admin/js/unified-metabox.js' ); |
| 232 |
|
| 233 |
// Enqueue styles |
| 234 |
wp_enqueue_style( |
| 235 |
'betterdocs-unified-metabox', |
| 236 |
BETTERDOCS_ABSURL . 'assets/admin/css/unified-metabox.css', |
| 237 |
[], |
| 238 |
BETTERDOCS_VERSION |
| 239 |
); |
| 240 |
} |
| 241 |
} |
| 242 |
|
| 243 |
/** |
| 244 |
* Get AI icon SVG |
| 245 |
* |
| 246 |
* @return string SVG icon markup |
| 247 |
*/ |
| 248 |
private function get_ai_icon() { |
| 249 |
return '<svg width="16" height="16" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 250 |
<g filter="url(#filter0_d_13132_3862)"> |
| 251 |
<path d="M4.5 15.9986C4.5 15.5068 4.89984 15.1128 5.38925 15.0642C9.59729 14.647 12.9438 11.3004 13.361 7.09237C13.4096 6.60296 13.8036 6.20312 14.2954 6.20312C14.7872 6.20312 15.1812 6.60296 15.2297 7.09237C15.6469 11.3004 18.9935 14.647 23.2015 15.0642C23.6909 15.1128 24.0907 15.5068 24.0907 15.9986C24.0907 16.4904 23.6909 16.8844 23.2015 16.9329C18.9935 17.3501 15.6469 20.6967 15.2297 24.9048C15.1812 25.3942 14.7872 25.794 14.2954 25.794C13.8036 25.794 13.4096 25.3942 13.361 24.9048C12.9438 20.6967 9.59729 17.3501 5.38925 16.9329C4.89984 16.8844 4.5 16.4904 4.5 15.9986Z" fill="url(#paint0_linear_13132_3862)"/> |
| 252 |
</g> |
| 253 |
<defs> |
| 254 |
<linearGradient id="paint0_linear_13132_3862" x1="14.2954" y1="6.20312" x2="14.2954" y2="25.794" gradientUnits="userSpaceOnUse"> |
| 255 |
<stop stop-color="#6C5CE7"/> |
| 256 |
<stop offset="1" stop-color="#A29BFE"/> |
| 257 |
</linearGradient> |
| 258 |
</defs> |
| 259 |
</svg>'; |
| 260 |
} |
| 261 |
} |
| 262 |
|
| 263 |
|