get( 'license' ); return $license->is_feature_available( $feature ); } /** * Every FeatureMap feature, mapped to whether the current tier has it. * * What the admin and frontend scripts receive as webcalApiSettings.features. * Built from the map rather than listed by hand: the two hand-written copies * this replaces had drifted, both missing filter_by_place and image_sideload. * * @return array */ function webcal_feature_flags(): array { $flags = []; foreach ( array_keys( \WebCalendar\WP\License\FeatureMap::all() ) as $feature ) { $flags[ $feature ] = webcal_feature_available( $feature ); } return $flags; } /** * The PHP date format the calendar displays dates in. * * The calendar's own Date Format setting, falling back to WordPress's * (Settings → General) when it is blank. "Ymd" counts as blank: it was the * field's pre-filled value, so any site that saved the settings page for * another reason stored it without choosing it. * * @return string A PHP date() format string. */ function webcal_date_format(): string { $raw = get_option( 'webcal_config_DATE_FORMAT', '' ); $format = is_scalar( $raw ) ? trim( (string) $raw ) : ''; if ( '' === $format || 'Ymd' === $format ) { $wp_raw = get_option( 'date_format', '' ); $format = is_scalar( $wp_raw ) ? trim( (string) $wp_raw ) : ''; } return '' === $format ? 'Y-m-d' : $format; } /** * The calendar's Time Format setting: '12' or '24'. * * One default for every reader. The settings screen used to default to '24' * while the calendars defaulted to '12', so a site that never saved the page * showed "24-hour" selected and rendered 12-hour times. * * @return string '12' or '24'. */ function webcal_time_format(): string { $raw = get_option( 'webcal_config_TIME_FORMAT', '12' ); return ( is_scalar( $raw ) && '24' === (string) $raw ) ? '24' : '12'; } /** * The PHP time format matching the Time Format setting. * * @return string 'H:i' for 24-hour, 'g:i A' for 12-hour. */ function webcal_time_php_format(): string { return '24' === webcal_time_format() ? 'H:i' : 'g:i A'; } /** * Resolve the capability required to use the AI/MCP integration. * * Driven by the `webcal_mcp_audience` setting: `admins` (default) requires * `manage_options`; `all` requires `webcal_can_view`, so any calendar user can * connect their own assistant. Access stays scoped either way — every tool has * its own `permission_callback` and SQL-level access filtering still applies. * * @return string A WordPress capability slug. */ function webcal_mcp_capability(): string { $audience = get_option( 'webcal_mcp_audience', 'admins' ); return ( is_scalar( $audience ) && (string) $audience === 'all' ) ? 'webcal_can_view' : 'manage_options'; } /** * Render an upgrade notice for a gated feature. * * @param string $feature Feature identifier. */ function webcal_upgrade_notice( string $feature ): void { if ( webcal_feature_available( $feature ) ) { return; } /** @var \WebCalendar\WP\License\License */ $license = Container::get_instance()->get( 'license' ); $tier = $license->get_tier(); $upgrade_url = \WebCalendar\WP\License\License::PRICING_URL; if ( $license->is_freemius_active() ) { $fs = $license->get_freemius(); if ( $fs !== null ) { $upgrade_url = $fs->get_upgrade_url(); } } printf( '

%s %s

', esc_html__( 'This feature is not available in your current license tier.', 'agenticdaisy-calendar' ), esc_url( $upgrade_url ), esc_html__( 'Upgrade now to unlock.', 'agenticdaisy-calendar' ) ); }