Você está disposto a criar plugins para OKLAC Fifty Custom - Future CRM e vendê-los no CodeCanyon ou criar seus próprios recursos com base em sua necessidade? Este guia irá mostrar-lhe a maneira de fazer isso.
OKLAC Fifty Custom - Future 2.8 vem com um recurso embutido para criar plugins e integrar recursos adicionais junto com as funcionalidades principais.
Plugins são pacotes de código que suportam uma forma de modularização de código para ajudá-lo a criar código reutilizável. O que estende a funcionalidade principal do aplicativo principal.
Os plugins podem consistir em ganchos de ação, filtros, controladores, modelos, bibliotecas, linguagens, visualizações, arquivos de configuração, auxiliares e também podem acessar o código base do OKLAC Fifty Custom - Future CRM.
<?php
//Evita acesso direto
definido('PLUGINPATH') ou exit('Nenhum acesso direto ao script permitido');
/*
Nome do plug-in: Seu nome de plug-in
URL do plug-in: https://codecanyon.net/item/your_item
Descrição: a descrição do seu plug-in
Versão: 1.0
Requer pelo menos: 2,8
Autor: nome do autor
URL do autor: https://codecanyon.net/user/author_url
*/
Nota: Os metadados são necessários para adicionar apenas no arquivo index.php.
Visite a documentação oficial do CodeIgniter para obter informações avançadas.
<?php
configuração de namespace;
$rotas = Serviços::rotas();
$routes->get('my_plugin', 'My_Plugin::index', ['namespace' => 'My_Plugin\Controllers']);
$routes->get('my_plugin/(:any)', 'My_Plugin::$1', ['namespace' => 'My_Plugin\Controllers']);
$routes->post('my_plugin/(:any)', 'My_Plugin::$1', ['namespace' => 'My_Plugin\Controllers']); //será necessário se algum dado precisar ser postado
<?php
namespace My_Plugin\Controllers;
use App\Controllers\Security_Controller; // acessa o controller do app principal
class My_Plugin estende Security_Controller {
//seus métodos
}
<?php
namespace My_Plugin\Controllers;
use App\Models\Crud_model; //acessar os modelos do aplicativo principal
class My_Plugin_Model estende Crud_model {
//seus métodos
}
Chamando seus modelos:
$My_Plugin_Model = new \My_Plugin\Models\My_Plugin_Model();
<?php
namespace Meu_Plugin\Bibliotecas;
class My_Plugin_Library {
//seus métodos
}
Chamando sua biblioteca:
$my_plugin_library = new \My_Plugin\Libraries\My_Plugin_Library();
<?php
$lang["my_plugin_show_staff_members"] = "Mostrar membros da equipe";
Em seguida, você pode usar o OKLAC Fifty Custom - Future's app_lang("my_plugin_show_staff_members");para recuperar o valor do idioma. Adicione todos os diretórios de idiomas como no aplicativo principal se desejar oferecer suporte a todos os idiomas do seu plug-in.
$view_data['foo'] = "bar";
//$this->template->rander() a função mostrará a visualização com o menu esquerdo e a barra superior por padrão.
return $this->template->rander('Meu_Plugin\Views\folder\index', $view_data);
//$this->template->view() função mostrará apenas a visualização, mas aqui você obterá as informações do usuário de login como a variável $login_user se existir algum usuário de login
return $this->template->view('My_Plugin\Views\folder\index', $view_data);
//função de visualização padrão() do CI
return view('Meu_Plugin\Views\folder\index', $view_data);
helper("meu_plugin_general_helper");
require_once(PLUGINPATH . "My_Plugin/ThirdParty/library_folder/vendor/autoload.php");
<link rel='stylesheet' type='text/css' href='" . base_url(PLUGIN_URL_PATH . "My_Plugin/assets/css/my_plugin_styles.css") . "' />
PLUGIN_URL_PATH. "My_Plugin/files/my_plugin_files/"
Chame essas funções em sua pasta/arquivo index.php My_Plugin.
register_installation_hook("Meu_Plugin", function ($item_purchase_code) {
//valida o código de compra se desejar
if (!validate_purchase_code($item_purchase_code)) {
echo json_encode(array("sucesso" => false, 'message' => "Código de compra inválido"));
saída();
}
//executa as consultas sql necessárias
$db = db_connect('default');
$db_prefix = get_db_prefix();
$db->query("SET sql_mode = ''");
$db->query("CREATE TABLE SE NÃO EXISTE `" . $db_prefix . "plugin_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL ,
`deleted` tinyint(1) NOT NULL DEFAULT '0',
CHAVE PRIMÁRIA (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;");
});
register_uninstallation_hook("Meu_Plugin", function() {
//executa algo
});
register_activation_hook("Meu_Plugin", function() {
//executa algo
});
register_deactivation_hook("Meu_Plugin", function() {
//executa algo
});
register_update_hook("Meu_Plugin", function() {
//mostra as informações necessárias para atualizar este plugin no modal
});
register_data_insert_hook(função ($dados) {
// alguns dados foram inseridos
/*
o array $data tem 3 itens
id => id inserido
tabela => tabela associada
data => array de dados inserido
*/
});
register_data_update_hook(função ($dados) {
//alguns dados foram atualizados
/*
o array $data tem 3 itens
id => id atualizado
tabela => tabela associada
data => matriz de dados atualizada
*/
});
register_data_delete_hook(função ($dados) {
//alguns dados foram deletados
/*
o array $data tem 2 itens
id => id deletado
tabela => tabela associada
*/
});
Chame esses ganchos em sua pasta/arquivo index.php My_Plugin.
Importante: Ao usar a função de gancho add_filter, sempre retorne o primeiro parâmetro com/sem modificá-lo conforme a necessidade.
app_hooks()->add_filter('app_filter_app_csrf_exclude_uris', function ($app_csrf_exclude_uris) {
if (!in_array("plugin_controller.*+", $app_csrf_exclude_uris)) {
array_push($app_csrf_exclude_uris, "plugin_controller.*+");
}
return $app_csrf_exclude_uris;
});
app_hooks()->add_action('app_hook_after_cron_run', function() {
//executa algo
});
app_hooks()->add_filter('app_filter_dashboard_widget', function ($default_widgets_array) {
array_push($default_widgets_array, array(
"widget" => "widget_name",
"widget_view" => view("Meu_Plugin\Views\widget")
));
return $default_widgets_array;
});
app_hooks()->add_filter('app_filter_action_links_of_My_Plugin', function ($action_links_array) {
$action_links_array = array(
âncora(get_uri("meu_plugin/configurações"), "Configurações"),
âncora(get_uri("meu_plugin/get_support"), "Suporte")
);
return $action_links_array;
});
app_hooks()->add_action('app_hook_before_app_access', function ($data) {
$login_user_id = get_array_value($data, "login_user_id"); // logado no id do usuário se for um login válido
$redirect = get_array_value($data, "redirect"); // ou ele irá redirecionar para a página de login ou não se houver login inválido
//realiza algo antes de acessar o app principal
});
app_hooks()->add_filter('app_filter_staff_left_menu', function ($sidebar_menu) {
$sidebar_menu["left_menu_item"] = array(
"nome" => "item_name",
"url" => "meu_plugin/url",
"class" => "feather-icon-class", //like livro
"position" => 5 //estará na posição após o 4º item
);
return $sidebar_menu;
});
app_hooks()->add_filter('app_filter_client_left_menu', function ($sidebar_menu) {
$sidebar_menu["left_menu_item"] = array(
"nome" => "item_name",
"url" => "meu_plugin/url",
"class" => "feather-icon-class", //like livro
"position" => 5 //estará na posição após o 4º item
);
return $sidebar_menu;
});
app_hooks()->add_action('app_hook_post_notification', function ($notification_id) {
//faça alguma coisa
});
Nota: Na desativação do seu plugin, a configuração de notificação ainda será mostrada nas configurações de notificação. Por causa disso, use register_deactivation_hook() e defina delete=1 e register_activation_hook() para reverter novamente por delete=0.
INSERT INTO `notification_settings` (`event`, `category`, `enable_email`, `enable_web`, `notify_to_team`, `notify_to_team_members`, `notify_to_terms`, `deleted`) VALORES
('your_notification_key', 'your_category', 0, 0, '', '', '', 0);
Adicione também o campo de ID obrigatório conforme necessário à tabela de notificações.Nota: Por favor, adicione prefixo (plugin_) ao seu campo e observe que, na desativação do seu plugin, as notificações ainda serão mostradas na área de notificações do usuário. Por causa disso, use register_deactivation_hook() e defina delete=1 e register_activation_hook() para reverter novamente por delete=0.
ALTER TABLE `notificações` ADD `plugin_your_item_id` INT(11) NOT NULL AFTER `deleted`;
Adicionar gancho de categoria de configurações de notificação.
app_hooks()->add_filter('app_filter_notification_category_suggestion', function ($category_suggestions) {
$category_suggestions[] = array("id" => "sua_categoria", "texto" => app_lang("sua_categoria"));
return $category_suggestions;
});
Adicionar gancho de configuração de notificação.
app_hooks()->add_filter('app_filter_notification_config', function ($events_of_hook) {
$notification_link = function() {
return array("url" => get_uri("notification_link"));
};
$events_of_hook["your_notification_key"] = array( //verifica ...app/Helpers/notifications_helper.php > function get_notification_config() para melhores ideias
"notify_to" => array("recipient"), //verifica os valores disponíveis abaixo
"info" => $notification_link
);
return $events_of_hook;
});
Matriz notify_to suportada:
array("team_members", "team", "project_members", "client_primary_contact", "client_all_contacts", "task_assignee", "task_collaborators", "comment_creator", "cusomer_feedback_creator", "leave_applicant", "ticket_creator", "ticket_assignee", "estimate_request_assignee", "destinatário", "mencionados_membros", "proprietário", "client_assigned_contacts", "post_creator", "order_creator_contact");
Prepare a consulta de obtenção de notify_to users:
app_hooks()->add_filter('app_filter_create_notification_where_query', function ($where_queries_from_hook, $data) {
//prepara a consulta WHERE e retorna
//verifique ...app/Models/Notifications_model.php > function create_notification() para melhores ideias
/*
A variável $data tem estes valores de chave:
"event" => Chave do evento (your_notification_key).
"user_id" => Qual usuário criou a notificação. Se for 0, então é criado pelo aplicativo.
"options" => Ele contém outra matriz de IDs de itens de notificação disponíveis. Verifique ...app/Models/Notifications_model.php > function create_notification() para melhores ideias.
"notify_to_terms" => Notificar ao array de termos conforme selecionado na configuração de notificação para este evento. Como array("team_members", "team", "project_members").
*/
$where_queries_from_hook[] = "SUAS CONSULTAS";
return $where_queries_from_hook;
});
Se você quiser mostrar mais informações com a notificação, você terá que adicionar este gancho:
//para web
app_hooks()->add_filter('app_filter_notification_description', function ($notification_descriptions, $notification) {
$notification_descriptions[] = view("your_notification_description", array("notification" => $notification)), //check ...app/Views/notifications/notification_description.php
return $notification_descriptions;
});
//para folga
app_hooks()->add_filter('app_filter_notification_description_for_slack', function ($notification_descriptions, $notification) {
$notification_descriptions[] = view("your_notification_description_for_slack", array("notification" => $notification)) //check ...app/Views/notifications/notification_description_for_slack.php
return $notification_descriptions;
});
Adicione modelos de e-mail.
app_hooks()->add_filter('app_filter_email_templates', function ($templates_array) {
$templates_array["account"]["your_email_template"] = array("USER_FIRST_NAME", "USER_LAST_NAME", "LOGO_URL", "SIGNATURE", "OR_ANY_VARIABLE_YOU_WANT_TO_ADD");
return $templates_array;
});
Isso também requer adicionar este modelo de email na tabela email_templates durante a instalação do plug-in.
INSERT INTO `email_templates` (`template_name`, `email_subject`, `default_message`, `custom_message`, `deleted`) VALUES ('seu_email_template', 'assunto do e-mail', 'CONTENT OF YOUR EMAIL TEMPLATE', '', '0 ');
Personalize a notificação por e-mail.
app_hooks()->add_filter('app_filter_send_email_notification', function ($data) {
//valores disponíveis em $data
//verifique .../app/Helpers/notifications_helper.php > function send_notification_emails() para melhores ideias
$notification_info = get_array_value($data, "notificação");
$parser_data = get_array_value($data, "parser_data");
$user_language = get_array_value($data, "user_language");
//verifica se é a notificação do seu plugin caso contrário ele enviará para todas as notificações
if ($notificação->evento !== "your_notification_key") {
retorna $dados;
}
$Email_templates_model = model("App\Models\Email_templates_model");
$email_template = $Email_templates_model->get_final_template("seu_email_template", true);
$parser_data["ANY_VARIABLE"] = "valor";
$parser = \Config\Services::parser();
$message = get_array_value($email_template, "message_$user_language") ? get_array_value($email_template, "message_$user_language") : get_array_value($email_template, "message_default");
$assunto = get_array_value($email_template, "assunto_$user_language") ? get_array_value($email_template, "subject_$user_language") : get_array_value($email_template, "subject_default");
$mensagem = $parser->setData($parser_data)->renderString($message); //modifica a mensagem de e-mail
$assunto = $parser->setData($parser_data)->renderString($assunto); //modifica o assunto do email
//juntar anexo
//mostrando demonstração do envio de uma fatura pdf
$invoice_data = get_invoice_making_data(invoice_id);
$attachement_url = prepare_invoice_pdf($invoice_data, "enviar_email");
$email_options["attachments"] = array(array("file_path" => $attachment_url));
$info_array = array(
"assunto" => $assunto,
"mensagem" => $mensagem,
"email_options" => $email_options,
"attachement_url" => $attachement_url,
);
return $info_array;
});
app_hooks()->add_filter('app_filter_payment_method_settings', function($settings) {
$settings["payment_method_name"] = array(
array("name" => "pay_button_text", "text" => app_lang("pay_button_text"), "type" => "texto", "default" => "Método de Pagamento"), //requerido
array("name" => "payment_method_setting_text", "text" => "Configuração da forma de pagamento (Texto)", "type" => "text", "default" => ""),
array("name" => "payment_method_setting_boolean", "text" => "Configuração da forma de pagamento (Boolean)", "type" => "boolean", "default" => "0"),
array("name" => "payment_method_setting_readonly", "text" => "Configuração do método de pagamento (Readonly)", "type" => "readonly", "default" => "Este é o valor readonly"),
);
retornar $configurações;
});
Isso também requer adicionar este método de pagamento na tabela payment_methods durante a instalação do plug-in.
INSERT INTO `payment_methods` (`title`, `type`, `description`, `online_payable`, `available_on_invoice`, `minimum_payment_amount`, `settings`, `deleted`) VALUES ('Payment method name', 'payment_method_name', 'Descrição da forma de pagamento', 1, 0, 0, '', 0);
Observe que, na desativação de um plug-in de método de pagamento, o método de pagamento ainda será exibido nas configurações do método de pagamento. Por causa disso, use register_deactivation_hook() e defina delete=1 e register_activation_hook() para reverter novamente por delete=0.
app_hooks()->add_action('app_hook_invoice_payment_extension', function($payment_method_variables) {
if (get_array_value($payment_method_variables, "method_type") === "my_payment_method") {
echo view("My_Payment_Method\Views\index", $payment_method_variables);
}
});
O array $payment_method_variables() tem estes valores de chave:
//adiciona guia ajax no perfil da equipe
app_hooks()->add_filter('app_filter_staff_profile_ajax_tab', function ($hook_tabs, $user_id) {
$hook_tabs[] = array(
"título" => app_lang("tab_title"),
"url" => get_uri("my_plugin/my_tab"),
"target" => "meu-plugin-minha-guia"
);
return $hook_tabs;
});
Ganchos disponíveis para adicionar guias ajax:
app_hooks()->add_filter('app_filter_client_details_ajax_tab', 'function_to_add_tab'); //parâmetro: $hook_tabs, $client_id
app_hooks()->add_filter('app_filter_client_profile_ajax_tab', 'function_to_add_tab'); //parâmetro: $hook_tabs, $client_contact_id
app_hooks()->add_filter('app_filter_lead_details_ajax_tab', 'function_to_add_tab'); //parâmetro: $hook_tabs, $lead_id
app_hooks()->add_filter('app_filter_lead_profile_ajax_tab', 'function_to_add_tab'); //parâmetro: $hook_tabs, $lead_contact_id
app_hooks()->add_filter('app_filter_integration_settings_tab', 'function_to_add_tab'); //parâmetro: $hook_tabs
app_hooks()->add_filter('app_filter_admin_settings_menu', function($settings_menu) {
$settings_menu["setup"][] = array("name" => "my_plugin_setting", "url" => "my_plugin/setting");
return $settings_menu;
});
app_hooks()->add_action('app_hook_signin_extension', function() {
//mostre algo
});
app_hooks()->add_action('app_hook_signup_extension', function() {
//mostre algo
});
app_hooks()->add_action('app_hook_layout_main_view_extension', function() {
//mostre algo
});
app_hooks()->add_action('app_hook_head_extension', function() {
//inclui algo
});
app_hooks()->add_action('app_hook_dashboard_announcement_extension', function() {
//mostre algo
});
app_hooks()->add_action('app_hook_after_signin', function() {
//faça alguma coisa
});
app_hooks()->add_action('app_hook_before_signout', function() {
//faça alguma coisa
});
app_hooks()->add_action('app_hook_role_permissions_extension', function() {
//mostra uma configuração de função
});
app_hooks()->add_filter('app_filter_role_permissions_save_data', function ($permissions) {
$request = \Config\Services::request();
$permissions["your_permission"] = $request->getPost('your_permission');
retornar $permissões;
});
app_hooks()->add_action('app_hook_task_view_right_panel_extension', function() {
//mostre algo
});
app_hooks()->add_action('app_hook_general_settings_extension', 'function_to_add_setting');
app_hooks()->add_action('app_hook_general_settings_save_data', 'function_to_save_setting');
app_hooks()->add_action('app_hook_client_permissions_extension', 'function_to_add_setting');
app_hooks()->add_action('app_hook_client_permissions_save_data', 'function_to_save_setting');
app_hooks()->add_action('app_hook_team_members_my_preferences_extension', 'function_to_add_setting');
app_hooks()->add_action('app_hook_team_members_my_preferences_save_data', 'function_to_save_setting');
app_hooks()->add_action('app_hook_clients_my_preferences_extension', 'function_to_add_setting');
app_hooks()->add_action('app_hook_clients_my_preferences_save_data', 'function_to_save_setting');
app_hooks()->add_action('app_hook_general_settings_extension', function() {
//Mostrar configurações
//mostra um bloco de configuração (<div class="form-group">)
//verifique .../app/Views/settings/general.php para melhores ideias
echo view("Meu_Plugin\Visualizações\configuração");
});
Salvar configuração:
app_hooks()->add_action('app_hook_general_settings_save_data', function() {
$request = \Config\Services::request();
$your_setting_value = $request->getPost("your_setting");
$Settings_model = model("App\Models\Settings_model");
$Settings_model->save_setting("your_setting", $your_setting_value);
});
//adiciona guia ajax no perfil da equipe
app_hooks()->add_filter('app_filter_team_members_project_details_tab', function ($project_tabs_of_hook_of_staff, $project_id = 0) {
$project_tabs_of_hook_of_staff["my_tab_title_with_available_language_key_value"] = "my_plugin/my_tab_url";
$project_tabs_of_hook_of_staff["my_tab_another_title_with_available_language_key_value"] = "my_plugin/my_another_tab_url";
return $project_tabs_of_hook_of_staff;
});
//filtro disponível para clientes
app_hooks()->add_filter('app_filter_clients_project_details_tab', 'function_to_add_tab'); //parâmetro: $project_tabs_of_hook_of_staff, $project_id
Events::on('pre_system', function() {
if (!defined('PLUGIN_CUSTOM_STORAGE')) {
define('PLUGIN_CUSTOM_STORAGE', TRUE);
}
});
app_hooks()->add_action('app_hook_upload_file_to_temp', function ($data) {
$temp_file = get_array_value($data, "temp_file");
$file_name = get_array_value($data, "file_name");
\Your_Storage_Integration\Libraries\Your_Storage_Integration::upload_file_to_temp($temp_file, $file_name);
//verifique a função upload_file_to_temp() em .../app/Helpers/app_files_helper.php para melhores ideias
});
app_hooks()->add_filter('app_filter_move_temp_file', function ($data) {
$related_to = get_array_value($data, "related_to");
$file_name = get_array_value($data, "file_name");
$new_filename = get_array_value($data, "new_filename");
$file_content = get_array_value($data, "file_content");
$source_path = get_array_value($data, "source_path");
$target_path = get_array_value($data, "target_path");
$files_data = \Your_Storage_Integration\Libraries\Your_Storage_Integration::move_temp_file($file_name, $new_filename); //utiliza os parâmetros necessários
//verifique a função move_temp_file() em .../app/Helpers/app_files_helper.php para melhores ideias
return $arquivos_dados;
});
app_hooks()->add_filter('app_filter_get_file_content', function ($data) {
$file_info = get_array_value($data, "file_info");
$file_id = get_array_value($file_info, "file_id");
//você pode usar qualquer chave aqui em vez de file_id que é necessário para baixar o conteúdo
//mas você deve passar essa chave e valor no gancho app_filter_move_temp_file (ao retornar o array $files_data)
//verifique a função download_app_files() em .../app/Controllers/App_Controller.php para melhores ideias
return \Your_Storage_Integration\Libraries\Your_Storage_Integration::get_file_content($file_id);
});
app_hooks()->add_filter('app_filter_get_source_url_of_file', function ($data) {
//verifique a função get_source_url_of_file() em .../app/Helpers/app_files_helper.php para melhores ideias
$file_info = get_array_value($data, "file_info");
$file_id = get_array_value($file_info, "file_id");
return \Your_Storage_Integration\Libraries\Your_Storage_Integration::get_source_url_of_file($file_id);
});
app_hooks()->add_action('app_hook_delete_app_file', function ($file_info) {
//verifique a função delete_app_files() em .../app/Helpers/app_files_helper.php para melhores ideias
$file_id = get_array_value($file_info, "file_id");
\Your_Storage_Integration\Libraries\Your_Storage_Integration::delete_file($file_id);
});
Siga estas práticas recomendadas ao desenvolver seu plug-in:
<html>
<cabeça>
<title>403 Proibido</title>
</head>
<corpo>
<p>O acesso ao diretório é proibido.</p>
</body>
</html>