Commit realizado el 12:13:52 08-04-2024
This commit is contained in:
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" stroke="#6c7781"><g fill="none" fill-rule="evenodd"><g transform="translate(1 1)" stroke-width="2"><circle stroke-opacity=".5" cx="18" cy="18" r="18"/><path d="M36 18c0-9.94-8.06-18-18-18"><animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="1s" repeatCount="indefinite"/></path></g></g></svg>
|
||||
|
After Width: | Height: | Size: 417 B |
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+16
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* Block script dependencies.
|
||||
*
|
||||
* @package RankMath
|
||||
* @subpackage RankMath\ContentAI
|
||||
* @author Rank Math <support@rankmath.com>
|
||||
*/
|
||||
|
||||
return [
|
||||
'dependencies' => [
|
||||
'wp-element',
|
||||
'wp-block-editor',
|
||||
],
|
||||
'version' => rank_math()->version,
|
||||
];
|
||||
+1
@@ -0,0 +1 @@
|
||||
!function(){"use strict";var e=wp.blocks,t=wp.blockEditor,n=wp.element,r=wp.i18n,a=function(){return!rankMath.isUserRegistered||!rankMath.contentAIPlan||!rankMath.contentAICredits||rankMath.contentAiMigrating},o=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"rank-math/command","title":"AI Assistant [Content AI]","icon":"star","category":"rank-math-blocks","description":"Generate content without any hassle, powered by Rank Math\'s Content AI.","keywords":["ai","content","rank math","rankmath","content ai","seo"],"textdomain":"rank-math-pro","editorScript":"file:../js/index.js","attributes":{"content":{"type":"string","source":"html","selector":"p","default":"<span>//</span>","__experimentalRole":"content"}}}');function c(e){return c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},c(e)}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e,t,n){return(t=function(e){var t=function(e,t){if("object"!==c(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!==c(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===c(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var m=o.name,u={icon:wp.element.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 17.08 18.02"},wp.element.createElement("g",{id:"Layer_2","data-name":"Layer 2"},wp.element.createElement("g",{id:"Layer_1-2","data-name":"Layer 1"},wp.element.createElement("path",{d:"M16.65,12.08a.83.83,0,0,0-1.11.35A7.38,7.38,0,1,1,9,1.63a7.11,7.11,0,0,1,.92.06A2.52,2.52,0,0,1,11,.23,8.87,8.87,0,0,0,9,0a9,9,0,1,0,8,13.19A.83.83,0,0,0,16.65,12.08Z"}),wp.element.createElement("path",{d:"M7.68,7.29A1.58,1.58,0,0,0,6.2,8.94a1.57,1.57,0,0,0,1.48,1.64A1.56,1.56,0,0,0,9.16,8.94,1.57,1.57,0,0,0,7.68,7.29Z"}),wp.element.createElement("path",{d:"M13.34,4.71a2.45,2.45,0,0,1-1,.2A2.53,2.53,0,0,1,9.93,3,7.18,7.18,0,0,0,9.12,3a6,6,0,1,0,4.22,1.73ZM10.53,11.3a.75.75,0,1,1-1.5,0v-.06a2.4,2.4,0,0,1-1.66.69,2.81,2.81,0,0,1-2.58-3,2.82,2.82,0,0,1,2.58-3A2.39,2.39,0,0,1,9,6.64a.75.75,0,0,1,1.5.07Zm2.56,0a.75.75,0,1,1-1.5,0V6.71a.75.75,0,1,1,1.5,0Z"}),wp.element.createElement("circle",{cx:"12.42",cy:"2.37",r:"1.45"})))),edit:function(e){var o=e.attributes,c=e.onReplace,l=e.setAttributes,i=o.content,m=(0,t.useBlockProps)({className:"rank-math-content-ai-command"}),u=(0,n.useRef)(null);return(0,n.useEffect)((function(){var e=u.current;e.focus();var t=document.createRange(),n=window.getSelection();t.selectNodeContents(e),t.collapse(!1),n.removeAllRanges(),n.addRange(t)}),[]),wp.element.createElement("div",m,wp.element.createElement(t.BlockControls,null),a()&&wp.element.createElement("div",{className:"rich-text",ref:u},rankMath.isUserRegistered?rankMath.contentAIPlan?wp.element.createElement(React.Fragment,null,(0,r.__)("You have exhausted your Content AI Credits.","rank-math"),wp.element.createElement("a",{href:"https://rankmath.com/kb/how-to-use-content-ai/?play-video=ioPeVIntJWw&utm_source=Plugin&utm_medium=Buy+Credits+Button&utm_campaign=WP",target:"_blank",rel:"noreferrer"},(0,r.__)("Get more","rank-math"))):wp.element.createElement(React.Fragment,null,(0,r.__)("You do not have a Content AI plan.","rank-math"),wp.element.createElement("a",{href:"https://rankmath.com/kb/how-to-use-content-ai/?play-video=ioPeVIntJWw&utm_source=Plugin&utm_medium=Buy+Plan+Button&utm_campaign=WP"},(0,r.__)("Choose your plan","rank-math"))):wp.element.createElement(React.Fragment,null,(0,r.__)("Start using Content AI by connecting your RankMath account.","rank-math"),wp.element.createElement("a",{href:rankMath.connectSiteUrl},(0,r.__)("Connect Now","rank-math")))),!a()&&wp.element.createElement(t.RichText,{tagName:"div",allowedFormats:[],value:i,onChange:function(e){return l({content:e})},onSplit:function(){return!1},onReplace:c,"data-empty":!i,isSelected:!0,ref:u}))}};(0,e.registerBlockType)(function(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}({name:m},o),u)}();
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2,
|
||||
"name": "rank-math/command",
|
||||
"title": "AI Assistant [Content AI]",
|
||||
"icon": "star",
|
||||
"category": "rank-math-blocks",
|
||||
"description": "Generate content without any hassle, powered by Rank Math's Content AI.",
|
||||
"keywords": [ "ai", "content", "rank math", "rankmath", "content ai", "seo" ],
|
||||
"textdomain": "rank-math-pro",
|
||||
"editorScript": "file:../js/index.js",
|
||||
"attributes": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"source": "html",
|
||||
"selector": "p",
|
||||
"default": "<span>//</span>",
|
||||
"__experimentalRole": "content"
|
||||
}
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* WordPress dependencies
|
||||
*/
|
||||
import {
|
||||
RichText,
|
||||
useBlockProps,
|
||||
BlockControls,
|
||||
} from '@wordpress/block-editor'
|
||||
import { useRef, useEffect } from '@wordpress/element'
|
||||
import { __ } from '@wordpress/i18n'
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import hasError from '../../../../assets/src/page/helpers/hasError'
|
||||
|
||||
const getErrorMessage = () => {
|
||||
if ( ! rankMath.isUserRegistered ) {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
__( 'Start using Content AI by connecting your RankMath account.', 'rank-math' )
|
||||
}
|
||||
<a href={ rankMath.connectSiteUrl }>{ __( 'Connect Now', 'rank-math' ) }</a>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
if ( ! rankMath.contentAIPlan ) {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
__( 'You do not have a Content AI plan.', 'rank-math' )
|
||||
}
|
||||
<a href="https://rankmath.com/kb/how-to-use-content-ai/?play-video=ioPeVIntJWw&utm_source=Plugin&utm_medium=Buy+Plan+Button&utm_campaign=WP">{ __( 'Choose your plan', 'rank-math' ) }</a>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
__( 'You have exhausted your Content AI Credits.', 'rank-math' )
|
||||
}
|
||||
<a href="https://rankmath.com/kb/how-to-use-content-ai/?play-video=ioPeVIntJWw&utm_source=Plugin&utm_medium=Buy+Credits+Button&utm_campaign=WP" target="_blank" rel="noreferrer">{ __( 'Get more', 'rank-math' ) }</a>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ( {
|
||||
attributes,
|
||||
onReplace,
|
||||
setAttributes,
|
||||
} ) => {
|
||||
const { content } = attributes
|
||||
const blockProps = useBlockProps( {
|
||||
className: 'rank-math-content-ai-command',
|
||||
} )
|
||||
|
||||
const contentEditableRef = useRef( null )
|
||||
useEffect( () => {
|
||||
const { current: contentEditable } = contentEditableRef
|
||||
contentEditable.focus()
|
||||
|
||||
const range = document.createRange()
|
||||
const selection = window.getSelection()
|
||||
range.selectNodeContents( contentEditable )
|
||||
range.collapse( false )
|
||||
selection.removeAllRanges()
|
||||
selection.addRange( range )
|
||||
}, [] )
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<BlockControls />
|
||||
{
|
||||
hasError() &&
|
||||
<div className="rich-text" ref={ contentEditableRef }>
|
||||
{ getErrorMessage() }
|
||||
</div>
|
||||
}
|
||||
{
|
||||
! hasError() &&
|
||||
<RichText
|
||||
tagName="div"
|
||||
allowedFormats={ [] }
|
||||
value={ content }
|
||||
onChange={ ( newContent ) => {
|
||||
return setAttributes( { content: newContent } )
|
||||
} }
|
||||
onSplit={ () => {
|
||||
return false
|
||||
} }
|
||||
onReplace={ onReplace }
|
||||
data-empty={ content ? false : true }
|
||||
isSelected={ true }
|
||||
ref={ contentEditableRef }
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* WordPress dependencies
|
||||
*/
|
||||
import { registerBlockType } from '@wordpress/blocks'
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import edit from './edit'
|
||||
import metadata from './block.json'
|
||||
|
||||
const { name } = metadata
|
||||
|
||||
export { metadata, name }
|
||||
|
||||
export const settings = {
|
||||
icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17.08 18.02"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M16.65,12.08a.83.83,0,0,0-1.11.35A7.38,7.38,0,1,1,9,1.63a7.11,7.11,0,0,1,.92.06A2.52,2.52,0,0,1,11,.23,8.87,8.87,0,0,0,9,0a9,9,0,1,0,8,13.19A.83.83,0,0,0,16.65,12.08Z"/><path d="M7.68,7.29A1.58,1.58,0,0,0,6.2,8.94a1.57,1.57,0,0,0,1.48,1.64A1.56,1.56,0,0,0,9.16,8.94,1.57,1.57,0,0,0,7.68,7.29Z" /><path d="M13.34,4.71a2.45,2.45,0,0,1-1,.2A2.53,2.53,0,0,1,9.93,3,7.18,7.18,0,0,0,9.12,3a6,6,0,1,0,4.22,1.73ZM10.53,11.3a.75.75,0,1,1-1.5,0v-.06a2.4,2.4,0,0,1-1.66.69,2.81,2.81,0,0,1-2.58-3,2.82,2.82,0,0,1,2.58-3A2.39,2.39,0,0,1,9,6.64a.75.75,0,0,1,1.5.07Zm2.56,0a.75.75,0,1,1-1.5,0V6.71a.75.75,0,1,1,1.5,0Z" /><circle cx="12.42" cy="2.37" r="1.45" /></g></g></svg>,
|
||||
edit,
|
||||
}
|
||||
|
||||
registerBlockType( { name, ...metadata }, settings )
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* The TOC Block
|
||||
*
|
||||
* @since 1.0.104
|
||||
* @package RankMath
|
||||
* @subpackage RankMath\ContentAI
|
||||
* @author Rank Math <support@rankmath.com>
|
||||
*/
|
||||
|
||||
namespace RankMath\ContentAI;
|
||||
|
||||
use WP_Block_Type_Registry;
|
||||
use RankMath\Helper;
|
||||
use RankMath\Traits\Hooker;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Content AI Command Block class.
|
||||
*/
|
||||
class Block_Command {
|
||||
|
||||
use Hooker;
|
||||
|
||||
/**
|
||||
* Block type name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $block_type = 'rank-math/command';
|
||||
|
||||
/**
|
||||
* The single instance of the class.
|
||||
*
|
||||
* @var Block_Command
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Retrieve main Block_Command instance.
|
||||
*
|
||||
* Ensure only one instance is loaded or can be loaded.
|
||||
*
|
||||
* @return Block_Command
|
||||
*/
|
||||
public static function get() {
|
||||
if ( is_null( self::$instance ) && ! ( self::$instance instanceof Block_Command ) ) {
|
||||
self::$instance = new Block_Command();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( WP_Block_Type_Registry::get_instance()->is_registered( $this->block_type ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
register_block_type( RANK_MATH_PATH . 'includes/modules/content-ai/blocks/command/assets/src/block.json' );
|
||||
}
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
/**
|
||||
* Add Content AI Bulk Action options.
|
||||
*
|
||||
* @since 1.0.212
|
||||
* @package RankMath
|
||||
* @subpackage RankMath\Content_AI_Page
|
||||
* @author Rank Math <support@rankmath.com>
|
||||
*/
|
||||
|
||||
namespace RankMath\ContentAI;
|
||||
|
||||
use RankMath\Traits\Hooker;
|
||||
use RankMath\Helper;
|
||||
use RankMath\Helpers\Str;
|
||||
use RankMath\Paper\Paper;
|
||||
use RankMath\Admin\Admin_Helper;
|
||||
use RankMath\Post;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Bulk_Actions class.
|
||||
*/
|
||||
class Bulk_Actions {
|
||||
use Hooker;
|
||||
|
||||
/**
|
||||
* The Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->action( 'admin_init', 'init_admin', 15 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
public function init_admin() {
|
||||
$post_types = Helper::get_settings( 'general.content_ai_post_types', [] );
|
||||
foreach ( $post_types as $post_type ) {
|
||||
$this->filter( "bulk_actions-edit-{$post_type}", 'bulk_actions', 9 );
|
||||
$this->filter( "handle_bulk_actions-edit-{$post_type}", 'handle_bulk_actions', 10, 3 );
|
||||
}
|
||||
|
||||
$taxonomies = Helper::get_accessible_taxonomies();
|
||||
unset( $taxonomies['post_format'] );
|
||||
$taxonomies = wp_list_pluck( $taxonomies, 'label', 'name' );
|
||||
foreach ( $taxonomies as $taxonomy => $label ) {
|
||||
$this->filter( "bulk_actions-edit-{$taxonomy}", 'bulk_actions' );
|
||||
$this->filter( "handle_bulk_actions-edit-{$taxonomy}", 'handle_bulk_actions', 10, 3 );
|
||||
}
|
||||
|
||||
$this->filter( 'wp_bulk_edit_seo_meta_post_args', 'update_background_process_args' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bulk actions for applicable posts, pages, CPTs.
|
||||
*
|
||||
* @param array $actions Actions.
|
||||
* @return array New actions.
|
||||
*/
|
||||
public function bulk_actions( $actions ) {
|
||||
if ( ! Helper::has_cap( 'content_ai' ) ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
$actions['rank_math_ai_options'] = __( '↓ Rank Math Content AI', 'rank-math' );
|
||||
$actions['rank_math_content_ai_fetch_seo_title'] = esc_html__( 'Write SEO Title with AI', 'rank-math' );
|
||||
$actions['rank_math_content_ai_fetch_seo_description'] = esc_html__( 'Write SEO Description with AI', 'rank-math' );
|
||||
$actions['rank_math_content_ai_fetch_seo_title_description'] = esc_html__( 'Write SEO Title & Description with AI', 'rank-math' );
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle bulk actions for applicable posts, pages, CPTs.
|
||||
*
|
||||
* @param string $redirect Redirect URL.
|
||||
* @param string $doaction Performed action.
|
||||
* @param array $object_ids Post IDs.
|
||||
*
|
||||
* @return string New redirect URL.
|
||||
*/
|
||||
public function handle_bulk_actions( $redirect, $doaction, $object_ids ) {
|
||||
if ( empty( $object_ids ) || ! in_array( $doaction, [ 'rank_math_content_ai_fetch_seo_title', 'rank_math_content_ai_fetch_seo_description', 'rank_math_content_ai_fetch_seo_title_description' ], true ) ) {
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
if ( ! empty( get_option( 'rank_math_content_ai_posts' ) ) ) {
|
||||
Helper::add_notification(
|
||||
esc_html__( 'Another bulk editing process is already running. Please try again later after the existing process is complete.', 'rank-math' ),
|
||||
[
|
||||
'type' => 'warning',
|
||||
'id' => 'rank_math_content_ai_posts_error',
|
||||
'classes' => 'rank-math-notice',
|
||||
]
|
||||
);
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
$action = 'both';
|
||||
if ( 'rank_math_content_ai_fetch_seo_title' === $doaction ) {
|
||||
$action = 'title';
|
||||
}
|
||||
|
||||
if ( 'rank_math_content_ai_fetch_seo_description' === $doaction ) {
|
||||
$action = 'description';
|
||||
}
|
||||
|
||||
$is_post_list = Admin_Helper::is_post_list();
|
||||
$data = [
|
||||
'action' => $action,
|
||||
'language' => Helper::get_settings( 'general.content_ai_language', Helper::content_ai_default_language() ),
|
||||
'posts' => [],
|
||||
'is_taxonomy' => ! $is_post_list,
|
||||
];
|
||||
|
||||
$method = $is_post_list ? 'get_post_data' : 'get_term_data';
|
||||
foreach ( $object_ids as $object_id ) {
|
||||
$data['posts'][] = $this->$method( $object_id );
|
||||
}
|
||||
|
||||
Bulk_Edit_SEO_Meta::get()->start( $data );
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the timeout value in Background_Process to resolve the issue with notifications not appearing after completion in v1.2.
|
||||
*
|
||||
* @param array $args Process args.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function update_background_process_args( $args ) {
|
||||
$args['timeout'] = 0.01;
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Post data.
|
||||
*
|
||||
* @param integer $object_id Post ID.
|
||||
*
|
||||
* @return array Post data.
|
||||
*/
|
||||
private function get_post_data( $object_id ) {
|
||||
$object = get_post( $object_id );
|
||||
return [
|
||||
'post_id' => $object_id,
|
||||
'post_type' => 'download' === $object->post_type ? 'Product' : ucfirst( $object->post_type ),
|
||||
'title' => get_the_title( $object_id ),
|
||||
'focus_keyword' => Post::get_meta( 'focus_keyword', $object_id ),
|
||||
'summary' => Helper::replace_vars( $this->get_post_description( $object ), $object ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Term data.
|
||||
*
|
||||
* @param integer $object_id Term ID.
|
||||
*
|
||||
* @return array Term data.
|
||||
*/
|
||||
private function get_term_data( $object_id ) {
|
||||
$object = get_term( $object_id );
|
||||
return [
|
||||
'post_id' => $object_id,
|
||||
'post_type' => $object->taxonomy,
|
||||
'title' => $object->name,
|
||||
'focus_keyword' => get_term_meta( $object_id, 'rank_math_focus_keyword', true ),
|
||||
'summary' => Helper::replace_vars( $this->get_term_description( $object ), $object ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post description.
|
||||
*
|
||||
* @param WP_Post $object Post Instance.
|
||||
*
|
||||
* @return string Post description.
|
||||
*/
|
||||
private function get_post_description( $object ) {
|
||||
$description = Post::get_meta( 'description', $object->ID );
|
||||
if ( '' !== $description ) {
|
||||
return $description;
|
||||
}
|
||||
|
||||
return ! empty( $object->post_excerpt ) ? $object->post_excerpt : Str::truncate( Paper::get_from_options( "pt_{$object->post_type}_description", $object ), 160 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post description.
|
||||
*
|
||||
* @param WP_Post $object Post Instance.
|
||||
*
|
||||
* @return string Post description.
|
||||
*/
|
||||
private function get_term_description( $object ) {
|
||||
$description = get_term_meta( $object->term_id, 'rank_math_description', true );
|
||||
if ( '' !== $description ) {
|
||||
return $description;
|
||||
}
|
||||
|
||||
return ! empty( $object->description ) ? $object->description : Str::truncate( Paper::get_from_options( "tax_{$object->taxonomy}_description", $object ), 160 );
|
||||
}
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/**
|
||||
* Bulk Edit SEO Meta data from Content AI API.
|
||||
*
|
||||
* @since 1.0.108
|
||||
* @package RankMath
|
||||
* @subpackage RankMath\Status
|
||||
* @author Rank Math <support@rankmath.com>
|
||||
*/
|
||||
|
||||
namespace RankMath\ContentAI;
|
||||
|
||||
use RankMath\Helper;
|
||||
use RankMath\Admin\Admin_Helper;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Bulk_Edit_SEO_Meta class.
|
||||
*/
|
||||
class Bulk_Edit_SEO_Meta extends \WP_Background_Process {
|
||||
|
||||
/**
|
||||
* Action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $action = 'bulk_edit_seo_meta';
|
||||
|
||||
/**
|
||||
* Main instance.
|
||||
*
|
||||
* Ensure only one instance is loaded or can be loaded.
|
||||
*
|
||||
* @return Bulk_Edit_SEO_Meta
|
||||
*/
|
||||
public static function get() {
|
||||
static $instance;
|
||||
|
||||
if ( is_null( $instance ) && ! ( $instance instanceof Bulk_Edit_SEO_Meta ) ) {
|
||||
$instance = new Bulk_Edit_SEO_Meta();
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start creating batches.
|
||||
*
|
||||
* @param array $data Posts data.
|
||||
*/
|
||||
public function start( $data ) {
|
||||
Helper::add_notification(
|
||||
esc_html__( 'Bulk editing SEO meta started. It might take few minutes to complete the process.', 'rank-math' ),
|
||||
[
|
||||
'type' => 'success',
|
||||
'id' => 'rank_math_content_ai_posts_started',
|
||||
'classes' => 'rank-math-notice',
|
||||
]
|
||||
);
|
||||
|
||||
$action = $data['action'];
|
||||
$posts = $data['posts'];
|
||||
$language = $data['language'];
|
||||
|
||||
update_option( 'rank_math_content_ai_posts', $posts );
|
||||
$chunks = array_chunk( $posts, 10, true );
|
||||
foreach ( $chunks as $chunk ) {
|
||||
$this->push_to_queue(
|
||||
[
|
||||
'posts' => $chunk,
|
||||
'action' => $action,
|
||||
'language' => $language,
|
||||
'is_taxonomy' => ! empty( $data['is_taxonomy'] ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$this->save()->dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to perform.
|
||||
*
|
||||
* @param string $data Posts to process.
|
||||
*/
|
||||
public function wizard( $data ) {
|
||||
$this->task( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the Bulk edit process.
|
||||
*/
|
||||
public function cancel() {
|
||||
delete_option( 'rank_math_content_ai_posts' );
|
||||
delete_option( 'rank_math_content_ai_posts_processed' );
|
||||
parent::clear_scheduled_event();
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete.
|
||||
*
|
||||
* Override if applicable, but ensure that the below actions are
|
||||
* performed, or, call parent::complete().
|
||||
*/
|
||||
protected function complete() {
|
||||
$posts = get_option( 'rank_math_content_ai_posts' );
|
||||
delete_option( 'rank_math_content_ai_posts' );
|
||||
delete_option( 'rank_math_content_ai_posts_processed' );
|
||||
Helper::add_notification(
|
||||
// Translators: placeholder is the number of modified items.
|
||||
sprintf( _n( 'SEO meta successfully updated in %d item.', 'SEO meta successfully updated in %d items.', count( $posts ), 'rank-math' ), count( $posts ) ),
|
||||
[
|
||||
'type' => 'success',
|
||||
'id' => 'rank_math_content_ai_posts',
|
||||
'classes' => 'rank-math-notice',
|
||||
]
|
||||
);
|
||||
|
||||
parent::complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to perform.
|
||||
*
|
||||
* @param array $data Posts to process.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function task( $data ) {
|
||||
try {
|
||||
$posts = json_decode( wp_remote_retrieve_body( $this->get_posts( $data ) ), true );
|
||||
if ( empty( $posts['meta'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $posts['meta'] as $post_id => $data ) {
|
||||
$method = ! empty( $data['object_type'] ) && 'term' === $data['object_type'] ? 'update_term_meta' : 'update_post_meta';
|
||||
if ( ! empty( $data['title'] ) ) {
|
||||
$method( $post_id, 'rank_math_title', sanitize_text_field( $data['title'] ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $data['description'] ) ) {
|
||||
$method( $post_id, 'rank_math_description', sanitize_textarea_field( $data['description'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
$this->update_content_ai_posts_count( count( $posts['meta'] ) );
|
||||
|
||||
$credits = ! empty( $posts['credits'] ) ? $posts['credits'] : [];
|
||||
if ( ! empty( $credits['available'] ) ) {
|
||||
$credits = $credits['available'] - $credits['taken'];
|
||||
Helper::update_credits( $credits );
|
||||
|
||||
if ( $credits <= 0 ) {
|
||||
$posts_processed = get_option( 'rank_math_content_ai_posts_processed' );
|
||||
delete_option( 'rank_math_content_ai_posts' );
|
||||
delete_option( 'rank_math_content_ai_posts_processed' );
|
||||
Helper::add_notification(
|
||||
// Translators: placeholder is the number of modified posts.
|
||||
sprintf( esc_html__( 'SEO meta successfully updated in %d posts. The process was stopped as you have used all the credits on your site.', 'rank-math' ), $posts_processed ),
|
||||
[
|
||||
'type' => 'success',
|
||||
'id' => 'rank_math_content_ai_posts',
|
||||
'classes' => 'rank-math-notice',
|
||||
]
|
||||
);
|
||||
|
||||
wp_clear_scheduled_hook( 'wp_bulk_edit_seo_meta_cron' );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch ( Exception $error ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Posts to bulk update the data.
|
||||
*
|
||||
* @param array $data Data to process.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_posts( $data ) {
|
||||
$connect_data = Admin_Helper::get_registration_data();
|
||||
$posts = array_values( $data['posts'] );
|
||||
$action = $data['action'];
|
||||
$language = $data['language'];
|
||||
$data = [
|
||||
'posts' => $posts,
|
||||
'output' => $action,
|
||||
'language' => $language,
|
||||
'choices' => 1,
|
||||
'username' => $connect_data['username'],
|
||||
'api_key' => $connect_data['api_key'],
|
||||
'site_url' => $connect_data['site_url'],
|
||||
'is_taxonomy' => ! empty( $data['is_taxonomy'] ),
|
||||
'plugin_version' => rank_math()->version,
|
||||
];
|
||||
|
||||
return wp_remote_post(
|
||||
CONTENT_AI_URL . '/ai/bulk_seo_meta',
|
||||
[
|
||||
'headers' => [
|
||||
'content-type' => 'application/json',
|
||||
],
|
||||
'timeout' => 60000,
|
||||
'body' => wp_json_encode( $data ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep count of the Content AI posts that were processed.
|
||||
*
|
||||
* @param int $count Number of posts processed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function update_content_ai_posts_count( $count ) {
|
||||
$content_ai_posts_count = get_option( 'rank_math_content_ai_posts_processed', 0 ) + $count;
|
||||
update_option( 'rank_math_content_ai_posts_processed', $content_ai_posts_count, false );
|
||||
}
|
||||
}
|
||||
+374
@@ -0,0 +1,374 @@
|
||||
<?php
|
||||
/**
|
||||
* The Role Manager Module.
|
||||
*
|
||||
* @since 0.9.0
|
||||
* @package RankMath
|
||||
* @subpackage RankMath\Content_AI_Page
|
||||
* @author Rank Math <support@rankmath.com>
|
||||
*/
|
||||
|
||||
namespace RankMath\ContentAI;
|
||||
|
||||
use RankMath\ContentAI\Content_AI;
|
||||
use RankMath\Helper;
|
||||
use RankMath\Traits\Hooker;
|
||||
use RankMath\Admin\Page;
|
||||
use RankMath\Helpers\Param;
|
||||
use WP_Block_Editor_Context;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Content_AI_Page class.
|
||||
*/
|
||||
class Content_AI_Page {
|
||||
use Hooker;
|
||||
|
||||
/**
|
||||
* The Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->action( 'rank_math/admin_bar/items', 'admin_bar_items', 11 );
|
||||
$this->action( 'rank_math/admin/editor_scripts', 'enqueue' );
|
||||
$this->action( 'init', 'init' );
|
||||
$this->filter( 'wp_insert_post_data', 'remove_unused_generated_content' );
|
||||
$this->filter( 'rank_math/database/tools', 'add_tools' );
|
||||
$this->filter( 'rank_math/tools/content_ai_cancel_bulk_edit_process', 'cancel_bulk_edit_process' );
|
||||
|
||||
if ( Param::get( 'page' ) !== 'rank-math-content-ai-page' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->action( 'rank_math/before_help_link', 'add_credits_remaining' );
|
||||
$this->action( 'admin_footer', 'content_editor_settings' );
|
||||
add_filter( 'should_load_block_editor_scripts_and_styles', '__return_true' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Init function.
|
||||
*/
|
||||
public function init() {
|
||||
$this->register_post_type();
|
||||
$this->register_admin_page();
|
||||
Block_Command::get();
|
||||
Bulk_Edit_SEO_Meta::get();
|
||||
Event_Scheduler::get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Credits remaining text before the help link in the admin header.
|
||||
*/
|
||||
public function add_credits_remaining() {
|
||||
// Early bail if site is not connected or doesn't have a Content AI Plan.
|
||||
if ( ! Helper::is_site_connected() || ! Helper::get_content_ai_plan() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$credits = Helper::get_credits();
|
||||
?>
|
||||
<div class="credits-remaining">
|
||||
<?php echo esc_html__( 'Credits Remaining: ', 'rank-math' ); ?>
|
||||
<strong><?php echo esc_html( $credits ); ?></strong>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue Content AI Page CSS.
|
||||
*/
|
||||
public function enqueue() {
|
||||
wp_enqueue_style(
|
||||
'rank-math-content-ai-page',
|
||||
rank_math()->plugin_url() . 'includes/modules/content-ai/assets/css/content-ai-page.css',
|
||||
[ 'rank-math-common' ],
|
||||
rank_math()->version
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'rank-math-content-ai-page',
|
||||
rank_math()->plugin_url() . 'includes/modules/content-ai/assets/js/content-ai-page.js',
|
||||
[
|
||||
'lodash',
|
||||
'wp-dom-ready',
|
||||
'rank-math-content-ai',
|
||||
],
|
||||
rank_math()->version,
|
||||
true
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'rank-math-content-ai-page', 'rank-math' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register admin page.
|
||||
*/
|
||||
public function register_admin_page() {
|
||||
$uri = untrailingslashit( plugin_dir_url( __FILE__ ) );
|
||||
|
||||
$new_label = '<span class="rank-math-new-label" style="color:#ed5e5e;font-size:10px;font-weight:normal;">' . esc_html__( 'New!', 'rank-math' ) . '</span>';
|
||||
|
||||
if ( 'rank-math-content-ai-page' === Param::get( 'page' ) ) {
|
||||
Helper::add_json( 'isContentAIPage', true );
|
||||
Content_AI::localized_data();
|
||||
}
|
||||
|
||||
new Page(
|
||||
'rank-math-content-ai-page',
|
||||
esc_html__( 'Content AI', 'rank-math' ),
|
||||
[
|
||||
'position' => 4,
|
||||
'parent' => 'rank-math',
|
||||
// Translators: placeholder is the new label.
|
||||
'menu_title' => sprintf( esc_html__( 'Content AI %s', 'rank-math' ), $new_label ),
|
||||
'capability' => 'rank_math_content_ai',
|
||||
'render' => dirname( __FILE__ ) . '/views/main.php',
|
||||
'classes' => [ 'rank-math-page' ],
|
||||
'assets' => [
|
||||
'styles' => [
|
||||
'wp-edit-post' => '',
|
||||
'rank-math-common' => '',
|
||||
'rank-math-cmb2' => '',
|
||||
'wp-block-library' => '',
|
||||
'rank-math-content-ai-page' => $uri . '/assets/css/content-ai-page.css',
|
||||
],
|
||||
'scripts' => [
|
||||
'lodash' => '',
|
||||
'wp-components' => '',
|
||||
'wp-block-library' => '',
|
||||
'wp-format-library' => '',
|
||||
'wp-edit-post' => '',
|
||||
'wp-blocks' => '',
|
||||
'wp-element' => '',
|
||||
'wp-editor' => '',
|
||||
'rank-math-block-faq' => rank_math()->plugin_url() . 'assets/admin/js/blocks.js',
|
||||
'rank-math-analyzer' => rank_math()->plugin_url() . 'assets/admin/js/analyzer.js',
|
||||
'rank-math-content-ai' => rank_math()->plugin_url() . 'includes/modules/content-ai/assets/js/content-ai.js',
|
||||
'rank-math-content-ai-page' => $uri . '/assets/js/content-ai-page.js',
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add admin bar item.
|
||||
*
|
||||
* @param Admin_Bar_Menu $menu Menu class instance.
|
||||
*/
|
||||
public function admin_bar_items( $menu ) {
|
||||
$url = Helper::get_admin_url( 'content-ai-page' );
|
||||
$menu->add_sub_menu(
|
||||
'content-ai-page',
|
||||
[
|
||||
'title' => esc_html__( 'Content AI', 'rank-math' ),
|
||||
'href' => $url,
|
||||
'priority' => 50,
|
||||
]
|
||||
);
|
||||
|
||||
$items = [
|
||||
'content-ai-tools' => [
|
||||
'title' => esc_html__( 'AI Tools', 'rank-math' ),
|
||||
'href' => $url . '#ai-tools',
|
||||
'meta' => [ 'title' => esc_html__( 'Content AI Tools', 'rank-math' ) ],
|
||||
],
|
||||
|
||||
'content-ai-editor' => [
|
||||
'title' => esc_html__( 'Content Editor', 'rank-math' ),
|
||||
'href' => $url . '#content-editor',
|
||||
'meta' => [ 'title' => esc_html__( 'Content AI Editor', 'rank-math' ) ],
|
||||
],
|
||||
|
||||
'content-ai-chat' => [
|
||||
'title' => esc_html__( 'Chat', 'rank-math' ),
|
||||
'href' => $url . '#chat',
|
||||
'meta' => [ 'title' => esc_html__( 'Content AI Chat', 'rank-math' ) ],
|
||||
],
|
||||
|
||||
'content-ai-history' => [
|
||||
'title' => esc_html__( 'History', 'rank-math' ),
|
||||
'href' => $url . '#history',
|
||||
'meta' => [ 'title' => esc_html__( 'Content AI History', 'rank-math' ) ],
|
||||
],
|
||||
];
|
||||
|
||||
foreach ( $items as $id => $args ) {
|
||||
$menu->add_sub_menu( $id, $args, 'content-ai-page' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Content Editor Settings.
|
||||
*/
|
||||
public function content_editor_settings() {
|
||||
$post = $this->get_content_editor_post();
|
||||
$block_editor_context = new WP_Block_Editor_Context( [ 'post' => [] ] );
|
||||
|
||||
// Flag that we're loading the block editor.
|
||||
$current_screen = get_current_screen();
|
||||
$current_screen->is_block_editor( true );
|
||||
|
||||
$editor_settings = [
|
||||
'availableTemplates' => [],
|
||||
'disablePostFormats' => true,
|
||||
'autosaveInterval' => 0,
|
||||
'richEditingEnabled' => user_can_richedit(),
|
||||
'supportsLayout' => function_exists( 'wp_theme_has_theme_json' ) ? wp_theme_has_theme_json() : false,
|
||||
'supportsTemplateMode' => false,
|
||||
'enableCustomFields' => false,
|
||||
];
|
||||
|
||||
$editor_settings = get_block_editor_settings( $editor_settings, $block_editor_context );
|
||||
|
||||
/**
|
||||
* Scripts
|
||||
*/
|
||||
wp_enqueue_media( [ 'post' => $post->ID ] );
|
||||
?>
|
||||
|
||||
<div id="editor2" data-settings='<?php echo esc_attr( wp_json_encode( $editor_settings ) ); ?>' data-post-id="<?php echo esc_attr( $post->ID ); ?>"></div>
|
||||
<?php
|
||||
|
||||
wp_set_script_translations( 'rank-math-content-ai', 'rank-math' );
|
||||
wp_set_script_translations( 'rank-math-content-ai-page', 'rank-math' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unsed content generated from the Toolbar option of the Content AI.
|
||||
*
|
||||
* @param array $data An array of slashed, sanitized, and processed post data.
|
||||
*/
|
||||
public function remove_unused_generated_content( $data ) {
|
||||
$blocks = parse_blocks( $data['post_content'] );
|
||||
if ( empty( $blocks ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$update = false;
|
||||
foreach ( $blocks as $key => $block ) {
|
||||
if ( 'rank-math/command' === $block['blockName'] ) {
|
||||
unset( $blocks[ $key ] );
|
||||
$update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $update ) {
|
||||
$data['post_content'] = serialize_blocks( $blocks );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add database tools.
|
||||
*
|
||||
* @param array $tools Array of tools.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_tools( $tools ) {
|
||||
$posts = get_option( 'rank_math_content_ai_posts' );
|
||||
|
||||
// Early Bail if process is not running.
|
||||
if ( empty( $posts ) ) {
|
||||
return $tools;
|
||||
}
|
||||
|
||||
$processed = get_option( 'rank_math_content_ai_posts_processed' );
|
||||
|
||||
$tools['content_ai_cancel_bulk_edit_process'] = [
|
||||
'title' => esc_html__( 'Cancel Content AI Bulk Editing Process', 'rank-math' ),
|
||||
'description' => sprintf(
|
||||
// Translators: placeholders are the number of posts that were processed.
|
||||
esc_html__( 'Terminate the ongoing Content AI Bulk Editing Process to halt any pending modifications and revert to the previous state. The bulk metadata has been generated for %1$d out of %1$d posts so far.', 'rank-math' ),
|
||||
$processed,
|
||||
count( $posts )
|
||||
),
|
||||
'button_text' => esc_html__( 'Terminate', 'rank-math' ),
|
||||
];
|
||||
|
||||
return $tools;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to cancel the Bulk Edit process.
|
||||
*/
|
||||
public function cancel_bulk_edit_process() {
|
||||
Bulk_Edit_SEO_Meta::get()->cancel();
|
||||
Helper::remove_notification( 'rank_math_content_ai_posts_started' );
|
||||
return __( 'Bulk Editing Process Successfully Cancelled', 'rank-math' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Content AI post type to use the post in Content Editor.
|
||||
*/
|
||||
private function register_post_type() {
|
||||
register_post_type(
|
||||
'rm_content_editor',
|
||||
[
|
||||
'label' => 'RM Content Editor',
|
||||
'public' => false,
|
||||
'publicly_queryable' => false,
|
||||
'show_ui' => false,
|
||||
'show_in_rest' => true,
|
||||
'has_archive' => false,
|
||||
'show_in_menu' => false,
|
||||
'show_in_nav_menus' => false,
|
||||
'delete_with_user' => false,
|
||||
'exclude_from_search' => false,
|
||||
'capability_type' => 'page',
|
||||
'map_meta_cap' => true,
|
||||
'hierarchical' => false,
|
||||
'rewrite' => false,
|
||||
'query_var' => false,
|
||||
'supports' => [ 'editor' ],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Content Editor post.
|
||||
*
|
||||
* @return int Post ID.
|
||||
*/
|
||||
private function get_content_editor_post() {
|
||||
$posts = get_posts(
|
||||
[
|
||||
'post_type' => 'rm_content_editor',
|
||||
'numberposts' => 1,
|
||||
'post_status' => 'any',
|
||||
]
|
||||
);
|
||||
|
||||
if ( empty( $posts ) ) {
|
||||
$post_id = wp_insert_post(
|
||||
[
|
||||
'post_type' => 'rm_content_editor',
|
||||
'post_content' => '<!-- wp:rank-math/command /-->',
|
||||
]
|
||||
);
|
||||
|
||||
return get_post( $post_id );
|
||||
}
|
||||
|
||||
$ai_post = current( $posts );
|
||||
$content = $ai_post->post_content;
|
||||
$blocks = parse_blocks( $content );
|
||||
if ( ! empty( $blocks ) && count( $blocks ) < 2 && 'core/paragraph' === $blocks[0]['blockName'] ) {
|
||||
$content = do_blocks( $ai_post->post_content );
|
||||
$content = trim( preg_replace( '/<p[^>]*><\\/p[^>]*>/', '', $content ) );
|
||||
}
|
||||
|
||||
if ( ! $content ) {
|
||||
wp_update_post(
|
||||
[
|
||||
'ID' => $ai_post->ID,
|
||||
'post_content' => '<!-- wp:rank-math/command /-->',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return $ai_post;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
/**
|
||||
* The Content AI module.
|
||||
*
|
||||
* @since 1.0.71
|
||||
* @package RankMath
|
||||
* @subpackage RankMath
|
||||
* @author Rank Math <support@rankmath.com>
|
||||
*/
|
||||
|
||||
namespace RankMath\ContentAI;
|
||||
|
||||
use RankMath\KB;
|
||||
use RankMath\Helper;
|
||||
use RankMath\Helpers\Sitepress;
|
||||
use RankMath\Helpers\Url;
|
||||
use RankMath\Helpers\Arr;
|
||||
use RankMath\Admin\Admin_Helper as AdminHelper;
|
||||
use RankMath\CMB2;
|
||||
use RankMath\Traits\Hooker;
|
||||
use RankMath\Traits\Ajax;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Content_AI class.
|
||||
*/
|
||||
class Content_AI {
|
||||
use Hooker, Ajax;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->action( 'rest_api_init', 'init_rest_api' );
|
||||
|
||||
new Content_AI_Page();
|
||||
new Bulk_Actions();
|
||||
if ( ! Helper::has_cap( 'content_ai' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->filter( 'rank_math/analytics/post_data', 'add_contentai_data', 10, 2 );
|
||||
$this->filter( 'rank_math/settings/general', 'add_settings' );
|
||||
$this->action( 'rank_math/admin/editor_scripts', 'editor_scripts', 20 );
|
||||
$this->filter( 'rank_math/metabox/post/values', 'add_metadata', 10, 2 );
|
||||
$this->action( 'cmb2_admin_init', 'add_content_ai_metabox', 11 );
|
||||
$this->action( 'rank_math/deregister_site', 'remove_credits_data' );
|
||||
$this->filter( 'rank_math/elementor/dark_styles', 'add_dark_style' );
|
||||
$this->filter( 'rank_math/status/rank_math_info', 'content_ai_info' );
|
||||
$this->action( 'rank_math/connect/account_connected', 'refresh_content_ai_credits' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dark style
|
||||
*
|
||||
* @param array $styles The dark mode styles.
|
||||
*/
|
||||
public function add_dark_style( $styles = [] ) {
|
||||
|
||||
$styles['rank-math-content-ai-dark'] = rank_math()->plugin_url() . 'includes/modules/content-ai/assets/css/content-ai-dark.css';
|
||||
|
||||
return $styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Content AI score in Single Page Site Analytics.
|
||||
*
|
||||
* @param array $data array.
|
||||
* @param \WP_REST_Request $request post object.
|
||||
* @return array $data sorted array.
|
||||
*/
|
||||
public function add_contentai_data( $data, \WP_REST_Request $request ) {
|
||||
$post_id = $data['object_id'];
|
||||
$content_ai_data = Helper::get_post_meta( 'contentai_score', $post_id );
|
||||
$content_ai_score = ! empty( $content_ai_data ) ? round( array_sum( array_values( $content_ai_data ) ) / count( $content_ai_data ) ) : 0;
|
||||
$data['contentAiScore'] = absint( $content_ai_score );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the REST API endpoints.
|
||||
*/
|
||||
public function init_rest_api() {
|
||||
$rest = new Rest();
|
||||
$rest->register_routes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove credits data when site is disconnected.
|
||||
*/
|
||||
public function remove_credits_data() {
|
||||
delete_option( 'rank_math_ca_credits' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add module settings in the General Settings panel.
|
||||
*
|
||||
* @param array $tabs Array of option panel tabs.
|
||||
* @return array
|
||||
*/
|
||||
public function add_settings( $tabs ) {
|
||||
Arr::insert(
|
||||
$tabs,
|
||||
[
|
||||
'content-ai' => [
|
||||
'icon' => 'rm-icon rm-icon-content-ai',
|
||||
'title' => esc_html__( 'Content AI', 'rank-math' ),
|
||||
/* translators: Link to kb article */
|
||||
'desc' => sprintf( esc_html__( 'Get sophisticated AI suggestions for related Keywords, Questions & Links to include in the SEO meta & Content Area. %s.', 'rank-math' ), '<a href="' . KB::get( 'content-ai-settings', 'Options Panel Content AI Tab' ) . '" target="_blank">' . esc_html__( 'Learn more', 'rank-math' ) . '</a>' ),
|
||||
'file' => dirname( __FILE__ ) . '/views/options.php',
|
||||
],
|
||||
],
|
||||
8
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add link suggestion metabox.
|
||||
*/
|
||||
public function add_content_ai_metabox() {
|
||||
if ( ! self::can_add_tab() || 'classic' !== Helper::get_current_editor() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$id = 'rank_math_metabox_content_ai';
|
||||
$cmb = new_cmb2_box(
|
||||
[
|
||||
'id' => $id,
|
||||
'title' => esc_html__( 'Content AI', 'rank-math' ),
|
||||
'object_types' => array_keys( Helper::get_accessible_post_types() ),
|
||||
'context' => 'side',
|
||||
'priority' => 'high',
|
||||
'mb_callback_args' => [ '__block_editor_compatible_meta_box' => false ],
|
||||
]
|
||||
);
|
||||
|
||||
CMB2::pre_init( $cmb );
|
||||
|
||||
// Move content AI metabox below the Publish box.
|
||||
$this->reorder_content_ai_metabox( $id );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enqueue assets for post/term/user editors.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function editor_scripts() {
|
||||
if ( ! self::can_add_tab() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$editor = Helper::get_current_editor();
|
||||
if ( ! $editor ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_register_style( 'rank-math-common', rank_math()->plugin_url() . 'assets/admin/css/common.css', null, rank_math()->version );
|
||||
wp_enqueue_style(
|
||||
'rank-math-content-ai',
|
||||
rank_math()->plugin_url() . 'includes/modules/content-ai/assets/css/content-ai.css',
|
||||
[ 'rank-math-common' ],
|
||||
rank_math()->version
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'rank-math-content-ai',
|
||||
rank_math()->plugin_url() . 'includes/modules/content-ai/assets/js/content-ai.js',
|
||||
[ 'rank-math-editor' ],
|
||||
rank_math()->version,
|
||||
true
|
||||
);
|
||||
|
||||
wp_set_script_translations( 'rank-math-content-ai', 'rank-math' );
|
||||
|
||||
$this->localized_data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta data to use in gutenberg.
|
||||
*
|
||||
* @param array $values Aray of tabs.
|
||||
* @param Screen $screen Sceen object.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_metadata( $values, $screen ) {
|
||||
$countries = [];
|
||||
foreach ( Helper::choices_contentai_countries() as $value => $label ) {
|
||||
$countries[] = [
|
||||
'value' => $value,
|
||||
'label' => $label,
|
||||
];
|
||||
}
|
||||
|
||||
$values['contentAiCountry'] = Helper::get_settings( 'general.content_ai_country', 'all' );
|
||||
$values['countries'] = $countries;
|
||||
$values['ca_credits'] = Helper::get_credits();
|
||||
$values['ca_keyword'] = '';
|
||||
$values['ca_viewed'] = true;
|
||||
|
||||
$content_ai_viewed = get_option( 'rank_math_content_ai_viewed', false );
|
||||
if ( ! $content_ai_viewed ) {
|
||||
$values['ca_viewed'] = false;
|
||||
update_option( 'rank_math_content_ai_viewed', true );
|
||||
}
|
||||
$keyword = $screen->get_meta( $screen->get_object_type(), $screen->get_object_id(), 'rank_math_ca_keyword' );
|
||||
if ( empty( $keyword ) ) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
$data = get_option( 'rank_math_ca_data' );
|
||||
$country = empty( $keyword['country'] ) ? '' : $keyword['country'];
|
||||
if (
|
||||
! empty( $data[ $country ] ) &&
|
||||
! empty( $data[ $country ][ mb_strtolower( $keyword['keyword'] ) ] )
|
||||
) {
|
||||
$values['ca_data'] = $data[ $country ][ mb_strtolower( $keyword['keyword'] ) ];
|
||||
}
|
||||
|
||||
$values['ca_keyword'] = $keyword;
|
||||
|
||||
$content_ai_data = $screen->get_meta( $screen->get_object_type(), $screen->get_object_id(), 'rank_math_contentai_score' );
|
||||
$content_ai_score = ! empty( $content_ai_data ) && is_array( $content_ai_data ) ? round( array_sum( array_values( $content_ai_data ) ) / count( $content_ai_data ) ) : 0;
|
||||
$values['contentAiScore'] = absint( $content_ai_score );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to load Content AI data.
|
||||
*/
|
||||
public static function can_add_tab() {
|
||||
return in_array( Helper::get_post_type(), (array) Helper::get_settings( 'general.content_ai_post_types' ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Localized data to use on the Content AI page.
|
||||
*/
|
||||
public static function localized_data() {
|
||||
Helper::add_json( 'ca_audience', (array) Helper::get_settings( 'general.content_ai_audience', 'General Audience' ) );
|
||||
Helper::add_json( 'ca_tone', (array) Helper::get_settings( 'general.content_ai_tone', 'Formal' ) );
|
||||
Helper::add_json( 'ca_language', Helper::get_settings( 'general.content_ai_language', Helper::content_ai_default_language() ) );
|
||||
Helper::add_json( 'contentAIHistory', Helper::get_outputs() );
|
||||
Helper::add_json( 'contentAIChats', Helper::get_chats() );
|
||||
Helper::add_json( 'contentAIRecentPrompts', Helper::get_recent_prompts() );
|
||||
Helper::add_json( 'contentAIPrompts', Helper::get_prompts() );
|
||||
Helper::add_json( 'isUserRegistered', Helper::is_site_connected() );
|
||||
Helper::add_json( 'connectSiteUrl', AdminHelper::get_activate_url( Url::get_current_url() ) );
|
||||
Helper::add_json( 'contentAICredits', Helper::get_content_ai_credits() );
|
||||
Helper::add_json( 'contentAIPlan', Helper::get_content_ai_plan() );
|
||||
Helper::add_json( 'contentAIErrors', Helper::get_content_ai_errors() );
|
||||
Helper::add_json( 'connectData', AdminHelper::get_registration_data() );
|
||||
Helper::add_json( 'registerWriteShortcut', version_compare( get_bloginfo( 'version' ), '6.2', '>=' ) );
|
||||
Helper::add_json( 'contentAiMigrating', get_site_transient( 'rank_math_content_ai_migrating_user' ) );
|
||||
Helper::add_json( 'contentAiUrl', CONTENT_AI_URL . '/ai/' );
|
||||
|
||||
$refresh_date = Helper::get_content_ai_refresh_date();
|
||||
Helper::add_json( 'contentAIRefreshDate', $refresh_date ? wp_date( 'Y-m-d g:ia', $refresh_date ) : '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Content AI details in System Info
|
||||
*
|
||||
* @param array $rankmath Array of rankmath.
|
||||
*/
|
||||
public function content_ai_info( $rankmath ) {
|
||||
$refresh_date = Helper::get_content_ai_refresh_date();
|
||||
$content_ai = [
|
||||
'ca_plan' => [
|
||||
'label' => esc_html__( 'Content AI Plan', 'rank-math' ),
|
||||
'value' => \ucwords( Helper::get_content_ai_plan() ),
|
||||
],
|
||||
'ca_credits' => [
|
||||
'label' => esc_html__( 'Content AI Credits', 'rank-math' ),
|
||||
'value' => Helper::get_content_ai_credits(),
|
||||
],
|
||||
'ca_refresh_date' => [
|
||||
'label' => esc_html__( 'Content AI Refresh Date', 'rank-math' ),
|
||||
'value' => $refresh_date ? wp_date( 'Y-m-d g:i a', $refresh_date ) : '',
|
||||
],
|
||||
];
|
||||
|
||||
array_splice( $rankmath['fields'], 3, 0, $content_ai );
|
||||
|
||||
return $rankmath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh Content AI credits when account is connected.
|
||||
*
|
||||
* @param array $data Authentication data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function refresh_content_ai_credits( $data ) {
|
||||
Helper::get_content_ai_credits( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the Content AI metabox in Classic editor.
|
||||
*
|
||||
* @param string $id Metabox ID.
|
||||
* @return void
|
||||
*/
|
||||
private function reorder_content_ai_metabox( $id ) {
|
||||
$post_type = Helper::get_post_type();
|
||||
if ( ! $post_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = wp_get_current_user();
|
||||
$order = (array) get_user_option( 'meta-box-order_' . $post_type, $user->ID );
|
||||
if ( ! empty( $order['normal'] ) && false !== strpos( $order['normal'], $id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order['side'] = ! isset( $order['side'] ) ? '' : $order['side'];
|
||||
if ( false !== strpos( $order['side'], $id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( false === strpos( $order['side'], 'submitdiv' ) ) {
|
||||
$order['side'] = 'submitdiv,' . $order['side'];
|
||||
}
|
||||
|
||||
if ( ',' === substr( $order['side'], -1 ) ) {
|
||||
$order['side'] = substr( $order['side'], 0, -1 );
|
||||
}
|
||||
|
||||
$current_order = [];
|
||||
$current_order = explode( ',', $order['side'] );
|
||||
|
||||
$key = array_search( 'submitdiv', $current_order, true );
|
||||
if ( false === $key ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$new_order = array_merge(
|
||||
array_slice( $current_order, 0, $key + 1 ),
|
||||
[ $id ]
|
||||
);
|
||||
|
||||
if ( count( $current_order ) > $key ) {
|
||||
$new_order = array_merge(
|
||||
$new_order,
|
||||
array_slice( $current_order, $key + 1 )
|
||||
);
|
||||
}
|
||||
|
||||
$order['side'] = implode( ',', array_unique( $new_order ) );
|
||||
update_user_option( $user->ID, 'meta-box-order_' . $post_type, $order, true );
|
||||
}
|
||||
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* The Event Scheduler for Content AI to update the prompts and credits data.
|
||||
*
|
||||
* @since 1.0.123
|
||||
* @package RankMath
|
||||
* @subpackage RankMath\ContentAI
|
||||
* @author Rank Math <support@rankmath.com>
|
||||
*/
|
||||
|
||||
namespace RankMath\ContentAI;
|
||||
|
||||
use WP_Block_Type_Registry;
|
||||
use RankMath\Helper;
|
||||
use RankMath\Admin\Admin_Helper;
|
||||
use RankMath\Traits\Hooker;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Event_Scheduler class.
|
||||
*/
|
||||
class Event_Scheduler {
|
||||
|
||||
use Hooker;
|
||||
|
||||
/**
|
||||
* The single instance of the class.
|
||||
*
|
||||
* @var Event_Scheduler
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Retrieve main Block_Command instance.
|
||||
*
|
||||
* Ensure only one instance is loaded or can be loaded.
|
||||
*
|
||||
* @return Event_Scheduler
|
||||
*/
|
||||
public static function get() {
|
||||
if ( is_null( self::$instance ) && ! ( self::$instance instanceof Event_Scheduler ) ) {
|
||||
self::$instance = new Event_Scheduler();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( ! Helper::is_site_connected() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$credits = get_option( 'rank_math_ca_credits' );
|
||||
if ( ! empty( $credits['refresh_date'] ) ) {
|
||||
wp_schedule_single_event( absint( $credits['refresh_date'] ) + 60, 'rank_math/content-ai/update_plan' );
|
||||
}
|
||||
|
||||
$this->action( 'rank_math/content-ai/update_prompts', 'update_prompts_data' );
|
||||
$this->action( 'rank_math/content-ai/update_plan', 'update_content_ai_plan' );
|
||||
$this->action( 'admin_footer', 'update_prompts_on_new_site' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and update the prompts data daily.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update_prompts_data() {
|
||||
if ( ! Helper::get_credits() || ! Helper::get_content_ai_plan() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$prompt_data = [];
|
||||
$data = wp_remote_get( CONTENT_AI_URL . '/ai/default_prompts' );
|
||||
$response_code = wp_remote_retrieve_response_code( $data );
|
||||
if ( is_wp_error( $data ) || 200 !== $response_code ) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_option( 'rank_math_prompts_updated', true );
|
||||
$data = wp_remote_retrieve_body( $data );
|
||||
$data = json_decode( $data, true );
|
||||
if ( empty( $data ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Helper::save_default_prompts( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the credits endpoint to update the plan on reset date.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update_content_ai_plan() {
|
||||
Helper::get_content_ai_credits( true );
|
||||
wp_clear_scheduled_hook( 'rank_math/content-ai/update_plan' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to update Prompts data on new sites.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update_prompts_on_new_site() {
|
||||
$prompts = Helper::get_prompts();
|
||||
if ( get_option( 'rank_math_prompts_updated' ) || ! empty( $prompts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_action( 'rank_math/content-ai/update_prompts' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,545 @@
|
||||
<?php
|
||||
/**
|
||||
* The Global functionality of the plugin.
|
||||
*
|
||||
* Defines the functionality loaded on admin.
|
||||
*
|
||||
* @since 1.0.71
|
||||
* @package RankMath
|
||||
* @subpackage RankMath\Rest
|
||||
* @author Rank Math <support@rankmath.com>
|
||||
*/
|
||||
|
||||
namespace RankMath\ContentAI;
|
||||
|
||||
use WP_Error;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Controller;
|
||||
use RankMath\Helper;
|
||||
use RankMath\Admin\Admin_Helper;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rest class.
|
||||
*/
|
||||
class Rest extends WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* Registered data.
|
||||
*
|
||||
* @var array|false
|
||||
*/
|
||||
private $registered;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->namespace = \RankMath\Rest\Rest_Helper::BASE . '/ca';
|
||||
$this->registered = Admin_Helper::get_registration_data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the routes for the objects of the controller.
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/researchKeyword',
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'research_keyword' ],
|
||||
'permission_callback' => [ $this, 'has_permission' ],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/getCredits',
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'get_credits' ],
|
||||
'permission_callback' => [ $this, 'has_permission' ],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/createPost',
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'create_post' ],
|
||||
'permission_callback' => [ $this, 'has_permission' ],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/saveOutput',
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'save_output' ],
|
||||
'permission_callback' => [ $this, 'has_permission' ],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/deleteOutput',
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'delete_output' ],
|
||||
'permission_callback' => [ $this, 'has_permission' ],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/updateRecentPrompt',
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'update_recent_prompt' ],
|
||||
'permission_callback' => [ $this, 'has_permission' ],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/updatePrompt',
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'update_prompt' ],
|
||||
'permission_callback' => [ $this, 'has_permission' ],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/savePrompts',
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [ $this, 'save_prompts' ],
|
||||
'permission_callback' => [ $this, 'has_permission' ],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/pingContentAI',
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'ping_content_ai' ],
|
||||
'permission_callback' => [ $this, 'has_ping_permission' ],
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/migrateuser',
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [ $this, 'migrate_user' ],
|
||||
'permission_callback' => [ $this, 'has_permission' ],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check API key in request.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return bool Whether the API key matches or not.
|
||||
*/
|
||||
public function has_ping_permission( WP_REST_Request $request ) {
|
||||
if ( empty( $this->registered ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $request->get_param( 'apiKey' ) === $this->registered['api_key'] &&
|
||||
$request->get_param( 'username' ) === $this->registered['username'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current user can manage analytics.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public function has_permission() {
|
||||
if ( ! Helper::has_cap( 'content_ai' ) || empty( $this->registered ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_access',
|
||||
__( 'Sorry, only authenticated users can research the keyword.', 'rank-math' ),
|
||||
[ 'status' => rest_authorization_required_code() ]
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Content AI Credits.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return int Credits.
|
||||
*/
|
||||
public function get_credits( WP_REST_Request $request ) {
|
||||
$credits = Helper::get_content_ai_credits( true, true );
|
||||
if ( ! empty( $credits['error'] ) ) {
|
||||
$error = $credits['error'];
|
||||
$error_texts = Helper::get_content_ai_errors();
|
||||
return [
|
||||
'error' => ! empty( $error_texts[ $error ] ) ? wp_specialchars_decode( $error_texts[ $error ], ENT_QUOTES ) : $error,
|
||||
'credits' => isset( $credits['credits'] ) ? $credits['credits'] : '',
|
||||
];
|
||||
}
|
||||
|
||||
return $credits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Research a keyword.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function research_keyword( WP_REST_Request $request ) {
|
||||
$object_id = $request->get_param( 'objectID' );
|
||||
$country = $request->get_param( 'country' );
|
||||
$keyword = mb_strtolower( $request->get_param( 'keyword' ) );
|
||||
$force_update = $request->get_param( 'force_update' );
|
||||
$keyword_data = get_option( 'rank_math_ca_data' );
|
||||
|
||||
if ( ! in_array( get_post_type( $object_id ), (array) Helper::get_settings( 'general.content_ai_post_types' ), true ) ) {
|
||||
return [
|
||||
'data' => esc_html__( 'Content AI is not enabled on this Post type.', 'rank-math' ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( ! apply_filters( 'rank_math/content_ai/call_api', true ) ) {
|
||||
return [
|
||||
'data' => 'show_dummy_data',
|
||||
];
|
||||
}
|
||||
|
||||
if (
|
||||
! $force_update &&
|
||||
! empty( $keyword_data ) &&
|
||||
! empty( $keyword_data[ $country ] ) &&
|
||||
! empty( $keyword_data[ $country ][ $keyword ] )
|
||||
) {
|
||||
update_post_meta(
|
||||
$object_id,
|
||||
'rank_math_ca_keyword',
|
||||
[
|
||||
'keyword' => $keyword,
|
||||
'country' => $country,
|
||||
]
|
||||
);
|
||||
|
||||
return [
|
||||
'data' => $keyword_data[ $country ][ $keyword ],
|
||||
'keyword' => $keyword,
|
||||
];
|
||||
}
|
||||
|
||||
$data = $this->get_researched_data( $keyword, $country, $force_update );
|
||||
if ( ! empty( $data['error'] ) ) {
|
||||
return $this->get_errored_data( $data['error'] );
|
||||
}
|
||||
|
||||
$credits = ! empty( $data['credits'] ) ? $data['credits'] : 0;
|
||||
if ( ! empty( $credits ) ) {
|
||||
$credits = $credits['available'] - $credits['taken'];
|
||||
}
|
||||
|
||||
$data = $data['data']['details'];
|
||||
$this->get_recommendations( $data );
|
||||
|
||||
update_post_meta(
|
||||
$object_id,
|
||||
'rank_math_ca_keyword',
|
||||
[
|
||||
'keyword' => $keyword,
|
||||
'country' => $country,
|
||||
]
|
||||
);
|
||||
$keyword_data[ $country ][ $keyword ] = $data;
|
||||
update_option( 'rank_math_ca_data', $keyword_data, false );
|
||||
Helper::update_credits( $credits );
|
||||
|
||||
return [
|
||||
'data' => $keyword_data[ $country ][ $keyword ],
|
||||
'credits' => $credits,
|
||||
'keyword' => $keyword,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Post from Content AI Page.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function create_post( WP_REST_Request $request ) {
|
||||
$content = $request->get_param( 'content' );
|
||||
$title = 'Content AI Post';
|
||||
$blocks = parse_blocks( $content );
|
||||
$current_block = ! empty( $blocks ) ? current( $blocks ) : '';
|
||||
if (
|
||||
! empty( $current_block ) &&
|
||||
$current_block['blockName'] === 'core/heading' &&
|
||||
$current_block['attrs']['level'] === 1
|
||||
) {
|
||||
$title = wp_strip_all_tags( $current_block['innerHTML'] );
|
||||
}
|
||||
|
||||
$post_id = wp_insert_post(
|
||||
[
|
||||
'post_title' => $title,
|
||||
'post_content' => $content,
|
||||
]
|
||||
);
|
||||
|
||||
return wp_specialchars_decode( add_query_arg( 'tab', 'content-ai', get_edit_post_link( $post_id ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the API output.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function save_output( WP_REST_Request $request ) {
|
||||
$outputs = $request->get_param( 'outputs' );
|
||||
$endpoint = $request->get_param( 'endpoint' );
|
||||
$is_chat = $request->get_param( 'isChat' );
|
||||
$attributes = $request->get_param( 'attributes' );
|
||||
$credits_data = $request->get_param( 'credits' );
|
||||
|
||||
if ( ! empty( $credits_data ) ) {
|
||||
$credits = ! empty( $credits_data['credits'] ) ? $credits_data['credits'] : [];
|
||||
$data = [
|
||||
'credits' => ! empty( $credits['available'] ) ? $credits['available'] - $credits['taken'] : 0,
|
||||
'plan' => ! empty( $credits_data['plan'] ) ? $credits_data['plan'] : '',
|
||||
'refresh_date' => ! empty( $credits_data['refreshDate'] ) ? $credits_data['refreshDate'] : '',
|
||||
];
|
||||
|
||||
Helper::update_credits( $data );
|
||||
}
|
||||
|
||||
if ( $is_chat ) {
|
||||
Helper::update_chats( current( $outputs ), end( $attributes['messages'] ), $attributes['session'], $attributes['isNew'], $attributes['regenerate'] );
|
||||
return true;
|
||||
}
|
||||
|
||||
return Helper::update_outputs( $endpoint, $outputs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the API output.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function delete_output( WP_REST_Request $request ) {
|
||||
$is_chat = $request->get_param( 'isChat' );
|
||||
if ( $is_chat ) {
|
||||
return Helper::delete_chats( $request->get_param( 'index' ) );
|
||||
}
|
||||
|
||||
return Helper::delete_outputs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the Prompts.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function update_prompt( WP_REST_Request $request ) {
|
||||
$prompt = $request->get_param( 'prompt' );
|
||||
|
||||
if ( is_string( $prompt ) ) {
|
||||
return Helper::delete_prompt( $prompt );
|
||||
}
|
||||
|
||||
return Helper::update_prompts( $prompt );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the Prompts.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function save_prompts( WP_REST_Request $request ) {
|
||||
$prompts = $request->get_param( 'prompts' );
|
||||
if ( empty( $prompts ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Helper::save_default_prompts( $prompts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the Recent Prompts.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function update_recent_prompt( WP_REST_Request $request ) {
|
||||
$prompt = $request->get_param( 'prompt' );
|
||||
return Helper::update_recent_prompts( $prompt );
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoing to update the AI plan and credits.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function ping_content_ai( WP_REST_Request $request ) {
|
||||
$credits = ! empty( $data['credits'] ) ? json_decode( $data['credits'], true ) : [];
|
||||
$data = [
|
||||
'credits' => ! empty( $credits['available'] ) ? $credits['available'] - $credits['taken'] : 0,
|
||||
'plan' => $request->get_param( 'plan' ),
|
||||
'refresh_date' => $request->get_param( 'refreshDate' ),
|
||||
];
|
||||
|
||||
Helper::update_credits( $data );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate user to nest js server.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function migrate_user( WP_REST_Request $request ) {
|
||||
return Helper::migrate_user_to_nest_js();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data from the API.
|
||||
*
|
||||
* @param string $keyword Researched keyword.
|
||||
* @param string $country Researched country.
|
||||
* @param bool $force_update Whether to force update the researched data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_researched_data( $keyword, $country, $force_update = false ) {
|
||||
$args = [
|
||||
'username' => rawurlencode( $this->registered['username'] ),
|
||||
'api_key' => rawurlencode( $this->registered['api_key'] ),
|
||||
'keyword' => rawurlencode( $keyword ),
|
||||
'site_url' => rawurlencode( Helper::get_home_url() ),
|
||||
'new_api' => 1,
|
||||
];
|
||||
|
||||
if ( 'all' !== $country ) {
|
||||
$args['locale'] = rawurlencode( $country );
|
||||
}
|
||||
|
||||
if ( $force_update ) {
|
||||
$args['force_refresh'] = 1;
|
||||
}
|
||||
|
||||
$url = add_query_arg(
|
||||
$args,
|
||||
CONTENT_AI_URL . '/ai/research'
|
||||
);
|
||||
|
||||
$data = wp_remote_get(
|
||||
$url,
|
||||
[
|
||||
'timeout' => 60,
|
||||
]
|
||||
);
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $data );
|
||||
if ( 200 !== $response_code ) {
|
||||
return [
|
||||
'error' => 410 !== $response_code ? $data['response']['message'] : wp_kses_post(
|
||||
sprintf(
|
||||
// Translators: link to the update page.
|
||||
__( 'There is a new version of Content AI available! %s the Rank Math SEO plugin to use this feature.', 'rank-math' ),
|
||||
'<a href="' . esc_url( self_admin_url( 'update-core.php' ) ) . '">' . __( 'Please update', 'rank-math' ) . '</a>'
|
||||
)
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
$data = wp_remote_retrieve_body( $data );
|
||||
$data = json_decode( $data, true );
|
||||
|
||||
if ( empty( $data['error'] ) && empty( $data['data']['details'] ) ) {
|
||||
return [
|
||||
'error' => esc_html__( 'No data found for the researched keyword.', 'rank-math' ),
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get errored data.
|
||||
*
|
||||
* @param array $error Error data received from the API.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_errored_data( $error ) {
|
||||
if ( empty( $error['code'] ) ) {
|
||||
return [
|
||||
'data' => $error,
|
||||
];
|
||||
}
|
||||
|
||||
if ( 'invalid_domain' === $error['code'] ) {
|
||||
return [
|
||||
'data' => esc_html__( 'This feature is not available on the localhost.', 'rank-math' ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( 'domain_limit_reached' === $error['code'] ) {
|
||||
return [
|
||||
'data' => esc_html__( 'You have used all the free credits which are allowed to this domain.', 'rank-math' ),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => '',
|
||||
'credits' => $error['code'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Recommendations data.
|
||||
*
|
||||
* @param array $data Researched data.
|
||||
*/
|
||||
private function get_recommendations( &$data ) {
|
||||
foreach ( $data['recommendations'] as $key => $value ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data['recommendations'][ $key ]['total'] = array_sum( $value );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* Content AI Page main view.
|
||||
*
|
||||
* @package RankMath
|
||||
* @subpackage RankMath\Role_Manager
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
// Header.
|
||||
rank_math()->admin->display_admin_header();
|
||||
?>
|
||||
<div class="wrap rank-math-wrap" id="rank-math-content-ai-page">
|
||||
<div class="rank-math-box container">
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
/**
|
||||
* Content AI general settings.
|
||||
*
|
||||
* @package RankMath
|
||||
* @subpackage RankMath\ContentAI
|
||||
*/
|
||||
|
||||
use RankMath\Helper;
|
||||
use RankMath\KB;
|
||||
use RankMath\Admin\Admin_Helper;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
if ( ! Helper::is_site_connected() ) {
|
||||
$cmb->add_field(
|
||||
[
|
||||
'id' => 'rank_math_content_ai_settings',
|
||||
'type' => 'raw',
|
||||
'content' => '<div id="setting-panel-content-ai" class="rank-math-tab rank-math-options-panel-content exclude">
|
||||
<div class="wp-core-ui rank-math-ui connect-wrap">
|
||||
<a href="' . Admin_Helper::get_activate_url( admin_url( 'admin.php??page=rank-math-options-general#setting-panel-content-ai' ) ) . '" class="button button-primary button-connect button-animated" name="rank_math_activate">'
|
||||
. esc_html__( 'Connect Your Rank Math Account', 'rank-math' )
|
||||
. '</a>
|
||||
</div>
|
||||
<div id="rank-math-pro-cta" class="content-ai-settings">
|
||||
<div class="rank-math-cta-box width-100 no-shadow no-padding no-border">
|
||||
<h3>' . esc_html__( 'Benefits of Connecting Rank Math Account', 'rank-math' ) . '</h3>
|
||||
<ul>
|
||||
<li>' . esc_html__( 'Gain Access to 40+ Advanced AI Tools.', 'rank-math' ) . '</li>
|
||||
<li>' . esc_html__( 'Experience the Revolutionary AI-Powered Content Editor.', 'rank-math' ) . '</li>
|
||||
<li>' . esc_html__( 'Engage with RankBot, Our AI Chatbot, For SEO Advice.', 'rank-math' ) . '</li>
|
||||
<li>' . esc_html__( 'Escape the Writer\'s Block Using AI to Write Inside WordPress.', 'rank-math' ) . '</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>',
|
||||
]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$cmb->add_field(
|
||||
[
|
||||
'id' => 'content_ai_country',
|
||||
'type' => 'select',
|
||||
'name' => esc_html__( 'Default Country', 'rank-math' ),
|
||||
'desc' => esc_html__( 'Content AI tailors keyword research to the target country for highly relevant suggestions. You can override this in individual posts/pages/CPTs.', 'rank-math' ),
|
||||
'options' => Helper::choices_contentai_countries(),
|
||||
'default' => 'all',
|
||||
]
|
||||
);
|
||||
|
||||
$cmb->add_field(
|
||||
[
|
||||
'id' => 'content_ai_tone',
|
||||
'type' => 'select',
|
||||
'name' => esc_html__( 'Default Tone', 'rank-math' ),
|
||||
'desc' => esc_html__( 'This feature enables the default primary tone or writing style that characterizes your content. You can override this in individual tools.', 'rank-math' ),
|
||||
'default' => 'Formal',
|
||||
'attributes' => ( 'data-s2' ),
|
||||
'options' => [
|
||||
'Analytical' => esc_html__( 'Analytical', 'rank-math' ),
|
||||
'Argumentative' => esc_html__( 'Argumentative', 'rank-math' ),
|
||||
'Casual' => esc_html__( 'Casual', 'rank-math' ),
|
||||
'Conversational' => esc_html__( 'Conversational', 'rank-math' ),
|
||||
'Creative' => esc_html__( 'Creative', 'rank-math' ),
|
||||
'Descriptive' => esc_html__( 'Descriptive', 'rank-math' ),
|
||||
'Emotional' => esc_html__( 'Emotional', 'rank-math' ),
|
||||
'Empathetic' => esc_html__( 'Empathetic', 'rank-math' ),
|
||||
'Expository' => esc_html__( 'Expository', 'rank-math' ),
|
||||
'Factual' => esc_html__( 'Factual', 'rank-math' ),
|
||||
'Formal' => esc_html__( 'Formal', 'rank-math' ),
|
||||
'Friendly' => esc_html__( 'Friendly', 'rank-math' ),
|
||||
'Humorous' => esc_html__( 'Humorous', 'rank-math' ),
|
||||
'Informal' => esc_html__( 'Informal', 'rank-math' ),
|
||||
'Journalese' => esc_html__( 'Journalese', 'rank-math' ),
|
||||
'Narrative' => esc_html__( 'Narrative', 'rank-math' ),
|
||||
'Objective' => esc_html__( 'Objective', 'rank-math' ),
|
||||
'Opinionated' => esc_html__( 'Opinionated', 'rank-math' ),
|
||||
'Persuasive' => esc_html__( 'Persuasive', 'rank-math' ),
|
||||
'Poetic' => esc_html__( 'Poetic', 'rank-math' ),
|
||||
'Satirical' => esc_html__( 'Satirical', 'rank-math' ),
|
||||
'Story-telling' => esc_html__( 'Story-telling', 'rank-math' ),
|
||||
'Subjective' => esc_html__( 'Subjective', 'rank-math' ),
|
||||
'Technical' => esc_html__( 'Technical', 'rank-math' ),
|
||||
],
|
||||
],
|
||||
);
|
||||
|
||||
$cmb->add_field(
|
||||
[
|
||||
'id' => 'content_ai_audience',
|
||||
'type' => 'select',
|
||||
'name' => esc_html__( 'Default Audience', 'rank-math' ),
|
||||
'desc' => esc_html__( 'This option lets you set the default audience that usually reads your content. You can override this in individual tools.', 'rank-math' ),
|
||||
'default' => 'General Audience',
|
||||
'attributes' => ( 'data-s2' ),
|
||||
'options' => [
|
||||
'Activists' => esc_html__( 'Activists', 'rank-math' ),
|
||||
'Artists' => esc_html__( 'Artists', 'rank-math' ),
|
||||
'Authors' => esc_html__( 'Authors', 'rank-math' ),
|
||||
'Bargain Hunters' => esc_html__( 'Bargain Hunters', 'rank-math' ),
|
||||
'Bloggers' => esc_html__( 'Bloggers', 'rank-math' ),
|
||||
'Business Owners' => esc_html__( 'Business Owners', 'rank-math' ),
|
||||
'Collectors' => esc_html__( 'Collectors', 'rank-math' ),
|
||||
'Cooks' => esc_html__( 'Cooks', 'rank-math' ),
|
||||
'Crafters' => esc_html__( 'Crafters', 'rank-math' ),
|
||||
'Dancers' => esc_html__( 'Dancers', 'rank-math' ),
|
||||
'DIYers' => esc_html__( 'DIYers', 'rank-math' ),
|
||||
'Designers' => esc_html__( 'Designers', 'rank-math' ),
|
||||
'Educators' => esc_html__( 'Educators', 'rank-math' ),
|
||||
'Engineers' => esc_html__( 'Engineers', 'rank-math' ),
|
||||
'Entrepreneurs' => esc_html__( 'Entrepreneurs', 'rank-math' ),
|
||||
'Environmentalists' => esc_html__( 'Environmentalists', 'rank-math' ),
|
||||
'Fashionistas' => esc_html__( 'Fashionistas', 'rank-math' ),
|
||||
'Fitness Enthusiasts' => esc_html__( 'Fitness Enthusiasts', 'rank-math' ),
|
||||
'Foodies' => esc_html__( 'Foodies', 'rank-math' ),
|
||||
'Gaming Enthusiasts' => esc_html__( 'Gaming Enthusiasts', 'rank-math' ),
|
||||
'Gardeners' => esc_html__( 'Gardeners', 'rank-math' ),
|
||||
'General Audience' => esc_html__( 'General Audience', 'rank-math' ),
|
||||
'Health Enthusiasts' => esc_html__( 'Health Enthusiasts', 'rank-math' ),
|
||||
'Healthcare Professionals' => esc_html__( 'Healthcare Professionals', 'rank-math' ),
|
||||
'Indoor Hobbyists' => esc_html__( 'Indoor Hobbyists', 'rank-math' ),
|
||||
'Investors' => esc_html__( 'Investors', 'rank-math' ),
|
||||
'Job Seekers' => esc_html__( 'Job Seekers', 'rank-math' ),
|
||||
'Movie Buffs' => esc_html__( 'Movie Buffs', 'rank-math' ),
|
||||
'Musicians' => esc_html__( 'Musicians', 'rank-math' ),
|
||||
'Outdoor Enthusiasts' => esc_html__( 'Outdoor Enthusiasts', 'rank-math' ),
|
||||
'Parents' => esc_html__( 'Parents', 'rank-math' ),
|
||||
'Pet Owners' => esc_html__( 'Pet Owners', 'rank-math' ),
|
||||
'Photographers' => esc_html__( 'Photographers', 'rank-math' ),
|
||||
'Podcast Listeners' => esc_html__( 'Podcast Listeners', 'rank-math' ),
|
||||
'Professionals' => esc_html__( 'Professionals', 'rank-math' ),
|
||||
'Retirees' => esc_html__( 'Retirees', 'rank-math' ),
|
||||
'Russian' => esc_html__( 'Russian', 'rank-math' ),
|
||||
'Seniors' => esc_html__( 'Seniors', 'rank-math' ),
|
||||
'Social Media Users' => esc_html__( 'Social Media Users', 'rank-math' ),
|
||||
'Sports Fans' => esc_html__( 'Sports Fans', 'rank-math' ),
|
||||
'Students' => esc_html__( 'Students', 'rank-math' ),
|
||||
'Tech Enthusiasts' => esc_html__( 'Tech Enthusiasts', 'rank-math' ),
|
||||
'Travelers' => esc_html__( 'Travelers', 'rank-math' ),
|
||||
'TV Enthusiasts' => esc_html__( 'TV Enthusiasts', 'rank-math' ),
|
||||
'Video Creators' => esc_html__( 'Video Creators', 'rank-math' ),
|
||||
'Writers' => esc_html__( 'Writers', 'rank-math' ),
|
||||
],
|
||||
],
|
||||
);
|
||||
|
||||
$cmb->add_field(
|
||||
[
|
||||
'id' => 'content_ai_language',
|
||||
'type' => 'select',
|
||||
'name' => esc_html__( 'Default Language', 'rank-math' ),
|
||||
'desc' => esc_html__( 'This option lets you set the default language for content generated using Content AI. You can override this in individual tools.', 'rank-math' ),
|
||||
'default' => Helper::content_ai_default_language(),
|
||||
'attributes' => ( 'data-s2' ),
|
||||
'options' => [
|
||||
'US English' => esc_html__( 'US English', 'rank-math' ),
|
||||
'UK English' => esc_html__( 'UK English', 'rank-math' ),
|
||||
'Bulgarian' => esc_html__( 'Bulgarian', 'rank-math' ),
|
||||
'Chinese' => esc_html__( 'Chinese', 'rank-math' ),
|
||||
'Czech' => esc_html__( 'Czech', 'rank-math' ),
|
||||
'Danish' => esc_html__( 'Danish', 'rank-math' ),
|
||||
'Dutch' => esc_html__( 'Dutch', 'rank-math' ),
|
||||
'Estonian' => esc_html__( 'Estonian', 'rank-math' ),
|
||||
'Finnish' => esc_html__( 'Finnish', 'rank-math' ),
|
||||
'French' => esc_html__( 'French', 'rank-math' ),
|
||||
'German' => esc_html__( 'German', 'rank-math' ),
|
||||
'Greek' => esc_html__( 'Greek', 'rank-math' ),
|
||||
'Hebrew' => esc_html__( 'Hebrew', 'rank-math' ),
|
||||
'Hungarian' => esc_html__( 'Hungarian', 'rank-math' ),
|
||||
'Indonesian' => esc_html__( 'Indonesian', 'rank-math' ),
|
||||
'Italian' => esc_html__( 'Italian', 'rank-math' ),
|
||||
'Japanese' => esc_html__( 'Japanese', 'rank-math' ),
|
||||
'Korean' => esc_html__( 'Korean', 'rank-math' ),
|
||||
'Latvian' => esc_html__( 'Latvian', 'rank-math' ),
|
||||
'Lithuanian' => esc_html__( 'Lithuanian', 'rank-math' ),
|
||||
'Norwegian' => esc_html__( 'Norwegian', 'rank-math' ),
|
||||
'Polish' => esc_html__( 'Polish', 'rank-math' ),
|
||||
'Portuguese' => esc_html__( 'Portuguese', 'rank-math' ),
|
||||
'Romanian' => esc_html__( 'Romanian', 'rank-math' ),
|
||||
'Russian' => esc_html__( 'Russian', 'rank-math' ),
|
||||
'Slovak' => esc_html__( 'Slovak', 'rank-math' ),
|
||||
'Slovenian' => esc_html__( 'Slovenian', 'rank-math' ),
|
||||
'Spanish' => esc_html__( 'Spanish', 'rank-math' ),
|
||||
'Swedish' => esc_html__( 'Swedish', 'rank-math' ),
|
||||
],
|
||||
],
|
||||
);
|
||||
|
||||
$post_types = Helper::choices_post_types();
|
||||
if ( isset( $post_types['attachment'] ) ) {
|
||||
unset( $post_types['attachment'] );
|
||||
}
|
||||
|
||||
$cmb->add_field(
|
||||
[
|
||||
'id' => 'content_ai_post_types',
|
||||
'type' => 'multicheck_inline',
|
||||
'name' => esc_html__( 'Select Post Type', 'rank-math' ),
|
||||
'desc' => esc_html__( 'Choose the type of posts/pages/CPTs where you want to use Content AI.', 'rank-math' ),
|
||||
'options' => $post_types,
|
||||
'default' => array_keys( $post_types ),
|
||||
]
|
||||
);
|
||||
|
||||
$credits = Helper::get_credits();
|
||||
if ( Helper::is_site_connected() && false !== $credits ) {
|
||||
$update_credits = '<a href="#" class="rank-math-tooltip update-credit">
|
||||
<i class="dashicons dashicons-image-rotate"></i>
|
||||
<span>' . esc_html__( 'Click to refresh the available credits.', 'rank-math' ) . '</span>
|
||||
</a>';
|
||||
|
||||
$refresh_date = Helper::get_content_ai_refresh_date();
|
||||
$cmb->add_field(
|
||||
[
|
||||
'id' => 'content_ai_credits',
|
||||
'type' => 'raw',
|
||||
/* translators: 1. Credits left 2. Buy more credits link */
|
||||
'content' => '<div class="cmb-row buy-more-credits rank-math-exclude-from-search">' . $update_credits . sprintf( esc_html__( '%1$s credits left this month. Credits will renew on %2$s or you can upgrade to get more credits %3$s.', 'rank-math' ), '<strong>' . $credits . '</strong>', wp_date( 'Y-m-d g:i a', $refresh_date ), '<a href="' . KB::get( 'content-ai-pricing-tables', 'Buy CAI Credits Options Panel' ) . '" target="_blank">' . esc_html__( 'here', 'rank-math' ) . '</a>' ) . '</div>',
|
||||
]
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user