diff --git a/.changeset/sweet-plums-give.md b/.changeset/sweet-plums-give.md new file mode 100644 index 00000000..0ef62097 --- /dev/null +++ b/.changeset/sweet-plums-give.md @@ -0,0 +1,5 @@ +--- +"wptelegram": minor +--- + +Added link preview options diff --git a/config/wpdev.base.project.js b/config/wpdev.base.project.js index c7860b24..36538d37 100644 --- a/config/wpdev.base.project.js +++ b/config/wpdev.base.project.js @@ -20,7 +20,7 @@ export const getBundleConfig = ({ slug, key, version, textDomain }) => { requirements: { requiresPHP: '7.4', requiresAtLeast: '6.2', - testedUpTo: '6.4.1', + testedUpTo: '6.4.3', }, target: { files: [ @@ -60,6 +60,17 @@ export const getBundleConfig = ({ slug, key, version, textDomain }) => { }, ], }, + { + // Replace 'x.y.z' everywhere with the new version + type: 'general', + files: ['**/*.php'], + textPatterns: [ + { + pattern: `'(x.y.z)'`, + flags: 'gi', + }, + ], + }, ], }, { diff --git a/packages/js/form/render/RenderField.tsx b/packages/js/form/render/RenderField.tsx index f3c0a32a..fd7aa897 100644 --- a/packages/js/form/render/RenderField.tsx +++ b/packages/js/form/render/RenderField.tsx @@ -70,6 +70,7 @@ export const RenderField: TRenderField = forwardRef< isDisabled={rest.isDisabled} isInvalid={Boolean(error)} isRequired={isRequired} + opacity={props.isDisabled ? 0.5 : undefined} > {label ? ( = ({ prefix }) => { + const link_preview_disabled = useWatch({ + name: prefixName('link_preview_disabled', prefix), + }); + + return ( + + + + + + + {__('URL to use for the link preview.')} +   + {createInterpolateElement( + sprintf( + /* translators: %s code example */ + __('For example %s'), + '', + ), + { + Ex: {'{full_url}'}, + }, + )} + + } + controlClassName="no-flex" + placeholder="{full_url}" + /> + + + + + + ); +}; diff --git a/packages/js/shared/wptelegram-ui/components/MiscMessageSettings.tsx b/packages/js/shared/wptelegram-ui/components/MiscMessageSettings.tsx index 9e616a83..8c1d23a2 100644 --- a/packages/js/shared/wptelegram-ui/components/MiscMessageSettings.tsx +++ b/packages/js/shared/wptelegram-ui/components/MiscMessageSettings.tsx @@ -1,11 +1,12 @@ -import { __ } from '@wpsocio/i18n'; -import { FormField } from '@wpsocio/form'; import { FeildStack, FeildStackItem } from '@wpsocio/components'; +import { FormField } from '@wpsocio/form'; +import { __ } from '@wpsocio/i18n'; import { prefixName } from '@wpsocio/utilities'; +import { Link } from '@wpsocio/adapters'; import { getFieldLabel } from '../services'; -import type { CommonProps } from './types'; import { ParseModeField } from './ParseModeField'; +import type { CommonProps } from './types'; export const MiscMessageSettings: React.FC = ({ prefix }) => { return ( @@ -24,10 +25,22 @@ export const MiscMessageSettings: React.FC = ({ prefix }) => { + {__('Learn more')} + + } + description={__( + 'Protects the contents of sent messages from forwarding and saving.', + )} fieldType="switch" - label={getFieldLabel('disable_web_page_preview')} - description={__('Disables previews for links in the messages.')} + label={getFieldLabel('protect_content')} + name={prefixName('protect_content', prefix)} controlClassName="no-flex" /> diff --git a/packages/js/shared/wptelegram-ui/components/ProtectContent.tsx b/packages/js/shared/wptelegram-ui/components/ProtectContent.tsx deleted file mode 100644 index a94d29bc..00000000 --- a/packages/js/shared/wptelegram-ui/components/ProtectContent.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { __ } from '@wpsocio/i18n'; -import { FormField } from '@wpsocio/form'; -import { prefixName } from '@wpsocio/utilities'; -import { Link } from '@wpsocio/adapters'; - -import { getFieldLabel } from '../services'; -import type { CommonProps } from './types'; - -export const ProtectContent: React.FC = ({ prefix }) => { - return ( - - {__('Learn more')} - - } - description={__( - 'Protects the contents of sent messages from forwarding and saving.', - )} - fieldType="switch" - label={getFieldLabel('protect_content')} - name={prefixName('protect_content', prefix)} - /> - ); -}; diff --git a/packages/js/shared/wptelegram-ui/components/SingleMessage.tsx b/packages/js/shared/wptelegram-ui/components/SingleMessage.tsx index e276b7f2..9082a6a4 100644 --- a/packages/js/shared/wptelegram-ui/components/SingleMessage.tsx +++ b/packages/js/shared/wptelegram-ui/components/SingleMessage.tsx @@ -1,6 +1,6 @@ -import { __, sprintf, isRTL } from '@wpsocio/i18n'; -import { Text, List, ListItem } from '@wpsocio/adapters'; +import { List, ListItem, Text } from '@wpsocio/adapters'; import { FormField, useWatch } from '@wpsocio/form'; +import { __, isRTL, sprintf } from '@wpsocio/i18n'; import { createInterpolateElement, prefixName } from '@wpsocio/utilities'; import { getFieldLabel } from '../services'; @@ -14,10 +14,10 @@ export const SingleMessage: React.FC = ({ isDisabled, prefix, }) => { - const [disable_preview, image_position, parse_mode, single_message] = + const [link_preview_disabled, image_position, parse_mode, single_message] = useWatch({ name: [ - prefixName('disable_web_page_preview', prefix), + prefixName('link_preview_disabled', prefix), prefixName('image_position', prefix), prefixName('parse_mode', prefix), prefixName('single_message', prefix), @@ -27,7 +27,7 @@ export const SingleMessage: React.FC = ({ const showWarning = single_message && image_position === 'after' && - (parse_mode === 'none' || disable_preview); + (parse_mode === 'none' || link_preview_disabled); return ( = ({ )} )} - {disable_preview && ( + {link_preview_disabled && ( {createInterpolateElement( sprintf( @@ -82,7 +82,7 @@ export const SingleMessage: React.FC = ({ ), { DisablePreview: ( - {getFieldLabel('disable_web_page_preview')} + {getFieldLabel('link_preview_disabled')} ), }, )} diff --git a/packages/js/shared/wptelegram-ui/components/index.ts b/packages/js/shared/wptelegram-ui/components/index.ts index c6617282..1b3b43a4 100644 --- a/packages/js/shared/wptelegram-ui/components/index.ts +++ b/packages/js/shared/wptelegram-ui/components/index.ts @@ -6,6 +6,7 @@ export * from './ExcerptSettings'; export * from './IfActive'; export * from './ImageSettings'; export * from './KeyboardButton'; +export * from './LinkPreviewOptions'; export * from './MessageTemplate'; export * from './MiscMessageSettings'; export * from './NotifyInstructions'; @@ -13,7 +14,6 @@ export * from './NotifyMessageTemplate'; export * from './P2TGInstructions'; export * from './P2TGSwitchAndPluginPosts'; export * from './ParseModeField'; -export * from './ProtectContent'; export * from './TemplateInfo'; export * from './UserNotifications'; export * from './proxy'; diff --git a/packages/js/shared/wptelegram-ui/services/fields.ts b/packages/js/shared/wptelegram-ui/services/fields.ts index 61460095..67bb119f 100644 --- a/packages/js/shared/wptelegram-ui/services/fields.ts +++ b/packages/js/shared/wptelegram-ui/services/fields.ts @@ -23,7 +23,9 @@ export const fieldLabels = { debug_info: () => __('Debug Info'), delay: () => __('Delay in Posting'), disable_notification: () => __('Disable Notifications'), - disable_web_page_preview: () => __('Disable Web Page Preview'), + link_preview_disabled: () => __('Disable link preview'), + link_preview_url: () => __('Link preview URL'), + link_preview_above_text: () => __('Show preview above text'), enable_logs: () => __('Enable logs for'), excerpt_length: () => __('Excerpt Length'), excerpt_preserve_eol: () => __('Excerpt Newlines'), diff --git a/plugins/wptelegram/js/settings/services/fields.ts b/plugins/wptelegram/js/settings/services/fields.ts index b540d366..99c7eafc 100644 --- a/plugins/wptelegram/js/settings/services/fields.ts +++ b/plugins/wptelegram/js/settings/services/fields.ts @@ -127,7 +127,9 @@ export const validationSchema = yup.object({ single_message: yup.boolean(), cats_as_tags: yup.boolean(), parse_mode: parseModeSchema, - disable_web_page_preview: yup.boolean(), + link_preview_disabled: yup.boolean(), + link_preview_url: yup.string(), + link_preview_above_text: yup.boolean(), inline_button_text: yup.string(), inline_button_url: yup.string(), delay: yup diff --git a/plugins/wptelegram/js/settings/services/types.ts b/plugins/wptelegram/js/settings/services/types.ts index 4513e2b4..49a11c83 100644 --- a/plugins/wptelegram/js/settings/services/types.ts +++ b/plugins/wptelegram/js/settings/services/types.ts @@ -59,7 +59,9 @@ export interface PostToTelegramFields extends CommonFields { channels?: ChatIds; delay?: number; disable_notification?: boolean; - disable_web_page_preview?: boolean; + link_preview_disabled?: boolean; + link_preview_url?: string; + link_preview_above_text?: boolean; excerpt_length?: number; excerpt_preserve_eol?: boolean; excerpt_source?: 'post_content' | 'before_more' | 'post_excerpt'; diff --git a/plugins/wptelegram/js/settings/ui/p2tg/MessageSettings.tsx b/plugins/wptelegram/js/settings/ui/p2tg/MessageSettings.tsx index d77975ba..ab6743b8 100644 --- a/plugins/wptelegram/js/settings/ui/p2tg/MessageSettings.tsx +++ b/plugins/wptelegram/js/settings/ui/p2tg/MessageSettings.tsx @@ -5,6 +5,7 @@ import { __ } from '@wpsocio/i18n'; import { ExcerptSettings, ImageSettings, + LinkPreviewOptions, MessageTemplate, MiscMessageSettings, TemplateInfo, @@ -31,6 +32,8 @@ export const MessageSettings: React.FC = () => { + + ); }; diff --git a/plugins/wptelegram/js/settings/ui/p2tg/Miscellaneous.tsx b/plugins/wptelegram/js/settings/ui/p2tg/Miscellaneous.tsx index 3c3d92ee..6f529949 100644 --- a/plugins/wptelegram/js/settings/ui/p2tg/Miscellaneous.tsx +++ b/plugins/wptelegram/js/settings/ui/p2tg/Miscellaneous.tsx @@ -6,7 +6,6 @@ import { DelayInPosting, DisableNotification, P2TGSwitchAndPluginPosts, - ProtectContent, } from '@wpsocio/shared-wptelegram-ui'; import { useData } from '../../services'; @@ -27,7 +26,6 @@ export const Miscellaneous: React.FC = () => { - ); }; diff --git a/plugins/wptelegram/src/includes/Upgrade.php b/plugins/wptelegram/src/includes/Upgrade.php index 1c8b1058..7795aa36 100644 --- a/plugins/wptelegram/src/includes/Upgrade.php +++ b/plugins/wptelegram/src/includes/Upgrade.php @@ -56,6 +56,7 @@ public function do_upgrade() { '3.0.0', '3.0.8', '4.0.0', + '4.1.0', ]; } @@ -666,4 +667,22 @@ protected function upgrade_to_4_0_0() { } } } + + /** + * Upgrade to 4.1.0 + * + * - Upgrade to link_preview_options + * + * @since 4.1.0 + */ + protected function upgrade_to_4_1_0() { + $p2tg_settings = WPTG()->options()->get( 'p2tg' ); + + $p2tg_settings['link_preview_disabled'] = isset( $p2tg_settings['disable_web_page_preview'] ) ? boolval( $p2tg_settings['disable_web_page_preview'] ) : false; + + unset( $p2tg_settings['disable_web_page_preview'] ); + + // Update the options. + WPTG()->options()->set( 'p2tg', $p2tg_settings ); + } } diff --git a/plugins/wptelegram/src/includes/restApi/SettingsController.php b/plugins/wptelegram/src/includes/restApi/SettingsController.php index 5ec0361e..7409984c 100644 --- a/plugins/wptelegram/src/includes/restApi/SettingsController.php +++ b/plugins/wptelegram/src/includes/restApi/SettingsController.php @@ -109,36 +109,38 @@ public static function get_default_values() { 'bot_username' => '', 'p2tg' => [ // flag. - 'active' => false, + 'active' => false, // Destination. - 'channels' => [], + 'channels' => [], // Rules. - 'send_when' => [ 'new' ], - 'post_types' => [ 'post' ], - 'rules' => [], + 'send_when' => [ 'new' ], + 'post_types' => [ 'post' ], + 'rules' => [], // Message. - 'message_template' => '{post_title}' . PHP_EOL . PHP_EOL . '{post_excerpt}' . PHP_EOL . PHP_EOL . '{full_url}', - 'excerpt_source' => 'post_content', - 'excerpt_length' => 55, - 'excerpt_preserve_eol' => true, + 'message_template' => '{post_title}' . PHP_EOL . PHP_EOL . '{post_excerpt}' . PHP_EOL . PHP_EOL . '{full_url}', + 'excerpt_source' => 'post_content', + 'excerpt_length' => 55, + 'excerpt_preserve_eol' => true, // Image. - 'send_featured_image' => true, - 'image_position' => 'before', - 'single_message' => true, + 'send_featured_image' => true, + 'image_position' => 'before', + 'single_message' => true, // Formatting. - 'cats_as_tags' => false, - 'parse_mode' => 'none', - 'disable_web_page_preview' => false, + 'cats_as_tags' => false, + 'parse_mode' => 'none', + 'link_preview_disabled' => false, + 'link_preview_url' => '', + 'link_preview_above_text' => false, // Inline button. - 'inline_url_button' => false, - 'inline_button_text' => sprintf( '🔗 %s', __( 'View Post', 'wptelegram' ) ), - 'inline_button_url' => '{full_url}', + 'inline_url_button' => false, + 'inline_button_text' => sprintf( '🔗 %s', __( 'View Post', 'wptelegram' ) ), + 'inline_button_url' => '{full_url}', // Misc. - 'plugin_posts' => false, - 'post_edit_switch' => true, - 'delay' => $is_wp_cron_disabled ? 0 : 0.5, - 'disable_notification' => false, - 'protect_content' => false, + 'plugin_posts' => false, + 'post_edit_switch' => true, + 'delay' => $is_wp_cron_disabled ? 0 : 0.5, + 'disable_notification' => false, + 'protect_content' => false, ], 'notify' => [ 'active' => false, @@ -237,29 +239,29 @@ public static function get_settings_params( $context = 'edit' ) { 'sanitize_callback' => [ __CLASS__, 'sanitize_param' ], 'validate_callback' => 'rest_validate_request_arg', 'properties' => [ - 'active' => [ + 'active' => [ 'type' => 'boolean', ], - 'channels' => [ + 'channels' => [ 'type' => 'array', 'items' => [ 'type' => 'string', ], ], - 'send_when' => [ + 'send_when' => [ 'type' => 'array', 'items' => [ 'type' => 'string', 'enum' => [ 'new', 'existing' ], ], ], - 'post_types' => [ + 'post_types' => [ 'type' => 'array', 'items' => [ 'type' => 'string', ], ], - 'rules' => [ + 'rules' => [ 'type' => 'array', 'items' => [ 'type' => 'array', @@ -291,64 +293,70 @@ public static function get_settings_params( $context = 'edit' ) { ], ], ], - 'message_template' => [ + 'message_template' => [ 'type' => 'string', ], - 'excerpt_source' => [ + 'excerpt_source' => [ 'type' => 'string', 'enum' => [ 'post_content', 'before_more', 'post_excerpt' ], ], - 'excerpt_length' => [ + 'excerpt_length' => [ 'type' => 'integer', 'minimum' => 1, 'maximum' => 300, ], - 'excerpt_preserve_eol' => [ + 'excerpt_preserve_eol' => [ 'type' => 'boolean', ], - 'send_featured_image' => [ + 'send_featured_image' => [ 'type' => 'boolean', ], - 'image_position' => [ + 'image_position' => [ 'type' => 'string', 'enum' => [ 'before', 'after' ], ], - 'single_message' => [ + 'single_message' => [ 'type' => 'boolean', ], - 'cats_as_tags' => [ + 'cats_as_tags' => [ 'type' => 'boolean', ], - 'parse_mode' => [ + 'parse_mode' => [ 'type' => 'string', 'enum' => [ 'none', 'HTML' ], ], - 'disable_web_page_preview' => [ + 'link_preview_disabled' => [ 'type' => 'boolean', ], - 'inline_url_button' => [ + 'link_preview_url' => [ + 'type' => 'string', + ], + 'link_preview_above_text' => [ + 'type' => 'boolean', + ], + 'inline_url_button' => [ 'type' => 'boolean', ], - 'inline_button_text' => [ + 'inline_button_text' => [ 'type' => 'string', ], - 'inline_button_url' => [ + 'inline_button_url' => [ 'type' => 'string', ], - 'plugin_posts' => [ + 'plugin_posts' => [ 'type' => 'boolean', ], - 'post_edit_switch' => [ + 'post_edit_switch' => [ 'type' => 'boolean', ], - 'delay' => [ + 'delay' => [ 'type' => 'number', 'minimum' => 0, ], - 'disable_notification' => [ + 'disable_notification' => [ 'type' => 'boolean', ], - 'protect_content' => [ + 'protect_content' => [ 'type' => 'boolean', ], ], diff --git a/plugins/wptelegram/src/modules/notify/NotifySender.php b/plugins/wptelegram/src/modules/notify/NotifySender.php index 19d9ee6f..20a3819b 100644 --- a/plugins/wptelegram/src/modules/notify/NotifySender.php +++ b/plugins/wptelegram/src/modules/notify/NotifySender.php @@ -181,9 +181,9 @@ private function prepare_default_responses() { $this->responses = [ [ 'sendMessage' => [ - 'text' => Utils::prepare_content( $text, $options ), - 'parse_mode' => $options['format_to'], - 'disable_web_page_preview' => true, + 'text' => Utils::prepare_content( $text, $options ), + 'parse_mode' => $options['format_to'], + 'link_preview_options' => wp_json_encode( [ 'is_disabled' => true ] ), ], ], ]; diff --git a/plugins/wptelegram/src/modules/p2tg/PostSender.php b/plugins/wptelegram/src/modules/p2tg/PostSender.php index 4df86b5f..196356ff 100644 --- a/plugins/wptelegram/src/modules/p2tg/PostSender.php +++ b/plugins/wptelegram/src/modules/p2tg/PostSender.php @@ -230,27 +230,29 @@ public function set_form_data() { public static function get_defaults() { $array = []; $defaults = [ - 'cats_as_tags' => false, - 'channels' => $array, - 'delay' => 0, - 'disable_notification' => false, - 'disable_web_page_preview' => false, - 'excerpt_length' => 55, - 'excerpt_preserve_eol' => false, - 'excerpt_source' => 'post_content', - 'image_position' => 'before', - 'inline_button_text' => '', - 'inline_button_url' => '', - 'inline_url_button' => false, - 'message_template' => '', - 'parse_mode' => '', - 'plugin_posts' => false, - 'post_types' => $array, - 'protect_content' => false, - 'rules' => $array, - 'send_featured_image' => true, - 'send_when' => $array, - 'single_message' => false, + 'cats_as_tags' => false, + 'channels' => $array, + 'delay' => 0, + 'disable_notification' => false, + 'link_preview_disabled' => false, + 'link_preview_url' => '', + 'link_preview_above_text' => false, + 'excerpt_length' => 55, + 'excerpt_preserve_eol' => false, + 'excerpt_source' => 'post_content', + 'image_position' => 'before', + 'inline_button_text' => '', + 'inline_button_url' => '', + 'inline_url_button' => false, + 'message_template' => '', + 'parse_mode' => '', + 'plugin_posts' => false, + 'post_types' => $array, + 'protect_content' => false, + 'rules' => $array, + 'send_featured_image' => true, + 'send_when' => $array, + 'single_message' => false, ]; return (array) apply_filters( 'wptelegram_p2tg_defaults', $defaults ); @@ -1056,6 +1058,39 @@ private function check_for_rules() { return $rules->rules_apply( $this->options->get( 'rules' ), $this->post ); } + /** + * Get the link preview options + * + * @return array + */ + protected function get_link_preview_options() { + $link_preview_options = [ + 'is_disabled' => $this->options->get( 'link_preview_disabled' ), + ]; + + if ( ! $link_preview_options['is_disabled'] ) { + + unset( $link_preview_options['is_disabled'] ); + + $link_preview_url = $this->options->get( 'link_preview_url' ); + + if ( $link_preview_url ) { + + $parser = new TemplateParser( $this->post, $this->options ); + + $url = $parser->parse( $link_preview_url ); + + if ( $url ) { + $link_preview_options['url'] = $url; + } + } + + $link_preview_options['show_above_text'] = $this->options->get( 'link_preview_above_text', false ); + } + + return apply_filters( 'wptelegram_p2tg_link_preview_options', $link_preview_options, $this->post, $this->options ); + } + /** * Create responses based on the text and image source * @@ -1070,9 +1105,9 @@ private function get_default_responses( $text, $image_source ) { $parse_mode = MainUtils::valid_parse_mode( $this->options->get( 'parse_mode' ) ); - $disable_web_page_preview = $this->options->get( 'disable_web_page_preview' ); - $disable_notification = $this->options->get( 'disable_notification' ); - $protect_content = $this->options->get( 'protect_content' ); + $link_preview_options = wp_json_encode( $this->get_link_preview_options() ); + $disable_notification = $this->options->get( 'disable_notification' ); + $protect_content = $this->options->get( 'protect_content' ); $limit_to_one_message = apply_filters( 'wptelegram_p2tg_limit_text_to_one_message', true, $this->post, $this->options, $text, $image_source ); @@ -1085,20 +1120,15 @@ private function get_default_responses( $text, $image_source ) { $caption_options = array_merge( $text_options, [ 'limit' => MainUtils::get_max_text_length( 'caption' ) ] ); - // Do not fail if the replied-to message is not found. - $allow_sending_without_reply = true; - $method_params = [ 'sendPhoto' => compact( - 'allow_sending_without_reply', 'disable_notification', 'parse_mode', 'protect_content' ), 'sendMessage' => compact( - 'allow_sending_without_reply', 'disable_notification', - 'disable_web_page_preview', + 'link_preview_options', 'parse_mode', 'protect_content' ), @@ -1315,46 +1345,22 @@ public function get_inline_keyboard( $method_params ) { * @return string */ public static function get_parsed_button_url( $url_template, $post_id ) { - $macro_keys = [ - 'full_url', - 'short_url', - ]; - - $post_data = new PostData( $post_id ); + $parser = new TemplateParser( $post_id ); - $macro_values = []; + $button_url_filter = function ( $macro_values, $template, $post ) { + return (array) apply_filters_deprecated( + 'wptelegram_p2tg_button_url_macro_values', + [ $macro_values, $template, $post->ID ], + 'x.y.z', + 'wptelegram_p2tg_template_macro_values' + ); + }; - foreach ( $macro_keys as $macro_key ) { + add_filter( 'wptelegram_p2tg_template_macro_values', $button_url_filter, 10, 3 ); - // get the value only if it's in the template. - if ( false !== strpos( $url_template, '{' . $macro_key . '}' ) ) { + $url = $parser->parse( $url_template ); - $macro_values[ '{' . $macro_key . '}' ] = $post_data->get_field( $macro_key ); - } - } - - // if it's something unusual :) . - if ( preg_match_all( '/(?<=\{)(cf):([^\}]+?)(?=\})/iu', $url_template, $matches ) ) { - - foreach ( $matches[0] as $field ) { - - $macro_values[ '{' . $field . '}' ] = $post_data->get_field( $field ); - } - } - - /** - * Use this filter to replace your own macros - * with the corresponding values - */ - $macro_values = (array) apply_filters( 'wptelegram_p2tg_button_url_macro_values', $macro_values, $url_template, $post_id ); - - // decode all HTML entities & URL encode non-URL values. - foreach ( $macro_values as &$value ) { - // decode all HTML entities. - $value = MainUtils::decode_html( $value ); - } - - $url = str_replace( array_keys( $macro_values ), array_values( $macro_values ), $url_template ); + remove_filter( 'wptelegram_p2tg_template_macro_values', $button_url_filter, 10, 3 ); return apply_filters( 'wptelegram_p2tg_parsed_button_url', $url, $url_template, $post_id ); } @@ -1370,154 +1376,13 @@ public static function get_parsed_button_url( $url_template, $post_id ) { */ private function get_response_text( $template ) { - // Remove wpautop() from the `the_content` filter - // to preserve newlines. - $priority = has_filter( 'the_content', 'wpautop' ); - if ( false !== $priority ) { - remove_filter( 'the_content', 'wpautop', $priority ); - add_filter( 'the_content', [ $this, 'restore_wpautop_hook' ], $priority + 1 ); - } - - $excerpt_source = $this->options->get( 'excerpt_source' ); - $excerpt_length = (int) $this->options->get( 'excerpt_length' ); - $excerpt_preserve_eol = $this->options->get( 'excerpt_preserve_eol' ); - $cats_as_tags = $this->options->get( 'cats_as_tags' ); - $parse_mode = MainUtils::valid_parse_mode( $this->options->get( 'parse_mode' ) ); - - // replace {tags} and {categories} with taxonomy names. - $replace = [ '{terms:post_tag}', '{terms:category}' ]; - - // use tags and categories for WooCommerce. - if ( class_exists( 'woocommerce' ) && 'product' === $this->post->post_type ) { - - $replace = [ '{terms:product_tag}', '{terms:product_cat}' ]; - } - - // modify the template. - $template = str_replace( [ '{tags}', '{categories}' ], $replace, $template ); - - $macro_keys = [ - 'ID', - 'post_title', - 'post_slug', - 'post_date', - 'post_date_gmt', - 'post_author', - 'post_excerpt', - 'post_content', - 'post_type', - 'post_type_label', - 'short_url', - 'full_url', - ]; - - // for post excerpt. - $params = compact( 'excerpt_source', 'excerpt_length', 'excerpt_preserve_eol', 'cats_as_tags', 'parse_mode' ); - - $macro_values = []; - - foreach ( $macro_keys as $macro_key ) { + $parser = new TemplateParser( $this->post, $this->options ); - $macro = '{' . $macro_key . '}'; - - // get the value only if it's in the template. - if ( false !== strpos( $template, $macro ) ) { - - $macro_values[ $macro ] = $this->post_data->get_field( $macro_key, $params ); - } - } - - // if it's something unusual. - if ( preg_match_all( '/(?<=\{)(terms|cf):([^\}]+?)(?=\})/iu', $template, $matches ) ) { - - foreach ( $matches[0] as $field ) { - - $macro_values[ '{' . $field . '}' ] = $this->post_data->get_field( $field, $params ); - } - } - - /** - * Use this filter to replace your own macros - * with the corresponding values - */ - $macro_values = (array) apply_filters( 'wptelegram_p2tg_macro_values', $macro_values, $this->post, $this->options ); - - // stripslashes for all values. - $macro_values = array_map( 'stripslashes', $macro_values ); - - // lets replace the conditional macros. - $template = $this->process_template_logic( $template, $macro_values ); - - // replace the lone macros with values. - $text = str_replace( array_keys( $macro_values ), array_values( $macro_values ), $template ); + $text = $parser->parse( $template ); return apply_filters( 'wptelegram_p2tg_response_text', $text, $template, $this->post, $this->options ); } - /** - * Resolve the conditional macros in the template - * - * @since 2.0.17 - * - * @param string $template The message template. - * @param array $macro_values The values for macros. - * @return string - */ - private function process_template_logic( $template, $macro_values ) { - - $raw_template = $template; - - $pattern = '/\[if\s*? # Conditional block starts - (\{[^\}]+?\}) # Conditional expression, a macro - \] # Conditional block ends - \[ # Consequence block starts - ([^\]]+?) # Consequence expression - \] # Consequence block ends - (?: # non-capturing alternative block - \[ # Alternative block starts - ([^\]]*?) # Alternative expression - \] # Alternative block ends - )? # Make alternative block optional - /ix'; - - preg_match_all( $pattern, $template, $matches ); - - // loop through the conditional expressions. - foreach ( $matches[1] as $key => $macro ) { - - // if expression is false, take from alternative. - $index = empty( $macro_values[ $macro ] ) ? 3 : 2; - - $replace = str_replace( array_keys( $macro_values ), array_values( $macro_values ), $matches[ $index ][ $key ] ); - - $template = str_replace( $matches[0][ $key ], $replace, $template ); - } - - // remove the ugly empty lines. - $template = preg_replace( '/(?:\A|[\n\r]).*?\{remove_line\}.*/u', '', $template ); - - return apply_filters( 'wptelegram_p2tg_process_template_logic', $template, $macro_values, $raw_template, $this->post, $this->options ); - } - - /** - * Re-add wp_autop() to the `the_content` filter. - * - * @access public - * - * @since 2.1.3 - * - * @param string $content The post content running through this filter. - * @return string The unmodified content. - */ - public function restore_wpautop_hook( $content ) { - $current_priority = has_filter( 'the_content', [ $this, 'restore_wpautop_hook' ] ); - - add_filter( 'the_content', 'wpautop', $current_priority - 1 ); - remove_filter( 'the_content', [ $this, 'restore_wpautop_hook' ], $current_priority ); - - return $content; - } - /** * Get the featured image URL or file location * @@ -1601,8 +1466,16 @@ private function send_responses() { if ( $message_as_reply && $this->bot_api->is_success( $res ) ) { - $result = $res->get_result(); - $params['reply_to_message_id'] = $result ? $result['message_id'] : null; + $result = $res->get_result(); + // send next message in reply to the previous one. + if ( ! empty( $result['message_id'] ) ) { + $params['reply_parameters'] = wp_json_encode( + [ + 'allow_sending_without_reply' => true, + 'message_id' => $result['message_id'], + ] + ); + } } /** diff --git a/plugins/wptelegram/src/modules/p2tg/TemplateParser.php b/plugins/wptelegram/src/modules/p2tg/TemplateParser.php new file mode 100644 index 00000000..c0d3d544 --- /dev/null +++ b/plugins/wptelegram/src/modules/p2tg/TemplateParser.php @@ -0,0 +1,367 @@ +set_post( $post ); + $this->set_options( $options ); + } + + /** + * Set the post + * + * @since x.y.z + * @param int|WP_Post $post Post object or ID. + */ + public function set_post( $post ) { + $this->post = get_post( $post ); + + $this->reset_data(); + + return $this; + } + + /** + * Set the post + * + * @since x.y.z + * + * @param Options $options The options for parsing the template. + */ + public function set_options( $options ) { + if ( ! $options ) { + // set to an empty object by default. + $options = new Options(); + } + $this->options = $options; + + return $this; + } + + /** + * Reset the existing post data. + */ + public function reset_data() { + $this->post_data = new PostData( $this->post ); + + return $this; + } + + /** + * Returns the valid parse mode. + */ + public function get_parse_mode() { + return MainUtils::valid_parse_mode( $this->options->get( 'parse_mode' ) ); + } + + /** + * Parses the given template and converts it to the text. + * + * @since x.y.z + * + * @param string $template The template to parse. + * + * @return string The parsed value. + */ + public function parse( $template ) { + + $template = $this->normalize_template( $template ); + + $macro_values = $this->parse_macros( $template ); + + // lets replace the conditional macros. + $template = $this->process_template_logic( $template, $macro_values ); + + $text = str_replace( array_keys( $macro_values ), array_values( $macro_values ), $template ); + + $text = $this->encode_values( $text ); + + return apply_filters( 'wptelegram_p2tg_parsed_template', $text, $template, $this->post, $this->options ); + } + + /** + * Parses the given template to encode the values if needed. + * + * @since x.y.z + * + * @param string $template The template to parse. + * + * @return string The parsed value. + */ + public function encode_values( $template ) { + $pattern = '#\{encode:([^\}]+?)\}#iu'; + + $encoded = preg_replace_callback( + $pattern, + function ( $match ) { + return rawurlencode( $match[1] ); + }, + $template + ); + + return apply_filters( 'wptelegram_p2tg_template_encoded_values', $encoded, $template ); + } + + /** + * Parses the given template to set the correct values to be parsed. + * + * @since x.y.z + * + * @param string $template The template to parse. + * + * @return string The normalized value. + */ + public function normalize_template( $template ) { + + $raw_template = $template; + + // replace {tags} and {categories} with taxonomy names. + $replace = [ '{terms:post_tag}', '{terms:category}' ]; + + // Use {tags} and {categories} for WooCommerce products. + if ( class_exists( 'woocommerce' ) && 'product' === $this->post->post_type ) { + + $replace = [ '{terms:product_tag}', '{terms:product_cat}' ]; + } + + // Modify the template. + $template = str_replace( [ '{tags}', '{categories}' ], $replace, $template ); + + return apply_filters( 'wptelegram_p2tg_normalized_template', $template, $raw_template, $this->post, $this->options ); + } + + /** + * Parses the given template for all possible macros and returns the macro data. + * + * @since x.y.z + * + * @param string $template The template to parse. + * + * @return array The parsed macro values. + */ + public function parse_macros( $template ) { + + // Remove wpautop() from the `the_content` filter + // to preserve newlines. + self::bypass_wpautop_for( 'the_content' ); + + $excerpt_source = $this->options->get( 'excerpt_source' ); + $excerpt_length = (int) $this->options->get( 'excerpt_length' ); + $excerpt_preserve_eol = $this->options->get( 'excerpt_preserve_eol' ); + $cats_as_tags = $this->options->get( 'cats_as_tags' ); + $parse_mode = MainUtils::valid_parse_mode( $this->options->get( 'parse_mode' ) ); + + $template = $this->normalize_template( $template ); + + $macro_keys = [ + 'ID', + 'featured_image_url', + 'full_url', + 'post_author', + 'post_content', + 'post_date', + 'post_date_gmt', + 'post_excerpt', + 'post_slug', + 'post_title', + 'post_type', + 'post_type_label', + 'short_url', + ]; + + // for post excerpt. + $params = compact( + 'excerpt_source', + 'excerpt_length', + 'excerpt_preserve_eol', + 'cats_as_tags', + 'parse_mode' + ); + + $macro_values = []; + + foreach ( $macro_keys as $macro_key ) { + $key = '{' . $macro_key . '}'; + + // get the value only if it's in the template. + if ( false !== strpos( $template, $key ) ) { + + $macro_values[ $key ] = $this->post_data->get_field( $macro_key, $params ); + } + } + + // if it's something unusual :) . + if ( preg_match_all( '/(?<=\{)(terms|a?cf):([^\}]+?)(?=\})/iu', $template, $matches ) ) { + + foreach ( $matches[0] as $field ) { + $key = '{' . $field . '}'; + + $macro_values[ $key ] = $this->post_data->get_field( $field, $params ); + } + } + + /** + * Use this filter to replace your own macros + * with the corresponding values + */ + $macro_values = (array) apply_filters( 'wptelegram_p2tg_template_macro_values', $macro_values, $template, $this->post, $this->options ); + + $macro_values = (array) apply_filters_deprecated( 'wptelegram_p2tg_macro_values', [ $macro_values, $this->post, $this->options ], 'x.y.z', 'wptelegram_p2tg_template_macro_values' ); + + // Prepare macro values for further processing. + $macro_values = array_map( [ $this, 'prepare_macro_value' ], $macro_values ); + + return $macro_values; + } + + /** + * Prepare macro value for further processing. + * + * @since x.y.z + * + * @param string $macro_value The value for a macro. + * + * @return string + */ + public function prepare_macro_value( $macro_value ) { + // Remove unwanted slashes. + return stripslashes( $macro_value ); + } + + /** + * Resolve the conditional macros in the template. + * + * @since x.y.z + * + * @param string $template The message template being processed. + * @param array $macro_values The values for all macros. + * + * @return string + */ + private function process_template_logic( $template, $macro_values ) { + + $raw_template = $template; + + $pattern = '/\[if\s*? # Conditional block starts + (\{[^\}]+?\}) # Conditional expression, a macro + \] # Conditional block ends + \[ # Consequence block starts + ([^\]]+?) # Consequence expression + \] # Consequence block ends + (?: # non-capturing alternative block + \[ # Alternative block starts + ([^\]]*?) # Alternative expression + \] # Alternative block ends + )? # Make alternative block optional + /ix'; + + preg_match_all( $pattern, $template, $matches ); + + // loop through the conditional expressions. + foreach ( $matches[1] as $key => $macro ) { + + // if expression is false, take from alternative. + $index = empty( $macro_values[ $macro ] ) ? 3 : 2; + + $replace = str_replace( array_keys( $macro_values ), array_values( $macro_values ), $matches[ $index ][ $key ] ); + + $template = str_replace( $matches[0][ $key ], $replace, $template ); + } + + // remove the ugly empty lines. + $template = preg_replace( '/(?:\A|[\n\r]).*?\{remove_line\}.*/u', '', $template ); + + return apply_filters( 'wptelegram_p2tg_process_template_logic', $template, $macro_values, $raw_template, $this->post, $this->options ); + } + + /** + * Bypass wpautop() from the given filter + * to preserve newlines. + * + * @since x.y.z + * + * @param string $tag The name of the filter hook like "the_content". + */ + public static function bypass_wpautop_for( $tag ) { + $priority = has_filter( $tag, 'wpautop' ); + if ( false !== $priority ) { + remove_filter( $tag, 'wpautop', $priority ); + add_filter( $tag, [ __CLASS__, 'restore_wpautop_hook' ], $priority + 1 ); + } + } + + /** + * Re-add wp_autop() to the given filter. + * + * @access public + * + * @since x.y.z + * + * @param string $content The post content running through this filter. + * @return string The unmodified content. + */ + public static function restore_wpautop_hook( $content ) { + $tag = current_filter(); + + $current_priority = has_filter( $tag, [ __CLASS__, 'restore_wpautop_hook' ] ); + + add_filter( $tag, 'wpautop', $current_priority - 1 ); + remove_filter( $tag, [ __CLASS__, 'restore_wpautop_hook' ], $current_priority ); + + return $content; + } +}