HEX
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.4.30
System: Linux iZj6c1151k3ad370bosnmsZ 3.10.0-1160.76.1.el7.x86_64 #1 SMP Wed Aug 10 16:21:17 UTC 2022 x86_64
User: root (0)
PHP: 7.4.30
Disabled: NONE
Upload Files
File: /var/www/html/breadsecret.com/wp-content/plugins/insert-php/includes/class.admin-bar.php
<?php
/**
 * Admin Bar functionality
 *
 * @package Woody_Code_Snippets
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class WINP_Admin_Bar
 * 
 * Adds Woody Code Snippets menu to WordPress admin bar.
 */
class WINP_Admin_Bar {

	/**
	 * Class instance.
	 * 
	 * @var self|null
	 */
	private static $instance;

	/**
	 * Active snippets on current page.
	 *
	 * @var array<int, array{id: int, name: string, type: string, location: string, scope: string}>
	 */
	private $active_snippets = [];

	/**
	 * Get instance.
	 *
	 * @return self
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Constructor.
	 */
	public function __construct() {
		add_action( 'admin_bar_menu', [ $this, 'add_admin_bar_menu' ], 100 );
		add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ] );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_styles' ] );
		add_action( 'wp_footer', [ $this, 'update_admin_bar_with_js' ], 9999 );
		add_action( 'admin_footer', [ $this, 'update_admin_bar_with_js' ], 9999 );
	}

	/**
	 * Enqueue admin bar styles.
	 * 
	 * @return void
	 */
	public function enqueue_styles() {
		if ( ! is_admin_bar_showing() ) {
			return;
		}

		wp_add_inline_style(
			'admin-bar',
			'
			/* Main menu item */
			#wp-admin-bar-woody-snippets .ab-icon:before {
				content: "{ }";
				font-family: monospace;
				font-size: 16px;
				font-weight: bold;
				top: -2px;
			}
			
			#wp-admin-bar-woody-snippets > .ab-item .ab-label {
				padding-left: 4px;
			}
			
			#wp-admin-bar-woody-snippets .woody-count {
				display: inline-block;
				background: #10b981;
				color: #fff;
				border-radius: 50%;
				width: 20px;
				height: 20px;
				line-height: 20px;
				text-align: center;
				font-size: 11px;
				font-weight: 600;
				margin-left: 6px;
				vertical-align: middle;
			}
			
			#wp-admin-bar-woody-snippets .woody-safe-mode {
                display: inline-block;
                background: #dba617;
                color: #fff;
                border-radius: 4px;
                padding: 0px 6px;
                font-size: 8px;
                font-weight: 600;
                margin-left: 6px;
                vertical-align: middle;
                text-transform: uppercase;
                letter-spacing: 0.5px;
			}
			
			/* Dropdown submenu */
			#wp-admin-bar-woody-snippets > .ab-sub-wrapper {
				width: 320px;
			}
			
			#wp-admin-bar-woody-snippets .ab-submenu {
				background: #23272a;
			}
			
			/* Header section */
			#wp-admin-bar-woody-snippets-header {
				background: #23272a !important;
				border-bottom: 2px solid #3b82f6 !important;
			}
			
			#wp-admin-bar-woody-snippets-header > .ab-item {
				color: #60a5fa !important;
				background: transparent !important;
				font-weight: 600;
				text-transform: uppercase;
				font-size: 11px;
				letter-spacing: 0.1em;
				cursor: default !important;
				padding: 4px 16px !important;
				line-height: 1.2;
				min-height: auto !important;
			}
			
			#wp-admin-bar-woody-snippets-header:hover > .ab-item {
				background: transparent !important;
				color: #60a5fa !important;
			}
			
			/* Snippet items */
			#wp-admin-bar-woody-snippets .woody-snippet-item > .ab-item {
				padding: 8px 16px !important;
                height: auto !important;
				line-height: 1.4;
				min-height: auto !important;
				background: #2c3338 !important;
                border-bottom: 1px solid rgb(60 67 74);
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-item {
				border-bottom: 1px solid rgba(255, 255, 255, 0.05);
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-item:hover > .ab-item {
				background: #32373c !important;
			}
			
			#wp-admin-bar-woody-snippets li.woody-snippet-item:last-of-type {
				border-bottom: none;
			}
			
			/* Snippet content wrapper */
			#wp-admin-bar-woody-snippets .woody-snippet-content {
				display: flex;
				flex-direction: column;
				gap: 8px;
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-name {
				font-weight: 400;
				font-size: 15px;
				color: #e8eaed;
				white-space: wrap;
				overflow: hidden;
				text-overflow: ellipsis;
				line-height: 1.3;
			}
			
			/* Snippet meta (type + location) */
			#wp-admin-bar-woody-snippets .woody-snippet-meta {
				display: flex;
				align-items: center;
				gap: 10px;
			}
			
			/* Type badge */
			#wp-admin-bar-woody-snippets .woody-snippet-type {
				display: inline-flex;
				align-items: center;
				justify-content: center;
				padding: 5px 11px;
				border-radius: 4px;
				font-weight: 700;
				font-size: 10px;
				text-transform: uppercase;
				letter-spacing: 0.02em;
				flex-shrink: 0;
				line-height: 1;
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-type.type-js {
				background: #f7df1e;
				color: #655b0e;
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-type.type-html {
				background: #e44d26;
				color: #fffffd;
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-type.type-php {
				background: #777bb3;
				color: #ffffff;
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-type.type-universal {
				background: #607D8B;
				color: #ffffff;
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-type.type-css {
				background: #1572b6;
				color: #ffffff;
			}
		
			#wp-admin-bar-woody-snippets .woody-snippet-type.type-text {
				background: #4CAF50;
				color: #fffffd;
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-type.type-ad {
				background: #26aa5d;
				color: #fffffd;
			}
			
			#wp-admin-bar-woody-snippets .woody-snippet-location {
				color: #a0a5aa;
				font-size: 12px;
				font-weight: 400;
				white-space: nowrap;
				overflow: hidden;
				text-overflow: ellipsis;
				line-height: 1.3;
			}
			
			/* View all link */
			#wp-admin-bar-woody-snippets-view-all {
				border-top: 1px solid rgba(255, 255, 255, 0.05);
				background: #23272a !important;
			}
			
			#wp-admin-bar-woody-snippets-view-all > .ab-item {
				text-align: center;
				color: #60a5fa !important;
				font-weight: 500;
				padding: 13px 16px !important;
				min-height: auto !important;
				background: transparent !important;
                padding: 3px 0 !important;
			}
			
			#wp-admin-bar-woody-snippets-view-all > .ab-item:after {
				content: " →";
			}
			
			#wp-admin-bar-woody-snippets-view-all:hover > .ab-item {
				color: #93c5fd !important;
				background: rgba(59, 130, 246, 0.1) !important;
			}
			
			/* Empty state */
			#wp-admin-bar-woody-snippets-empty > .ab-item {
				color: #a0a5aa !important;
				font-style: italic;
				padding: 16px !important;
				min-height: auto !important;
				background: #2c3338 !important;
			}
			
			/* Safe mode message */
			#wp-admin-bar-woody-snippets-safe-mode-message > .ab-item {
				padding: 16px !important;
				min-height: auto !important;
				background: #2c3338 !important;
				line-height: 1.5;
				color: #e8eaed;
				font-size: 14px;
				white-space: wrap !important;
				height: auto !important;
			}
			
			/* Disable safe mode button (styled like view all) */
			#wp-admin-bar-woody-snippets-disable-safe-mode {
				border-top: 1px solid rgba(255, 255, 255, 0.05);
				background: #23272a !important;
			}
			
			#wp-admin-bar-woody-snippets-disable-safe-mode > .ab-item {
				text-align: center;
				color: #60a5fa !important;
				font-weight: 500;
				padding: 13px 16px !important;
				min-height: auto !important;
				background: transparent !important;
				padding: 3px 0 !important;
			}
			
			#wp-admin-bar-woody-snippets-disable-safe-mode:hover > .ab-item {
				color: #93c5fd !important;
				background: rgba(59, 130, 246, 0.1) !important;
			}
			
			/* Pagination */
			#wp-admin-bar-woody-snippets-pagination {
				background: #23272a !important;
				border-top: 1px solid rgba(255, 255, 255, 0.05);
				border-bottom: 1px solid rgba(255, 255, 255, 0.05);
			}
			
			#wp-admin-bar-woody-snippets-pagination > .ab-item {
				display: flex !important;
				align-items: center;
				justify-content: space-between;
				padding: 8px 16px !important;
				min-height: auto !important;
				background: transparent !important;
				cursor: default !important;
			}
			
			#wp-admin-bar-woody-snippets-pagination .woody-pagination-buttons {
				display: flex;
				gap: 8px;
			}
			
			#wp-admin-bar-woody-snippets-pagination .woody-pagination-btn {
				background: #32373c;
				color: #a0a5aa;
				border: 1px solid rgba(255, 255, 255, 0.1);
				border-radius: 3px;
				padding: 4px 10px;
				font-size: 11px;
				font-weight: 500;
				cursor: pointer;
				transition: all 0.2s;
			}
			
			#wp-admin-bar-woody-snippets-pagination .woody-pagination-btn:hover:not(:disabled) {
				background: #3b82f6;
				color: #fff;
				border-color: #3b82f6;
			}
			
			#wp-admin-bar-woody-snippets-pagination .woody-pagination-btn:disabled {
				opacity: 0.4;
				cursor: not-allowed;
			}
			
			#wp-admin-bar-woody-snippets-pagination .woody-pagination-info {
				color: #a0a5aa;
				font-size: 12px;
			}
			'
		);
	}

	/**
	 * Add admin bar menu.
	 *
	 * @param WP_Admin_Bar $wp_admin_bar Admin bar instance.
	 * @return void
	 */
	public function add_admin_bar_menu( $wp_admin_bar ) {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		// Get active snippets (static for now).
		$this->collect_active_snippets();

		$count = count( $this->active_snippets );
		
		// Check if safe mode is enabled.
		$is_safe_mode = WINP_Helper::is_safe_mode();

		// Add parent menu item.
		$wp_admin_bar->add_node(
			[
				'id'     => 'woody-snippets',
				'parent' => 'top-secondary',
				'title'  => $is_safe_mode 
					? sprintf(
						'<span class="ab-icon"></span><span class="ab-label">%s</span><span class="woody-safe-mode">%s</span>',
						esc_html__( 'Woody', 'insert-php' ),
						esc_html__( 'Safe Mode', 'insert-php' )
					)
					: sprintf(
						'<span class="ab-icon"></span><span class="ab-label">%s</span><span class="woody-count">%d</span>',
						esc_html__( 'Woody', 'insert-php' ),
						$count
					),
				'href'   => admin_url( 'edit.php?post_type=' . WINP_SNIPPETS_POST_TYPE ),
				'meta'   => [
					'title' => $is_safe_mode 
						? __( 'Safe mode is enabled - snippets are not executing', 'insert-php' )
						: __( 'Active snippets on this page', 'insert-php' ),
				],
			]
		);

		// Add header.
		$wp_admin_bar->add_node(
			[
				'parent' => 'woody-snippets',
				'id'     => 'woody-snippets-header',
				'title'  => $is_safe_mode 
					? __( 'Safe Mode Enabled', 'insert-php' )
					: __( 'Active Snippets on This Page', 'insert-php' ),
				'meta'   => [
					'class' => 'woody-snippets-header',
				],
			]
		);
		
		// Add safe mode message if enabled.
		if ( $is_safe_mode ) {
			$wp_admin_bar->add_node(
				[
					'parent' => 'woody-snippets',
					'id'     => 'woody-snippets-safe-mode-message',
					'title'  => __( 'Safe Mode is active. All snippets are temporarily disabled. You can re-enable them after fixing any issues.', 'insert-php' ),
					'meta'   => [
						'class' => 'woody-safe-mode-message',
					],
				]
			);
		}

		// Add snippet items (limited to 5 per page).
		if ( ! empty( $this->active_snippets ) ) {
			$snippets_to_show = array_slice( $this->active_snippets, 0, 5 );
			foreach ( $snippets_to_show as $snippet ) {
				$wp_admin_bar->add_node(
					[
						'parent' => 'woody-snippets',
						'id'     => 'woody-snippet-' . $snippet['id'],
						'title'  => $this->render_snippet_item( $snippet ),
						'href'   => admin_url( 'post.php?post=' . $snippet['id'] . '&action=edit' ),
						'meta'   => [
							'class' => 'woody-snippet-item',
						],
					]
				);
			}
			
			// Add pagination if more than 5 snippets.
			if ( count( $this->active_snippets ) > 5 ) {
				$wp_admin_bar->add_node(
					[
						'parent' => 'woody-snippets',
						'id'     => 'woody-snippets-pagination',
						'title'  => $this->render_pagination( 1, count( $this->active_snippets ) ),
					]
				);
			}
		} elseif ( ! $is_safe_mode ) {
			// Only show empty state if not in safe mode.
			$wp_admin_bar->add_node(
				[
					'parent' => 'woody-snippets',
					'id'     => 'woody-snippets-empty',
					'title'  => __( 'No active snippets on this page', 'insert-php' ),
				]
			);
		}

		// Add disable safe mode button or view all link.
		if ( $is_safe_mode ) {
			$disable_url = admin_url( 'edit.php?post_type=wbcr-snippets&wbcr-php-snippets-disable-safe-mode=1' );
			$wp_admin_bar->add_node(
				[
					'parent' => 'woody-snippets',
					'id'     => 'woody-snippets-disable-safe-mode',
					'title'  => __( 'Disable Safe Mode', 'insert-php' ),
					'href'   => $disable_url,
				]
			);
		} else {
			$wp_admin_bar->add_node(
				[
					'parent' => 'woody-snippets',
					'id'     => 'woody-snippets-view-all',
					'title'  => __( 'View All Snippets', 'insert-php' ),
					'href'   => admin_url( 'edit.php?post_type=' . WINP_SNIPPETS_POST_TYPE ),
				]
			);
		}
	}

	/**
	 * Render snippet item HTML.
	 *
	 * @param array{id: int, name: string, type: string, location: string, scope: string} $snippet Snippet data.
	 * @return string
	 */
	private function render_snippet_item( $snippet ) {
		$type_class = 'type-' . strtolower( $snippet['type'] );
		
		return sprintf(
			'<div class="woody-snippet-content">
				<div class="woody-snippet-name">%s</div>
				<div class="woody-snippet-meta">
					<span class="woody-snippet-type %s">%s</span>
					<span class="woody-snippet-location">%s</span>
				</div>
			</div>',
			esc_html( $snippet['name'] ),
			esc_attr( $type_class ),
			esc_html( $snippet['type'] ),
			esc_html( $snippet['location'] )
		);
	}

	/**
	 * Render pagination controls.
	 *
	 * @param int $current_page Current page number.
	 * @param int $total_count Total number of snippets.
	 * @return string
	 */
	private function render_pagination( $current_page, $total_count ) {
		$total_pages = ceil( $total_count / 5 );
		$start       = ( ( $current_page - 1 ) * 5 ) + 1;
		$end         = min( $current_page * 5, $total_count );
		
		return sprintf(
			'<div style="display: flex; justify-content: space-between; align-items: center; width: 100%%;">
				<span class="woody-pagination-info">%s</span>
				<div class="woody-pagination-buttons">
					<button class="woody-pagination-btn" data-page="prev" %s>← %s</button>
					<button class="woody-pagination-btn" data-page="next" %s>%s →</button>
				</div>
			</div>',
			// translators: 1: start number, 2: end number, 3: total count.
			sprintf( __( '%1$d-%2$d of %3$d', 'insert-php' ), $start, $end, $total_count ),
			$current_page <= 1 ? 'disabled' : '',
			esc_html__( 'Previous', 'insert-php' ),
			$current_page >= $total_pages ? 'disabled' : '',
			esc_html__( 'Next', 'insert-php' )
		);
	}

	/**
	 * Collect active snippets on current page.
	 * 
	 * Gets the actually executed snippets from the execution tracker.
	 * 
	 * @return void
	 */
	private function collect_active_snippets() {
		// Get executed snippets from the execution tracker.
		if ( class_exists( 'WINP_Execute_Snippet' ) ) {
			$execute_instance = WINP_Execute_Snippet::app();
			if ( $execute_instance ) {
				$executed              = $execute_instance->get_executed_snippets();
				$this->active_snippets = array_values( $executed );
			}
		}
	}

	/**
	 * Update admin bar with JavaScript after all snippets have executed.
	 * 
	 * Outputs inline JavaScript that updates the admin bar with the final
	 * list of executed snippets, including footer snippets and shortcodes.
	 * 
	 * @return void
	 */
	public function update_admin_bar_with_js() {
		if ( ! is_admin_bar_showing() || ! current_user_can( 'manage_options' ) ) {
			return;
		}

		// Check if safe mode is enabled.
		$is_safe_mode = WINP_Helper::is_safe_mode();
		
		// If safe mode is enabled, don't update the snippets list.
		if ( $is_safe_mode ) {
			return;
		}

		// Get the final list of executed snippets.
		$this->collect_active_snippets();
		$count       = count( $this->active_snippets );
		$total_pages = ceil( $count / 5 );

		// Prepare snippet data for JavaScript.
		$snippets_data = [];
		foreach ( $this->active_snippets as $snippet ) {
			$snippets_data[] = [
				'id'       => $snippet['id'],
				'name'     => $snippet['name'],
				'type'     => $snippet['type'],
				'location' => $snippet['location'],
				'edit_url' => admin_url( 'post.php?post=' . $snippet['id'] . '&action=edit' ),
			];
		}

		?>
		<script type="text/javascript">
		(function() {
			const snippetsData = <?php echo wp_json_encode( $snippets_data ); ?>;
			const totalCount = <?php echo intval( $count ); ?>;
			const perPage = 5;
			let currentPage = 1;
			
			function renderSnippetItem(snippet) {
				const typeClass = 'type-' + snippet.type.toLowerCase();
				return `<div class="woody-snippet-content">
					<div class="woody-snippet-name">${snippet.name}</div>
					<div class="woody-snippet-meta">
						<span class="woody-snippet-type ${typeClass}">${snippet.type}</span>
						<span class="woody-snippet-location">${snippet.location}</span>
					</div>
				</div>`;
			}
			
			function renderPagination() {
				const totalPages = Math.ceil(totalCount / perPage);
				const start = ((currentPage - 1) * perPage) + 1;
				const end = Math.min(currentPage * perPage, totalCount);
				const prevDisabled = currentPage <= 1 ? 'disabled' : '';
				const nextDisabled = currentPage >= totalPages ? 'disabled' : '';
				
				return `<div style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
					<span class="woody-pagination-info">${start}-${end} of ${totalCount}</span>
					<div class="woody-pagination-buttons">
						<button class="woody-pagination-btn" data-page="prev" ${prevDisabled}>← Prev</button>
						<button class="woody-pagination-btn" data-page="next" ${nextDisabled}>Next →</button>
					</div>
				</div>`;
			}
			
			function updateDisplay() {
				const submenu = document.querySelector('#wp-admin-bar-woody-snippets .ab-submenu');
				if (!submenu) return;
				
				let html = '<li id="wp-admin-bar-woody-snippets-header"><a class="ab-item" href="javascript:void(0)"><?php echo esc_js( __( 'Active Snippets on This Page', 'insert-php' ) ); ?></a></li>';
				
				if (snippetsData.length === 0) {
					html += '<li id="wp-admin-bar-woody-snippets-empty"><a class="ab-item" href="javascript:void(0)"><?php echo esc_js( __( 'No active snippets on this page', 'insert-php' ) ); ?></a></li>';
				} else {
					const start = (currentPage - 1) * perPage;
					const end = start + perPage;
					const pageSnippets = snippetsData.slice(start, end);
					
					pageSnippets.forEach(snippet => {
						html += `<li id="wp-admin-bar-woody-snippet-${snippet.id}" class="woody-snippet-item"><a class="ab-item" href="${snippet.edit_url}">${renderSnippetItem(snippet)}</a></li>`;
					});
					
					if (snippetsData.length > perPage) {
						html += `<li id="wp-admin-bar-woody-snippets-pagination"><a class="ab-item" href="javascript:void(0)">${renderPagination()}</a></li>`;
					}
				}
				
				html += '<li id="wp-admin-bar-woody-snippets-view-all"><a class="ab-item" href="<?php echo esc_js( admin_url( 'edit.php?post_type=' . WINP_SNIPPETS_POST_TYPE ) ); ?>"><?php echo esc_js( __( 'View All Snippets', 'insert-php' ) ); ?></a></li>';
				
				submenu.innerHTML = html;
				
				// Attach pagination handlers
				const prevBtn = submenu.querySelector('[data-page="prev"]');
				const nextBtn = submenu.querySelector('[data-page="next"]');
				
				if (prevBtn) {
					prevBtn.addEventListener('click', (e) => {
						e.preventDefault();
						e.stopPropagation();
						if (currentPage > 1) {
							currentPage--;
							updateDisplay();
						}
					});
				}
				
				if (nextBtn) {
					nextBtn.addEventListener('click', (e) => {
						e.preventDefault();
						e.stopPropagation();
						const totalPages = Math.ceil(totalCount / perPage);
						if (currentPage < totalPages) {
							currentPage++;
							updateDisplay();
						}
					});
				}
			}
			
			function updateAdminBar() {
				// Update the count badge
				const countBadge = document.querySelector('#wp-admin-bar-woody-snippets .woody-count');
				if (countBadge) {
					countBadge.textContent = totalCount;
				}
				
				// Update the submenu with pagination
				updateDisplay();
			}
			
			// Try immediately
			updateAdminBar();
			
			// Also try after a small delay in case admin bar loads late
			setTimeout(updateAdminBar, 100);
		})();
		</script>
		<?php
	}
}